====== Restore or Create Records from File ======
I made this script to be able to quickly populate a zone with a default set of records. I then turned into a complete restore function based on the backup script also provided [[howtos:backup_zones|here]].
===== The Script =====
Basically you run the script with a backup file as a parameter. The file can be the backup dumped from the backup script or it can be handcrafted to fit a specific purpose, like a template.
==== Input File ====
The input file is formed like a csv file. First is the record type, and then depending on the type, different fields.
A,example.com,10.10.10.10,1,false,
A,chaos.example.com,10.10.10.10,1,false,
A,kaos.example.com,10.10.10.10,1,false,
A,mc1.example.com,10.10.10.10,1,false,
A,mc2.example.com,10.10.10.10,1,false,
CNAME,*.example.com,example.com,1,false,
SRV,_minecraft,_tcp,chaos.example.com,0,5,25562,mc1.example.com,1,false,
SRV,_minecraft,_tcp,kaos.example.com,0,5,25562,mc1.example.com,1,false,
SRV,_minecraft,_tcp,mc1.example.com,0,5,25564,mc1.example.com,1,false,
SRV,_minecraft,_tcp,mc2.example.com,0,5,25563,mc1.example.com,1,false,
TXT,example.com,v=spf1 ip4:172.17.4.5/32 ~all,1,false,
TXT,_dmarc.example.com,v=DMARC1; p=reject; rua=mailto:dmarc@example.com,1,false,
CAA,example.com,0,issue,letsencrypt.org,1,false,
==== Restore Script ====
The restore script take two API tokens, one for creating the zone records, and one for turning on the Certificate Transparency Monitoring feature. The two functions requires different authorization in Cloudflare. If you don't care about CT you can just disabled the function by setting the variable "ENABLE_CT=0".
#!/bin/bash
# Set your Cloudflare API key
API_KEY="xxx"
CT_AUTH_TOKEN="xxx"
IFS=","
TOGGLE="true"
ENABLE_CT=1
USE_COMMENTS=1
DEBUG=1
# Read the input file line by line
while read line; do
# Skip any lines that start with a # or is blank
[[ $line =~ ^([[:space:]]*#|$) ]] && continue
# Split the line into an array using tabs as the delimiter
read -ra RECORD <<< "$line"
# Look up the zone ID for the domain using Cloudflare's API
if [ "${RECORD[0]}" = "A" ] || [ "${RECORD[0]}" = "TXT" ] || [ "${RECORD[0]}" = "CAA" ] || [ "${RECORD[0]}" = "CNAME" ]; then
# For A, TXT, and CAA records, use the domain name itself (without the subdomain) to look up the zone ID
DOMAIN=$(echo "${RECORD[1]}" | awk -F'.' '{print $(NF-1)"."$NF}')
[[ $DEBUG -eq 1 ]] && echo "Domain extracted: $DOMAIN - ${RECORD[@]}"
elif [ "${RECORD[0]}" = "SRV" ];then
DOMAIN="${RECORD[3]}"
[[ $DEBUG -eq 1 ]] && echo "Domain extracted: $DOMAIN - ${RECORD[@]}"
else
# For all other records, use the full domain name to look up the zone ID
DOMAIN="${RECORD[1]}"
[[ $DEBUG -eq 1 ]] && echo "Domain from file: $DOMAIN"
fi
#echo name=${DOMAIN};sleep 10
ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${DOMAIN}" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" | jq -r '.result[0].id')
[[ $DEBUG -eq 1 ]] && echo "Zone ID: $ZONE_ID"
# If the zone ID is not found, print an error and skip the record
if [[ "$ZONE_ID" = "null" ]]; then
echo "Error: Could not find zone ID for domain ${RECORD[1]}"
continue
fi
# Insert comments in DNS records
if [[ $USE_COMMENTS -eq 1 ]]; then
last_element=${RECORD[-1]}
echo "last: $last_element"
# Check if the last element starts with "comment:"
if [[ "$last_element" == comment:* ]]; then
echo "comment: $last_element"
# Extract the comment text by removing the "comment: " prefix
comment_text=${last_element#comment:}
fi
else
comment_text=""
echo "lastx: $last_element"
fi
# Create the JSON data for the DNS record
if [ "${RECORD[0]}" = "MX" ]; then
# Create JSON for MX records with priority value
JSON="{\"type\":\"${RECORD[0]}\",\"name\":\"${RECORD[1]}\",\"content\":\"${RECORD[2]}\",\"priority\":${RECORD[3]},\"ttl\":${RECORD[4]},\"proxied\":${RECORD[5]}}"
elif [ "${RECORD[0]}" = "A" ] || [ "${RECORD[0]}" = "TXT" ]; then
# Create JSON for A and TXT records
JSON="{\"type\":\"${RECORD[0]}\",\"name\":\"${RECORD[1]}\",\"content\":\"${RECORD[2]}\",\"ttl\":${RECORD[3]},\"proxied\":${RECORD[4]}}"
elif [ "${RECORD[0]}" = "CAA" ]; then
# Create JSON for CAA records
JSON="{\"type\":\"${RECORD[0]}\",\"name\":\"${RECORD[1]}\",\"data\":{\"flags\":${RECORD[2]},\"tag\":\"${RECORD[3]}\",\"value\":\"${RECORD[4]}\"},\"ttl\":${RECORD[5]},\"proxied\":${RECORD[6]}}"
elif [ "${RECORD[0]}" = "SRV" ]; then
# Create JSON for SRV records
JSON="{\"type\":\"${RECORD[0]}\",\"comment\":\"$comment_text\",\"data\":{\"service\":\"${RECORD[1]}\",\"proto\":\"${RECORD[2]}\",\"name\":\"${RECORD[3]}\",\"priority\":${RECORD[4]},\"weight\":${RECORD[5]},\"port\":${RECORD[6]},\"target\":\"${RECORD[7]}\"}}"
else
# Create JSON for all other record types
JSON="{\"type\":\"${RECORD[0]}\",\"name\":\"${RECORD[1]}\",\"content\":\"${RECORD[2]}\",\"ttl\":${RECORD[3]},\"proxied\":${RECORD[4]}}"
fi
[[ $DEBUG -eq 1 ]] && echo "JSON: $JSON"
# Make the API call using curl
RESULT=$(curl -s -X POST -H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-d "$JSON" \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records")
# Check if the API call was successful and print the result
if echo "$RESULT" | jq -r '.success' | grep -q "true"; then
echo "Record ${RECORD[1]} (${RECORD[0]}) successfully updated"
[[ $DEBUG -eq 1 ]] && echo "Good result:" && echo "$RESULT"|jq
else
echo "Error updating record ${RECORD[1]} (${RECORD[0]}):"
echo "$RESULT" | jq -r '.errors[0].message'
[[ $DEBUG -eq 1 ]] && echo "Bad result:" && echo "$RESULT" | jq
fi
if [[ $ENABLE_CT -eq 1 ]]; then
# Enable Certificate Transparency Monitoring for the zone
RESULT=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/ct/alerting" \
-H "Authorization: Bearer ${CT_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
--data '{"enabled":'$TOGGLE'}')
# Check if the API call was successful and print the result
if echo "$RESULT" | jq -r '.success' | grep -q "true"; then
echo "Certificate Transparency Monitoring successfully enabled for zone ${DOMAIN}"
[[ $DEBUG -eq 1 ]] && echo "Good result:" && echo "$RESULT" | jq
else
echo "Error enabling Certificate Transparency Monitoring for zone ${DOMAIN}:"
echo "$RESULT" | jq -r '.errors[0].message'
[[ $DEBUG -eq 1 ]] && echo "Bad result:" && echo "$RESULT" | jq
fi
fi
done < "$1"