Created
August 14, 2025 04:07
-
-
Save swateek/1a6c1367ebce3cd8a9f6a432c5c4fb5f to your computer and use it in GitHub Desktop.
AWS Route53 Management Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -euo pipefail | |
AWS_PROFILE="devops" | |
function hosted_zone_exists() { | |
local domain=$1 | |
aws route53 list-hosted-zones-by-name \ | |
--dns-name "$domain" \ | |
--query "HostedZones[?Name=='${domain}.'] | length(@)" \ | |
--output text \ | |
--profile "$AWS_PROFILE" | |
} | |
function get_zone_id() { | |
local domain=$1 | |
aws route53 list-hosted-zones-by-name \ | |
--dns-name "$domain" \ | |
--query "HostedZones[?Name=='${domain}.'].Id | [0]" \ | |
--output text \ | |
--profile "$AWS_PROFILE" | sed 's|/hostedzone/||' | |
} | |
function create_hosted_zone() { | |
local domain=$1 | |
echo "Checking if hosted zone exists for $domain..." | |
if [[ $(hosted_zone_exists "$domain") -eq 1 ]]; then | |
echo "Hosted zone already exists for $domain. Skipping creation." | |
return | |
fi | |
echo "Creating hosted zone for $domain..." | |
hosted_zone_id=$(aws route53 create-hosted-zone \ | |
--name "$domain" \ | |
--caller-reference "$(date +%s)" \ | |
--hosted-zone-config Comment="Created via script",PrivateZone=false \ | |
--query "HostedZone.Id" \ | |
--output text \ | |
--profile "$AWS_PROFILE" \ | |
|| { echo "❌ Failed to create hosted zone."; exit 1; }) | |
hosted_zone_id=${hosted_zone_id#/hostedzone/} | |
echo "✅ Hosted zone created: $hosted_zone_id" | |
if [[ "$domain" == *.*.* ]]; then | |
add_ns_to_parent "$domain" "$hosted_zone_id" | |
else | |
echo "ℹ $domain is not a subdomain, skipping parent NS record update." | |
fi | |
} | |
function delete_hosted_zone() { | |
local domain=$1 | |
if [[ $(hosted_zone_exists "$domain") -eq 0 ]]; then | |
echo "No hosted zone found for $domain. Nothing to delete." | |
return | |
fi | |
zone_id=$(get_zone_id "$domain") | |
echo "Deleting all records (except SOA/NS) from zone $zone_id..." | |
tmpfile=$(mktemp) | |
aws route53 list-resource-record-sets \ | |
--hosted-zone-id "$zone_id" \ | |
--profile "$AWS_PROFILE" \ | |
| jq '{ | |
Changes: [ | |
.ResourceRecordSets[] | |
| select(.Type != "NS" and .Type != "SOA") | |
| {Action: "DELETE", ResourceRecordSet: .} | |
] | |
}' > "$tmpfile" | |
if [[ $(jq '.Changes | length' "$tmpfile") -gt 0 ]]; then | |
aws route53 change-resource-record-sets \ | |
--hosted-zone-id "$zone_id" \ | |
--change-batch file://"$tmpfile" \ | |
--profile "$AWS_PROFILE" | |
fi | |
rm "$tmpfile" | |
if [[ "$domain" == *.*.* ]]; then | |
remove_ns_from_parent "$domain" | |
fi | |
echo "Deleting hosted zone $domain..." | |
aws route53 delete-hosted-zone \ | |
--id "$zone_id" \ | |
--profile "$AWS_PROFILE" \ | |
|| { echo "❌ Failed to delete hosted zone."; exit 1; } | |
echo "✅ Hosted zone deleted." | |
} | |
function add_ns_to_parent() { | |
local subdomain=$1 | |
local sub_zone_id=$2 | |
parent_domain="${subdomain#*.}" | |
parent_zone_id=$(get_zone_id "$parent_domain") | |
# Get all NS records for the subdomain | |
ns_values=$(aws route53 list-resource-record-sets \ | |
--hosted-zone-id "$sub_zone_id" \ | |
--query "ResourceRecordSets[?Type=='NS'].ResourceRecords[].Value" \ | |
--output json \ | |
--profile "$AWS_PROFILE" \ | |
| jq '[.[] | {Value: .}]') | |
if [[ "$parent_zone_id" == "None" ]]; then | |
echo "⚠ Parent domain $parent_domain not found in Route53." | |
echo "Please add the following NS records for $subdomain in your DNS provider manually:" | |
echo "$ns_values" | jq -r '.[].Value' | |
return | |
fi | |
change_batch=$(jq -n \ | |
--arg name "$subdomain." \ | |
--argjson ns "$ns_values" \ | |
'{ | |
Changes: [{ | |
Action: "UPSERT", | |
ResourceRecordSet: { | |
Name: $name, | |
Type: "NS", | |
TTL: 300, | |
ResourceRecords: $ns | |
} | |
}] | |
}') | |
echo "Adding NS record for $subdomain in $parent_domain..." | |
aws route53 change-resource-record-sets \ | |
--hosted-zone-id "$parent_zone_id" \ | |
--change-batch "$change_batch" \ | |
--profile "$AWS_PROFILE" | |
echo "✅ NS record added to parent." | |
} | |
function remove_ns_from_parent() { | |
local subdomain=$1 | |
parent_domain="${subdomain#*.}" | |
parent_zone_id=$(get_zone_id "$parent_domain") | |
if [[ "$parent_zone_id" == "None" ]]; then | |
echo "⚠ Parent domain $parent_domain not found in Route53. Please remove NS records manually if needed." | |
return | |
fi | |
echo "Removing NS record for $subdomain from $parent_domain..." | |
ns_record=$(aws route53 list-resource-record-sets \ | |
--hosted-zone-id "$parent_zone_id" \ | |
--query "ResourceRecordSets[?Name=='${subdomain}.'] | [?Type=='NS']" \ | |
--output json \ | |
--profile "$AWS_PROFILE") | |
if [[ "$ns_record" == "[]" ]]; then | |
echo "No NS record found for $subdomain in parent. Skipping." | |
return | |
fi | |
change_batch=$(jq -n --argjson record "$ns_record" '{Changes:[{Action:"DELETE",ResourceRecordSet:$record[0]}]}') | |
aws route53 change-resource-record-sets \ | |
--hosted-zone-id "$parent_zone_id" \ | |
--change-batch "$change_batch" \ | |
--profile "$AWS_PROFILE" | |
echo "✅ NS record removed from parent." | |
} | |
echo "Enter action (create/delete):" | |
read -r action | |
echo "Enter domain (without trailing dot):" | |
read -r domain | |
case "$action" in | |
create) create_hosted_zone "$domain" ;; | |
delete) delete_hosted_zone "$domain" ;; | |
*) echo "Invalid action. Use 'create' or 'delete'." ;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When to use?
When a new client gets added, we manually entered these credentials via the Console and repeated it; thus automating it via this script
What it needs?
How to Run?