diff --git a/dns_scripts/dns_gcloud b/dns_scripts/dns_gcloud new file mode 100755 index 00000000..f3d2a81b --- /dev/null +++ b/dns_scripts/dns_gcloud @@ -0,0 +1,327 @@ +#!/usr/bin/env bash +# dns_gcloud +# Add/Del/List TXT record using the Google Cloud DNS gcloud command +# ver 2025-09-23 # shellcheck has read, even I'll say eveything was so nice +# org. version: +# https://github.com/kshji/gitssl_gcloud +# +# Main reason to make was to support getssl using DNS validation with Google Cloud DNS +# You can use this script to any host setting TXT records, default is _acme-challenge +# +# dns_gloud -c command domain token +# +# get help: +# dns_gloud -? | --help +# +# dns_gloud -c add example.com "testN" +# dns_gloud -c list example.com +# dns_gloud -c del example.com "testN" +# dns_gloud -c add example.com "test1" "test2" +# dns_gloud -c list example.com +# dns_gloud -c del example.com "test1" "test2" +# +# options: +# -d 0|1 # debug on/off to the file /var/tmp/getssl/...log +# -s 10 # sleeptime after gcloud add/del process, default 10 +# -h hostname # default is "_acme-challenge." +# # if like to use domain without host, set host empty string !!! +# -t ttlvalue # set ttl, default 60 = 1 min +# +# + +PRG="$0" +BINDIR="${PRG%/*}" +[ "$PRG" = "$BINDIR" ] && BINDIR="." # - same dir as program +PRG="${PRG##*/}" + +####################################################################################### +usage() +{ +cat </dev/null + chmod 1777 "$tmpd" 2>/dev/null + + + cnt=0 + # save only last execute info + { + date + echo "GCLOUD_PROJECTID:$GCLOUD_PROJECTID" + echo "GCLOUD_ZONE:$GCLOUD_ZONE" + echo "GCLOUD_ACCOUNT:$GCLOUD_ACCOUNT" + echo "GCLOUD_KEYFILE:$GCLOUD_KEYFILE" + env + } > "$tmpf" + for var in $all + do + ((cnt++)) + echo "$cnt:<$var>" >> "$tmpf" + done + +} + +####################################################################################### +check_end_dot() +{ + # gcloud need fulldomain ending dot = absolut domain path + # set the last dot if missing + Xorg="$1" + Xnodot="${Xorg%.}" # remove last dot if there is + echo "$Xnodot." # add dot allways +} + +####################################################################################### +list_txt() +{ + + Xname="$1" + list=$(gcloud dns record-sets list --zone="$GCLOUD_ZONE" --name="$Xname" --type="TXT" ) + stat=$? + (( stat > 0 )) && err "gcloud error to list TXT record" && exit 2 + variables=variables + + # Some shell checkers (ex.shellcheck) like to do next different way. I'll say both works + # you can read 1st line to var and then use {$var?} on reading + # in this case you'll get same result. This read 1st loop varianle variables, look value of variables + # on the second loop it read variables, which was on the 1st line ... command line process is so nice + # this do exactly what we need to do ... (not that what https://www.shellcheck.net/wiki/SC2229 explain) + oifs="$IFS" + cnt=0 + echo "$list" | while read $variables + do + (( cnt++ )) + # 1st line is header, read next line + (( cnt == 1 )) && continue + echo "name:$NAME type:$TYPE ttl:$TTL data:$DATA" + # next line works just what we need, shellcheck not like this ... + # Wiki's last part: it's okay https://www.shellcheck.net/wiki/SC2206 + IFS="," values=($DATA) + IFS="$oifs" + numOfvalues=${#values[@]} + for (( var=0; var" + +#exit + # start transaction + gcloud dns record-sets transaction start --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + stat=$? + (( stat > 0 )) && err "gcloud start transaction error" && exit 2 + + # del TXT + dbgstr gcloud dns record-sets transaction remove --name="$Xname" --ttl="$ttl" --type="TXT" \ + --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken" + gcloud dns record-sets transaction remove --name="$Xname" --ttl="$ttl" --type="TXT" \ + --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken" + stat=$? + if (( stat > 0 )) ; then + err "gcloud remove error" + gcloud dns record-sets transaction abort --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + exit 2 + fi + + gcloud dns record-sets transaction execute --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + stat=$? + (( stat > 0 )) && err "gcloud transaction execute error" && exit 2 + + # if not sleep, get error ??? + sleep "$sleepafter" + exit 0 +} + +####################################################################################### +add_txt() +{ + + Xname="$1" + shift + # could be 1-n values + Xtoken="" + while [ $# -gt 0 ] + do + Xtoken="$Xtoken \"$1\"" + shift + done + dbgstr "<$Xtoken>" + + + + # start transaction + gcloud dns record-sets transaction start --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + stat=$? + if (( stat > 0 )) ; then + err "gcloud start transaction error" + gcloud dns record-sets transaction abort --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + exit 2 + fi + + # add TXT + dbgstr gcloud dns record-sets transaction add --name="$Xname" --ttl="$ttl" --type="TXT" \ + --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken" + gcloud dns record-sets transaction add --name="$Xname" --ttl="$ttl" --type="TXT" \ + --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken" + stat=$? + if (( stat > 0 )) ; then + err "gcloud add error" + gcloud dns record-sets transaction abort --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + exit 2 + fi + + gcloud dns record-sets transaction execute --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" + stat=$? + #echo "execute stat:$stat" + (( stat > 0 )) && err "gcloud transaction execute error" && exit 2 + + # if not sleep, get error ??? + sleep "$sleepafter" + exit 0 +} + +####################################################################################### +# MAIN +####################################################################################### + +DEBUG=0 +command="" +sleepafter=10 +# default host to manipulate +host="_acme-challenge." +ttl=60 + +while [ $# -gt 0 ] +do + arg="$1" + case "$arg" in + -c|--command|--cmd) command="$2"; shift ;; + -d|--debug) DEBUG="$2" ; shift ;; + -s|--sleep) sleepafter="$2"; shift ;; + -h|--host) host="$2" + [ $# -lt 2 ] && usage && exit 2 + host="$2" + shift + ;; + -t|--ttl) ttl="$2"; shift ;; + -?|--help) usage; exit 2 ;; + -*) # unknown option + err "unknown option $arg" + usage + exit 2 + ;; + *) # arguments, stop the option parser + break + ;; + esac + shift +done + +[ "$GCLOUD_PROJECTID" = "" ] && err "GCLOUD_PROJECTID is not set. Unable to set TXT records." && exit 2 +[ "$GCLOUD_ZONE" = "" ] && err "GCLOUD_ZONE is not set. Unable to set TXT records." && exit 2 +[ "$GCLOUD_ACCOUNT" = "" ] && err "GCLOUD_ACCOUNT is not set. Unable to set TXT records." && exit 2 +[ "$GCLOUD_KEYFILE" = "" ] && err "GCLOUD_KEYFILE is not set. Unable to set TXT records." && exit 2 +[ ! -f "$GCLOUD_KEYFILE" ] && err "file not usable:$GCLOUD_KEYFILE" && exit 2 + + +all="$*" +fulldomain="$1" +shift +token="$*" # could be 1-n tokens if del + +case "$command" in + add) ;; + del) ;; + list) ;; + *) command="" ;; +esac + + +[ "$command" = "" ] && err "need option -c add | -c del | -c list" && exit 2 +[ "$fulldomain" = "" ] && err "need fulldomain argument." && exit 2 +[ "$token" = "" ] && [ "$command" != "list" ] && err "need token argument." && exit 2 + +# dbg info to the program tmp dir +(( DEBUG>0)) && dbg "$fulldomain" "$command" + +# host check ending of dot +[ "$host" != "" ] && host=$(check_end_dot "$host") +# host fullname +gname=$(check_end_dot "$host$fulldomain") +#echo "gname: $gname" + +# activate google cloud account +gcloud auth activate-service-account "$GCLOUD_ACCOUNT" --key-file="$GCLOUD_KEYFILE" --project="$GCLOUD_PROJECTID" +stat=$? +(( stat > 0 )) && err "gcloud activate account error" && exit 2 + +case "$command" in + add) add_txt "$gname" "$token" + ;; + del) del_txt "$gname" "$token" + ;; + list) list_txt "$gname" + ;; + *) + err "unknown command" + exit 2 + ;; +esac + + + diff --git a/dns_scripts/dns_gcloud.README.md b/dns_scripts/dns_gcloud.README.md new file mode 100755 index 00000000..32249e95 --- /dev/null +++ b/dns_scripts/dns_gcloud.README.md @@ -0,0 +1,150 @@ +# getssl using Google Cloud DNS + +https://github.com/kshji/getssl_gcloud + +ver 2025-09-13 + +## You need install gcloud command + +[Gcloud install](gle.com/sdk/docs/install) + +If you are using *nix server without desktop (x-term), remove DISPLAY set if it's. +If you have set DISPLAY, try init process to start local chrome GUI process. +``` sh +unset DISPLAY +``` + +Init gcloud using, need to do once. + +``` sh +gcloud init +``` + +Need also Google Cloud Console Service Account: +[Google Cloud Console Service Account](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts ) + +* Permissions role "DNS Zone Editor" or "DNS Administrator" +* tab Keys generate Key, JSON: result is JSON keyfile + +Service Account account is email, usually something like xxx@xxx.gserviceaccount.com + +***Example*** using keyfile: + +``` sh +gcloud auth activate-service-account xxx@xxx.gserviceaccount.com --key-file=/somepath/PROJECT_ID_xxxxx.json +``` + +After auth you can use gcloud dns services. + +***Example***: Get zones from your Google Cloud DNS project: + +``` sh +gcloud dns managed-zones list --project=PROJECT_ID +``` + +More gcloud dns commands: [Reference DNS](https://google.com/sdk/gcloud/reference/dns) + +***Example***: List domain TXT records: + +``` sh +gcloud dns record-sets list --zone=ZONEID --name="example.com." --type="TXT" +``` + +ZONEID is usually ex. for domain example.com it is ***examplecom*** + +## getssl configuration DNS validation using Google Cloud DNS + +example.com/getssl.cfg + +``` sh +CA="https://acme-v02.api.letsencrypt.org" +SANS="*.example.com" + +#Set this to "true" to enable DNS validation +VALIDATE_VIA_DNS="true" +# Google Cloud DNS setup +# Use this command/script to add the challenge token to the DN#S entries for the domain +DNS_ADD_COMMAND="/somepath/dns_gcloud -c add " +# Use this command/script to remove the challenge token from the DNS entries for the domain +DNS_DEL_COMMAND="/somepath/dns_gcloud -c del " + +# example.com setup Google Cloud DNS validation +export GCLOUD_ZONE="examplecom" # Google Cloud DNS zoneid +export GCLOUD_PROJECTID="mydnsproject" # Google Cloud projectid +# Google Cloud Service Account +export GCLOUD_ACCOUNT="someuser@mydnsproject.iam.gserviceaccount.com" +export GCLOUD_KEYFILE="/somepath/mydnsprojectSomeid.json" + +``` + +## dns_cloud manual + + * default host is _acme-challenge. + * default ttl is 60 s. + * default sleep after gcloud process is 10 s. + * default debug is 0 = off + * env variables have to setup before using `dns_gcloud`: + * GCLOUD_ZONE + * GCLOUD_PROJECTID + * GCLOUD_ACCOUNT + * GCLOUD_KEYFILE + +### get help +``` sh +dns_gloud -? +dns_gloud --help +``` + +### Add TXT token +Add TXT token "testN"", host _acme-challenge.example.com + +``` sh +dns_gloud -c add example.com "testN" +``` + +Add TXT token "testN"", host somehost.example.com +``` sh +dns_gloud -h somehost -c add example.com "testN" +``` + +### Del TXT token +Del TXT token "testN"", host _acme-challenge.example.com +``` sh +dns_gloud -c del example.com "testN" +``` +Del TXT token "testN"", host somehost.example.com +``` sh +dns_gloud -h somehost -c del example.com "testN" +``` + +### List TXT token + +List host TXT tokens, default host _acme-challenge +``` sh +dns_gloud -c list example.com +``` + +List domain TXT tokens, not host. Set host empty string. +``` sh +dns_gloud -h "" -c list example.com +``` + + +### Extra options + +Debug messages, option -d with argument 0 or 1. +Some debug messages to the stdout and log env settings to file to dir ***/var/tmp/getssl*** + +``` sh +dns_gloud -d 1 -h "" -c list example.com +``` + +Change default 60 second ttl value when adding. Remember,when deleting, ttl have to be same. +``` sh +dns_gloud -c add -t 300 example.com "testN" +``` +Change default 10 second sleep after process +``` sh +dns_gloud -c add -s 5 example.com "testN" +``` +