User Tools

Site Tools


howtos:empty_a_zone

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
howtos/empty_a_zone.txt · Last modified: 09/04/2023 14:15 by domingo