43 lines
1.9 KiB
Bash
43 lines
1.9 KiB
Bash
#!/usr/bin/env bash
|
|
# Run with the agenix-backed Cloudflare EnvironmentFile, never with a token
|
|
# on the command line. Default is read-only; --apply creates missing records.
|
|
set -euo pipefail
|
|
set +x
|
|
mode=${1:---check}
|
|
[[ "$mode" == --check || "$mode" == --apply ]] || exit 2
|
|
: "${CLOUDFLARE_DNS_API_TOKEN:?Cloudflare environment required}"
|
|
api() {
|
|
printf 'Authorization: Bearer %s\n' "$CLOUDFLARE_DNS_API_TOKEN" |
|
|
curl --fail --silent --show-error --max-time 30 -H @- \
|
|
-H 'Content-Type: application/json' "$@"
|
|
}
|
|
base=https://api.cloudflare.com/client/v4
|
|
zone=$(api "$base/zones?name=lukasrosier.com" |
|
|
jq -er 'select(.success) | .result | select(length == 1) | .[0].id')
|
|
target=ipv6-test.0ff.space
|
|
missing=()
|
|
# Preflight all identity names before writing any of them. Never replace an existing
|
|
# service, delete a record, or touch the wildcard/mail/NS/0ff.space records.
|
|
for name in dex.lukasrosier.com head.lukasrosier.com lldap.lukasrosier.com; do
|
|
records=$(api "$base/zones/$zone/dns_records?name=$name&per_page=100" |
|
|
jq -ec 'select(.success) | .result')
|
|
if [[ $(jq length <<< "$records") == 0 ]]; then
|
|
missing+=("$name")
|
|
printf 'Missing: %s CNAME %s (DNS-only)\n' "$name" "$target"
|
|
elif jq -e --arg target "$target" \
|
|
'length == 1 and .[0].type == "CNAME" and
|
|
(.[0].content | rtrimstr(".")) == $target and .[0].proxied == false' \
|
|
<<< "$records" >/dev/null; then
|
|
printf 'Already correct: %s\n' "$name"
|
|
else
|
|
printf 'Refusing to replace existing records at %s\n' "$name" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
[[ "$mode" == --apply ]] || exit 0
|
|
for name in "${missing[@]}"; do
|
|
payload=$(jq -nc --arg name "$name" --arg target "$target" \
|
|
'{type:"CNAME",name:$name,content:$target,proxied:false,ttl:300}')
|
|
api -X POST "$base/zones/$zone/dns_records" --data "$payload" |
|
|
jq -e 'select(.success) | .result | {id,name,type,content,proxied,ttl}'
|
|
done
|