Skip to content

Commit f8e0cd2

Browse files
authored
Merge pull request #886 from kshji:dns_gcloud
dns validation Google Cloud DNS using gcloud
2 parents 0e802e7 + 120f48c commit f8e0cd2

2 files changed

Lines changed: 477 additions & 0 deletions

File tree

dns_scripts/dns_gcloud

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
#!/usr/bin/env bash
2+
# dns_gcloud
3+
# Add/Del/List TXT record using the Google Cloud DNS gcloud command
4+
# ver 2025-09-23 # shellcheck has read, even I'll say eveything was so nice
5+
# org. version:
6+
# https://github.com/kshji/gitssl_gcloud
7+
#
8+
# Main reason to make was to support getssl using DNS validation with Google Cloud DNS
9+
# You can use this script to any host setting TXT records, default is _acme-challenge
10+
#
11+
# dns_gloud -c command domain token
12+
#
13+
# get help:
14+
# dns_gloud -? | --help
15+
#
16+
# dns_gloud -c add example.com "testN"
17+
# dns_gloud -c list example.com
18+
# dns_gloud -c del example.com "testN"
19+
# dns_gloud -c add example.com "test1" "test2"
20+
# dns_gloud -c list example.com
21+
# dns_gloud -c del example.com "test1" "test2"
22+
#
23+
# options:
24+
# -d 0|1 # debug on/off to the file /var/tmp/getssl/...log
25+
# -s 10 # sleeptime after gcloud add/del process, default 10
26+
# -h hostname # default is "_acme-challenge."
27+
# # if like to use domain without host, set host empty string !!!
28+
# -t ttlvalue # set ttl, default 60 = 1 min
29+
#
30+
#
31+
32+
PRG="$0"
33+
BINDIR="${PRG%/*}"
34+
[ "$PRG" = "$BINDIR" ] && BINDIR="." # - same dir as program
35+
PRG="${PRG##*/}"
36+
37+
#######################################################################################
38+
usage()
39+
{
40+
cat <<EOT
41+
usage:$PRG -c COMMAND [ -d 0|1 ] [ -t ttlvalue ] [ -s sleep_sec_after_gcloud ] [ -h hostname ] DOMAIN TOKEN
42+
or
43+
$PRG --command COMMAND [ --debug 0|1 ] [ --ttl ttlvalue ] [ --sleep sleep_sec_after_gcloud ] [ --host hostname ] DOMAIN TOKEN
44+
45+
-d 1 # print some debug data and make debug file to the dir /var/tmp/getssl/
46+
-t NNN # set TTL value, default 60. Have to be same in the ADD and DEL
47+
-s NN # default 10 s, sleep seconds after gcloud process
48+
-h hostname # hostname, default is _acme-challenge, empty string = use domain
49+
50+
EOT
51+
52+
}
53+
54+
#######################################################################################
55+
err()
56+
{
57+
echo "$PRG err:$*"
58+
}
59+
60+
#######################################################################################
61+
dbgstr()
62+
{
63+
((DEBUG<1)) && return
64+
echo "$PRG debug:$*"
65+
}
66+
67+
#######################################################################################
68+
dbg()
69+
{
70+
71+
72+
Xdomain="$1" # domain + command
73+
Xcmd="$2"
74+
[ "$Xdomain" = "" ] && Xdomain="default"
75+
[ "$Xcmd" = "" ] && Xcmd="cmd"
76+
Xdomain="${Xdomain%.}" # del last dot
77+
tmpd="/var/tmp/getssl"
78+
tmpf="$tmpd/$PRG.$Xdomain.$Xcmd.log"
79+
mkdir -p "$tmpd" 2>/dev/null
80+
chmod 1777 "$tmpd" 2>/dev/null
81+
82+
83+
cnt=0
84+
# save only last execute info
85+
{
86+
date
87+
echo "GCLOUD_PROJECTID:$GCLOUD_PROJECTID"
88+
echo "GCLOUD_ZONE:$GCLOUD_ZONE"
89+
echo "GCLOUD_ACCOUNT:$GCLOUD_ACCOUNT"
90+
echo "GCLOUD_KEYFILE:$GCLOUD_KEYFILE"
91+
env
92+
} > "$tmpf"
93+
for var in $all
94+
do
95+
((cnt++))
96+
echo "$cnt:<$var>" >> "$tmpf"
97+
done
98+
99+
}
100+
101+
#######################################################################################
102+
check_end_dot()
103+
{
104+
# gcloud need fulldomain ending dot = absolut domain path
105+
# set the last dot if missing
106+
Xorg="$1"
107+
Xnodot="${Xorg%.}" # remove last dot if there is
108+
echo "$Xnodot." # add dot allways
109+
}
110+
111+
#######################################################################################
112+
list_txt()
113+
{
114+
115+
Xname="$1"
116+
list=$(gcloud dns record-sets list --zone="$GCLOUD_ZONE" --name="$Xname" --type="TXT" )
117+
stat=$?
118+
(( stat > 0 )) && err "gcloud error to list TXT record" && exit 2
119+
variables=variables
120+
121+
# Some shell checkers (ex.shellcheck) like to do next different way. I'll say both works
122+
# you can read 1st line to var and then use {$var?} on reading
123+
# in this case you'll get same result. This read 1st loop varianle variables, look value of variables
124+
# on the second loop it read variables, which was on the 1st line ... command line process is so nice
125+
# this do exactly what we need to do ... (not that what https://www.shellcheck.net/wiki/SC2229 explain)
126+
oifs="$IFS"
127+
cnt=0
128+
echo "$list" | while read $variables
129+
do
130+
(( cnt++ ))
131+
# 1st line is header, read next line
132+
(( cnt == 1 )) && continue
133+
echo "name:$NAME type:$TYPE ttl:$TTL data:$DATA"
134+
# next line works just what we need, shellcheck not like this ...
135+
# Wiki's last part: it's okay https://www.shellcheck.net/wiki/SC2206
136+
IFS="," values=($DATA)
137+
IFS="$oifs"
138+
numOfvalues=${#values[@]}
139+
for (( var=0; var<numOfvalues ; var++ ))
140+
do
141+
echo " - data($var):${values[$var]}"
142+
done
143+
done
144+
sleep 1
145+
exit 0
146+
}
147+
148+
#######################################################################################
149+
del_txt()
150+
{
151+
152+
Xname="$1"
153+
shift
154+
#
155+
Xtoken=""
156+
while [ $# -gt 0 ]
157+
do
158+
Xtoken="$Xtoken \"$1\""
159+
shift
160+
done
161+
dbgstr "<$Xtoken>"
162+
163+
#exit
164+
# start transaction
165+
gcloud dns record-sets transaction start --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
166+
stat=$?
167+
(( stat > 0 )) && err "gcloud start transaction error" && exit 2
168+
169+
# del TXT
170+
dbgstr gcloud dns record-sets transaction remove --name="$Xname" --ttl="$ttl" --type="TXT" \
171+
--zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken"
172+
gcloud dns record-sets transaction remove --name="$Xname" --ttl="$ttl" --type="TXT" \
173+
--zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken"
174+
stat=$?
175+
if (( stat > 0 )) ; then
176+
err "gcloud remove error"
177+
gcloud dns record-sets transaction abort --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
178+
exit 2
179+
fi
180+
181+
gcloud dns record-sets transaction execute --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
182+
stat=$?
183+
(( stat > 0 )) && err "gcloud transaction execute error" && exit 2
184+
185+
# if not sleep, get error ???
186+
sleep "$sleepafter"
187+
exit 0
188+
}
189+
190+
#######################################################################################
191+
add_txt()
192+
{
193+
194+
Xname="$1"
195+
shift
196+
# could be 1-n values
197+
Xtoken=""
198+
while [ $# -gt 0 ]
199+
do
200+
Xtoken="$Xtoken \"$1\""
201+
shift
202+
done
203+
dbgstr "<$Xtoken>"
204+
205+
206+
207+
# start transaction
208+
gcloud dns record-sets transaction start --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
209+
stat=$?
210+
if (( stat > 0 )) ; then
211+
err "gcloud start transaction error"
212+
gcloud dns record-sets transaction abort --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
213+
exit 2
214+
fi
215+
216+
# add TXT
217+
dbgstr gcloud dns record-sets transaction add --name="$Xname" --ttl="$ttl" --type="TXT" \
218+
--zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken"
219+
gcloud dns record-sets transaction add --name="$Xname" --ttl="$ttl" --type="TXT" \
220+
--zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID" "$Xtoken"
221+
stat=$?
222+
if (( stat > 0 )) ; then
223+
err "gcloud add error"
224+
gcloud dns record-sets transaction abort --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
225+
exit 2
226+
fi
227+
228+
gcloud dns record-sets transaction execute --zone="$GCLOUD_ZONE" --project="$GCLOUD_PROJECTID"
229+
stat=$?
230+
#echo "execute stat:$stat"
231+
(( stat > 0 )) && err "gcloud transaction execute error" && exit 2
232+
233+
# if not sleep, get error ???
234+
sleep "$sleepafter"
235+
exit 0
236+
}
237+
238+
#######################################################################################
239+
# MAIN
240+
#######################################################################################
241+
242+
DEBUG=0
243+
command=""
244+
sleepafter=10
245+
# default host to manipulate
246+
host="_acme-challenge."
247+
ttl=60
248+
249+
while [ $# -gt 0 ]
250+
do
251+
arg="$1"
252+
case "$arg" in
253+
-c|--command|--cmd) command="$2"; shift ;;
254+
-d|--debug) DEBUG="$2" ; shift ;;
255+
-s|--sleep) sleepafter="$2"; shift ;;
256+
-h|--host) host="$2"
257+
[ $# -lt 2 ] && usage && exit 2
258+
host="$2"
259+
shift
260+
;;
261+
-t|--ttl) ttl="$2"; shift ;;
262+
-?|--help) usage; exit 2 ;;
263+
-*) # unknown option
264+
err "unknown option $arg"
265+
usage
266+
exit 2
267+
;;
268+
*) # arguments, stop the option parser
269+
break
270+
;;
271+
esac
272+
shift
273+
done
274+
275+
[ "$GCLOUD_PROJECTID" = "" ] && err "GCLOUD_PROJECTID is not set. Unable to set TXT records." && exit 2
276+
[ "$GCLOUD_ZONE" = "" ] && err "GCLOUD_ZONE is not set. Unable to set TXT records." && exit 2
277+
[ "$GCLOUD_ACCOUNT" = "" ] && err "GCLOUD_ACCOUNT is not set. Unable to set TXT records." && exit 2
278+
[ "$GCLOUD_KEYFILE" = "" ] && err "GCLOUD_KEYFILE is not set. Unable to set TXT records." && exit 2
279+
[ ! -f "$GCLOUD_KEYFILE" ] && err "file not usable:$GCLOUD_KEYFILE" && exit 2
280+
281+
282+
all="$*"
283+
fulldomain="$1"
284+
shift
285+
token="$*" # could be 1-n tokens if del
286+
287+
case "$command" in
288+
add) ;;
289+
del) ;;
290+
list) ;;
291+
*) command="" ;;
292+
esac
293+
294+
295+
[ "$command" = "" ] && err "need option -c add | -c del | -c list" && exit 2
296+
[ "$fulldomain" = "" ] && err "need fulldomain argument." && exit 2
297+
[ "$token" = "" ] && [ "$command" != "list" ] && err "need token argument." && exit 2
298+
299+
# dbg info to the program tmp dir
300+
(( DEBUG>0)) && dbg "$fulldomain" "$command"
301+
302+
# host check ending of dot
303+
[ "$host" != "" ] && host=$(check_end_dot "$host")
304+
# host fullname
305+
gname=$(check_end_dot "$host$fulldomain")
306+
#echo "gname: $gname"
307+
308+
# activate google cloud account
309+
gcloud auth activate-service-account "$GCLOUD_ACCOUNT" --key-file="$GCLOUD_KEYFILE" --project="$GCLOUD_PROJECTID"
310+
stat=$?
311+
(( stat > 0 )) && err "gcloud activate account error" && exit 2
312+
313+
case "$command" in
314+
add) add_txt "$gname" "$token"
315+
;;
316+
del) del_txt "$gname" "$token"
317+
;;
318+
list) list_txt "$gname"
319+
;;
320+
*)
321+
err "unknown command"
322+
exit 2
323+
;;
324+
esac
325+
326+
327+

0 commit comments

Comments
 (0)