====== 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"