5 minutes
DNS: DNS’s Not Scary (kinda)
Before the beginning
This article originated from a desire to:
- Have the
surrealsoftware.com.au
domain managed by Route 53; and - Migrate the Hosted Zone from my Management account to a child account.
I hesitated for years as even though I have a strong software development background, networking has always been a weakness for me. Read on how I overcame my hesitation and conquered my fears.
In the beginning
Way back in March 2015 I created an AWS account for personal use. For many years, this was my only account, and I experimented freely by clicking through the AWS Console (shudder). I deleted resources that would cost me money and left behind resources that wouldn’t. My surrealsoftware.com.au
domain name was registered through an external registrar and I chucked up the obligatory “Under Construction” page and left it at that.
Years later, when AWS Organisations came into existence, I switched it on and made a half-arsed attempt to segregate different projects into different accounts. You guessed it… this website was one of those projects!
A few months back I finally transferred the domain name to Route 53 in the management account (as this was where my Hosted Zone resided). This left me with a little brain-itch; the website was hosted in a different AWS account and I was paying for two hosted zones when I only needed to pay for one. So, a few weeks back (at time of publishing) I finally got around to migrating the domain name and hosted zone to the child AWS account.
Task 1: Migrating the domain name
My first task involved migrating the domain name between accounts. A quick read of the two pages below and I felt confident to tackle migration via the AWS CLI. I kept the transcript, (with private things redacted) to hopefully pay-it-forwards to the next person attempting this.
# List all the domains (silly when there was only one, but hey 😄)
aws --region us-east-1 --profile mgmt-account route53domains list-domains
{
"Domains": [
{
"DomainName": "surrealsoftware.com.au",
...
}
]
}
# Initiate transfer to the new account
aws --region us-east-1 --profile mgmt-account
route53domains transfer-domain-to-another-aws-account \
--domain-name "surrealsoftware.com.au" \
--account-id "222222222222"
{
"OperationId": "redacted-operation-id-1",
"Password": "redacted-password"
}
# Accept the transfer to the child account
aws --region us-east-1 --profile child-account \
route53domains accept-domain-transfer-from-another-aws-account \
--domain-name "surrealsoftware.com.au" \
--password "redacted-password"
{
"OperationId": "redacted-operation-id-2"
}
# Verify that the transfer was successful
aws --region us-east-1 --profile child-account \
route53domains get-operation-detail \
--operation-id "redacted-operation-id-2"
{
"OperationId": "redacted-operation-id-2",
"Status": "SUCCESSFUL",
"DomainName": "surrealsoftware.com.au",
...
}
Total time was only a few minutes. Super easy!
Task 2: Migrate the hosted zone
Now the domain name was in the right account, the second task was to migrate the DNS records from the Management account’s Hosted Zone to the child account. Even though this is an optional step, I still did it because:
- I want to follow AWS Account best-practices and keep the Management account as empty-as-possible of resources; and
- I wanted to avoid paying for multiple hosted zones.
A quick read of Migrating a hosted zone to a different AWS account and I was underway.
Side Note: Rather than creating the Hosted Zone via the AWS Console, I wrapped it up in a CloudFormation template. In the not-too-distant future I’ll be deploying additional shared resources within the account, such as AWS Cognito. When I do, I can then extend the CloudFormation template with these additional resources.
# Find the HostedZoneId in the management account
aws --profile mgmt-account route53 list-hosted-zones
{
"HostedZones": [
{
"Id": "/hostedzone/ZMGMTHOSTEDZN",
"Name": "surrealsoftware.com.au.",
...
}
]
}
# Dump out all the record-sets into a JSON file
aws --profile mgmt-account route53 list-resource-record-sets --hosted-zone-id ZMGMTHOSTEDZN > old-record-sets.json
# Follow the docs here and turn the "old-record-sets.json" into "new-change-record-sets.json"
# I stopped here and deployed my CloudFormation template to create shared resources (ie. the new HostedZone)
# aws --profile child-account cloudformation deploy ....
# Find the HostedZoneId in the child account
aws --profile child-account route53 list-hosted-zones
{
"HostedZones": [
{
"Id": "/hostedzone/ZCHILDHOSTEDZONE12345",
"Name": "www.surrealsoftware.com.au.",
"CallerReference": "Route53HostedZone-d8dlJMZjN7R2",
"Comment": "Old hosted zone - about to be replaced",
},
},
{
"Id": "/hostedzone/ZNEW_HOSTED_ZONE_1234",
"Name": "surrealsoftware.com.au.",
...
}
]
}
# Import the record-sets into the new HostedZone
aws --profile child-account route53 change-resource-record-sets --hosted-zone-id "ZNEW_HOSTED_ZONE_1234" --change-batch file://new-change-record-sets.json
{
"ChangeInfo": {
"Id": "/change/C000CHANGEID000ABCDEF",
"Status": "PENDING",
...
}
}
# Verify the change was successful
aws --profile child-account route53 get-change --id "/change/C000CHANGEID000ABCDEF"
{
"ChangeInfo": {
"Id": "/change/C000CHANGEID000ABCDEF",
"Status": "INSYNC",
...
}
}
# Grab the new record-sets
aws --profile child-account route53 list-resource-record-sets --hosted-zone-id "ZNEW_HOSTED_ZONE_1234" > new-record-sets.json
# And finally performed a diff and verify that all is good!
Task 3: Update the domain name’s name servers
The final task requires updating the domain name’s name servers to the values in the new Hosted Zone. This is also easily done via the CLI:
aws --region us-east-1 --profile child-account route53domains \
update-domain-nameservers \
--domain-name "surrealsoftware.com.au" \
--nameservers \
Name=ns-new1.example.com. \
Name=ns-new1.example.org. \
Name=ns-new1.example.net. \
Name=ns-new2.example.com.
{
"OperationId": "00000000-0000-0000-0000-exampleid000"
}
aws --region us-east-1 --profile child-account route53domains get-operation-detail --operation-id "00000000-0000-0000-0000-exampleid000"
{
"OperationId": "00000000-0000-0000-0000-exampleid000",
"Status": "SUCCESSFUL",
"DomainName": "surrealsoftware.com.au",
"Type": "UPDATE_NAMESERVER",
}
In the end
I hesitated for months, based on an irrational fear, before attempting the migration. In hindsight my fears about how hard it would be and what would I do if it all went wrong were unfounded.
In the end, the execution was smooth and I’m saving a whole $1 a month. Wahoo!!