====== Empty a Zone ====== To be honest I don't really know when this script could be useful. I made it because I needed a way to test the restore script with an empty zone. It does its thing very efficiently, so please be very careful when you use it. I have tried to safeguard it but if you make a mistake there is no way back! ===== The Script ===== You simply run the script with the zone as a parameter. For now, it only take one zone at a time. #!/bin/bash # This script deletes all DNS records in a specified Cloudflare zone. # It requires the user to confirm the deletion by entering a generated confirmation code. # Debug mode can be enabled by setting the DEBUG variable to 1,2 or 3. # Set your Cloudflare API credentials CF_API_KEY="xxx" # DEBUG can be between 0-3 DEBUG=2 # [[ $DEBUG -gt 2 ]] && set -x # Set the Cloudflare API base URL CF_API_BASE_URL="https://api.cloudflare.com/client/v4" # The output_format parameter controls how debug messages are printed: # - 0: Print a single message (default) # - 1: Print an array of messages # - 2: Print a JSON object (requires the 'jq' command) function debug { local message="${@:3}" local output_format="${1}" local source_function="${2}" case "${output_format}" in 0) echo "*DEBUG* $source_function: ${message}" >&2;echo ;; 1) echo "*DEBUG* $source_function: " && echo ${message[@]}|sed 's/ /,\n/g;s/$/,/';echo;; 2) echo "*DEBUG* $source_function:" && echo "${message}" | jq >&2;echo ;; *) echo "ERROR $source_function: Invalid output format: ${output_format}" >&2;echo ;; esac } # Function to test if the Cloudflare API key is valid function test_cloudflare_api_key { local api_key=$1 # Make API call to Cloudflare local response=$(curl -s -X GET "${CF_API_BASE_URL}/user/tokens/verify" \ -H "Authorization: Bearer $api_key") #[[ $DEBUG -gt 0 ]] && debug "$response" 2 "test_cloudflare_api_key" [[ $DEBUG -gt 0 ]] && debug 2 "test_cloudflare_api_key" "$response" # Check response for errors local errors=$(echo $response | jq -r '.errors[]?.code') if [[ ! -z $errors ]]; then echo "Error verifying Cloudflare API key: $errors" return 1 fi echo "Cloudflare API key verified successfully!" return 0 } # Function to generate a random string for confirmation generate_random_string() { cat /dev/urandom | tr -dc 'A-Z0-9' | fold -w 4 | head -n 1 } # Function to print the colored confirmation code print_colored_code() { local code=$1 local number_color_code='\033[0;32m' # Green color local default_color_code='\033[0m' # Reset to default color for ((i=0; i<${#code}; i++)); do char="${code:$i:1}" if [[ $char =~ [0-9] ]]; then printf "${number_color_code}%s${default_color_code} " "${char}" else printf "%s " "${char}" fi done #printf "\n" } # Function to get the zone ID for a given zone name get_zone_id() { local zone_name=$1 local zone_id zone_id=$(curl -s -X GET "${CF_API_BASE_URL}/zones?name=${zone_name}" \ -H "Authorization: Bearer ${CF_API_KEY}" \ -H "Content-Type: application/json" | jq -r '.result[0].id') echo "$zone_id" } # Function to get all DNS records for a specified zone ID get_records() { local zone_id=$1 local records records=$(curl -s -X GET "${CF_API_BASE_URL}/zones/${zone_id}/dns_records" \ -H "Authorization: Bearer ${CF_API_KEY}" \ -H "Content-Type: application/json") echo "$records" } # Function to delete a DNS record by zone ID and record ID delete_record() { local zone_id=$1 local record_id=$2 local response if [[ $DEBUG -gt 1 ]];then record=$(curl -s -X GET "${CF_API_BASE_URL}/zones/${zone_id}/dns_records/${record_id}" \ -H "Authorization: Bearer ${CF_API_KEY}" \ -H "Content-Type: application/json") debug 2 "delete_record" "$record" fi response=$(curl -s -X DELETE "${CF_API_BASE_URL}/zones/${zone_id}/dns_records/${record_id}" \ -H "Authorization: Bearer ${CF_API_KEY}" \ -H "Content-Type: application/json") [[ $DEBUG -gt 0 ]] && echo "Deletion response for record ID $record_id:" && echo $response | jq } # Test the API key before proceeding with the script if ! test_cloudflare_api_key "${CF_API_KEY}"; then echo "Error: Invalid Cloudflare API key." exit 1 fi # Check for the zone parameter if [ -z "$1" ]; then echo "Error: Zone Parameter is missing." exit 1 fi zone_name="$1" [[ $DEBUG -gt 0 ]] && echo "Zone Name Supplied: ${zone_name}" && echo ZONE_ID=$(get_zone_id "${zone_name}") [[ $DEBUG -gt 0 ]] && debug 0 "get_zone_id" "${ZONE_ID}" RECORDS=$(get_records "${ZONE_ID}") [[ $DEBUG -gt 0 ]] && debug 2 "get_records" "${RECORDS}" RECORD_IDS=($(echo "$RECORDS" | jq -r '.result[].id')) if [[ ${#RECORD_IDS[@]} -eq 0 ]]; then echo "RECORD_IDS is an empty array - No records found exiting..." echo exit 0 elif [[ $DEBUG -gt 1 ]];then #echo "RECORD_IDS contains: ${RECORD_IDS[@]}" debug 1 "RECORD_IDS contains" "${RECORD_IDS[@]}" elif [[ $DEBUG -gt 0 ]];then echo "RECORD_IDS contains ${#RECORD_IDS[@]} elements" fi confirmation_code=$(generate_random_string) #[[ $DEBUG -gt 1 ]] && debug "${confirmation_code}" "0" "confirmation_code" [[ $DEBUG -gt 1 ]] && debug 0 "confirmation_code" "${confirmation_code}" # Prompt user to confirm the deletion of all DNS records in the specified zone echo "WARNING: This script will destroy the ENTIRE zone for ${zone_name}. Are you sure you want to continue?" echo -n "To confirm, please enter the following code: " print_colored_code "${confirmation_code}" echo -e " (numbers are in \033[0;32mgreen\033[0m, it is case insensitive)" read -r -p "Enter the confirmation code: " user_input # Remove any spaces and sanitize from input before comparing input=$(echo "$user_input" | sed 's/[^[:alnum:]]//g') # If the user enters the correct confirmation code, proceed with the deletion of the DNS records # ",," lowercase the variable on both user_input and confirmation_code if [[ "${input,,}" == "${confirmation_code,,}" ]]; then # Loop through the record IDs and delete each record using the delete_record function for ID in "${RECORD_IDS[@]}"; do echo "Deleting record with ID: $ID" delete_record "${ZONE_ID}" "${ID}" done echo echo "----------------------------------------------------" echo "All DNS records for zone $ZONE_ID have been deleted." else # If the user enters an incorrect confirmation code, the script exits without deleting the DNS records echo "Invalid confirmation code. Destruction cancelled." fi