|
#!/usr/bin/env bash |
|
# |
|
# Script Name: cloudflare_encryption_mode.sh |
|
# Description: This script retrieves the list of domains from a Cloudflare account using the provided API credentials, checks their current encryption modes, and optionally updates them based on user input. A markdown report is generated displaying previous and updated statuses. |
|
# Author: Troy Kelly |
|
# Contact: [email protected] |
|
# Date: 07 October 2024 |
|
# Version: 1.3 |
|
# |
|
# History: |
|
# - Version 1.0: Initial script creation. |
|
# - Version 1.1: Added verbosity switch to output server interactions. |
|
# - Version 1.2: Improved table formatting with padded and centered values. |
|
# - Version 1.3: Adjusted function outputs to redirect messages to STDERR. |
|
|
|
# Exit immediately if a command exits with a non-zero status. |
|
set -e |
|
|
|
# Trap signals and handle cleanup |
|
trap 'cleanup' EXIT |
|
trap 'echo "Script interrupted." >&2; exit 1' INT TERM |
|
|
|
# Functions |
|
|
|
# Function to perform cleanup on exit |
|
cleanup() { |
|
# Placeholder for any cleanup tasks |
|
: |
|
} |
|
|
|
# Function to display usage information |
|
usage() { |
|
echo "Usage: $0 [--change-to MODE] [--verbose]" >&2 |
|
echo "Options:" >&2 |
|
echo " --change-to MODE Desired encryption mode (off, flexible, full, strict, origin_pull)" >&2 |
|
echo " --verbose, -v Enable verbose output" >&2 |
|
exit 1 |
|
} |
|
|
|
# Check for required environment variables |
|
if [[ -z "$CF_API_EMAIL" ]] || [[ -z "$CF_API_KEY" ]]; then |
|
echo "Error: CF_API_EMAIL and CF_API_KEY environment variables must be set." >&2 |
|
exit 1 |
|
fi |
|
|
|
# Parse command-line arguments |
|
CHANGE_TO="" |
|
VERBOSE=false |
|
while [[ $# -gt 0 ]]; do |
|
case "$1" in |
|
--change-to) |
|
if [[ -n "$2" ]]; then |
|
CHANGE_TO="$2" |
|
shift 2 |
|
else |
|
echo "Error: --change-to option requires an argument." >&2 |
|
usage |
|
fi |
|
;; |
|
--verbose|-v) |
|
VERBOSE=true |
|
shift |
|
;; |
|
*) |
|
echo "Error: Invalid option $1" >&2 |
|
usage |
|
;; |
|
esac |
|
done |
|
|
|
# Validate the CHANGE_TO value if provided |
|
VALID_MODES=("off" "flexible" "full" "strict" "origin_pull") |
|
if [[ -n "$CHANGE_TO" ]] && [[ ! " ${VALID_MODES[*]} " =~ " ${CHANGE_TO} " ]]; then |
|
echo "Error: Invalid encryption mode '${CHANGE_TO}'. Valid modes are: ${VALID_MODES[*]}." >&2 |
|
exit 1 |
|
fi |
|
|
|
# Variables |
|
API_ENDPOINT="https://api.cloudflare.com/client/v4" |
|
AUTH_HEADERS=( |
|
-H "X-Auth-Email: $CF_API_EMAIL" |
|
-H "X-Auth-Key: $CF_API_KEY" |
|
-H "Content-Type: application/json" |
|
) |
|
DOMAINS=() |
|
REPORT_LINES=() |
|
|
|
# Column widths |
|
DOMAIN_WIDTH=30 |
|
MODE_WIDTH=15 |
|
|
|
# Function to center text within a given width |
|
center_text() { |
|
local width=$1 |
|
local text="$2" |
|
local text_length=${#text} |
|
if [[ $text_length -ge $width ]]; then |
|
echo "$text" |
|
else |
|
local padding_total=$((width - text_length)) |
|
local padding_left=$((padding_total / 2)) |
|
local padding_right=$((padding_total - padding_left)) |
|
printf "%*s%s%*s" $padding_left "" "$text" $padding_right "" |
|
fi |
|
} |
|
|
|
# Function to generate table separator |
|
generate_separator() { |
|
local width=$1 |
|
printf '+%0.s-' $(seq 1 $width) |
|
} |
|
|
|
# Function to get list of zones (domains) |
|
get_zones() { |
|
local page=1 |
|
while true; do |
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Fetching zones: page $page" >&2 |
|
fi |
|
|
|
local response |
|
response=$(curl -s "${AUTH_HEADERS[@]}" -G "${API_ENDPOINT}/zones" --data-urlencode "page=${page}" --data-urlencode "per_page=50") |
|
|
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Response from fetching zones (page $page):" >&2 |
|
echo "$response" | jq '.' >&2 |
|
fi |
|
|
|
local success |
|
success=$(echo "$response" | jq -r '.success') |
|
if [[ "$success" != "true" ]]; then |
|
echo "Error retrieving zones: $(echo "$response" | jq -r '.errors[]?.message')" >&2 |
|
exit 1 |
|
fi |
|
local result_count |
|
result_count=$(echo "$response" | jq '.result | length') |
|
if [[ "$result_count" -eq 0 ]]; then |
|
break |
|
fi |
|
local zone_ids |
|
zone_ids=$(echo "$response" | jq -r '.result[] | {id, name} | @base64') |
|
while IFS= read -r zone; do |
|
DOMAINS+=("$zone") |
|
done <<< "$zone_ids" |
|
((page++)) |
|
done |
|
} |
|
|
|
# Function to get current encryption mode for a zone |
|
get_encryption_mode() { |
|
local zone_id="$1" |
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Getting encryption mode for zone ID: $zone_id" >&2 |
|
fi |
|
|
|
local response |
|
response=$(curl -s "${AUTH_HEADERS[@]}" -X GET "${API_ENDPOINT}/zones/${zone_id}/settings/ssl") |
|
|
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Response from getting encryption mode for zone ID $zone_id:" >&2 |
|
echo "$response" | jq '.' >&2 |
|
fi |
|
|
|
echo "$response" | jq -r '.result.value' |
|
} |
|
|
|
# Function to update encryption mode for a zone |
|
update_encryption_mode() { |
|
local zone_id="$1" |
|
local mode="$2" |
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Updating encryption mode for zone ID: $zone_id to '$mode'" >&2 |
|
fi |
|
|
|
local response |
|
response=$(curl -s "${AUTH_HEADERS[@]}" -X PATCH "${API_ENDPOINT}/zones/${zone_id}/settings/ssl" --data "{\"value\":\"${mode}\"}") |
|
|
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Response from updating encryption mode for zone ID $zone_id:" >&2 |
|
echo "$response" | jq '.' >&2 |
|
fi |
|
|
|
local success |
|
success=$(echo "$response" | jq -r '.success') |
|
if [[ "$success" != "true" ]]; then |
|
echo "Error updating encryption mode for zone ${zone_id}: $(echo "$response" | jq -r '.errors[]?.message')" >&2 |
|
exit 1 |
|
fi |
|
} |
|
|
|
# Main script execution |
|
main() { |
|
get_zones |
|
|
|
# Table header |
|
local header_domain=$(center_text $DOMAIN_WIDTH "Domain") |
|
local header_prev_mode=$(center_text $MODE_WIDTH "Previous Mode") |
|
local header_updated_mode=$(center_text $MODE_WIDTH "Updated Mode") |
|
local separator="+$(printf '%0.s-' $(seq 1 $((DOMAIN_WIDTH + 2))))+$(printf '%0.s-' $(seq 1 $((MODE_WIDTH + 2))))+$(printf '%0.s-' $(seq 1 $((MODE_WIDTH + 2))))+" |
|
REPORT_LINES+=("$separator") |
|
REPORT_LINES+=("| $header_domain | $header_prev_mode | $header_updated_mode |") |
|
REPORT_LINES+=("$separator") |
|
|
|
for zone_base64 in "${DOMAINS[@]}"; do |
|
# Decode the base64 encoded JSON |
|
local zone_json |
|
zone_json=$(echo "$zone_base64" | base64 --decode) |
|
local zone_id |
|
zone_id=$(echo "$zone_json" | jq -r '.id') |
|
local zone_name |
|
zone_name=$(echo "$zone_json" | jq -r '.name') |
|
|
|
if [[ "$VERBOSE" == true ]]; then |
|
echo "Processing zone: $zone_name (ID: $zone_id)" >&2 |
|
fi |
|
|
|
# Get current encryption mode |
|
local current_mode |
|
current_mode=$(get_encryption_mode "$zone_id") |
|
|
|
local updated_mode="$current_mode" |
|
|
|
# Update encryption mode if necessary |
|
if [[ -n "$CHANGE_TO" ]] && [[ "$current_mode" != "$CHANGE_TO" ]]; then |
|
update_encryption_mode "$zone_id" "$CHANGE_TO" |
|
updated_mode="$CHANGE_TO" |
|
fi |
|
|
|
# Center values |
|
local centered_domain=$(center_text $DOMAIN_WIDTH "$zone_name") |
|
local centered_current_mode=$(center_text $MODE_WIDTH "$current_mode") |
|
local centered_updated_mode=$(center_text $MODE_WIDTH "$updated_mode") |
|
|
|
# Append to report |
|
REPORT_LINES+=("| $centered_domain | $centered_current_mode | $centered_updated_mode |") |
|
done |
|
|
|
# Add table footer |
|
REPORT_LINES+=("$separator") |
|
|
|
# Output the report |
|
for line in "${REPORT_LINES[@]}"; do |
|
echo "$line" |
|
done |
|
} |
|
|
|
# Execute the main function |
|
main |