Skip to content

Migrating a domain between AWS accounts

The concept of a domain management strategy is not something most organizations have to think about. But when the time comes time, the domain of an organization is the gateway to everything. Remember when the Facebook domain failed? The repair personell could not get into the data centers because the badge system used the domain for routing. Service discovery? Also domain based. Nearly every system that is not strictly IP based is domain based. How many service do you know by there static IP? Now how many services do you know by the domain name? Exactly.

So, more on topic. I have a bunch of domains in one AWS account. I want to move them around to limit blast radius, simplify management and scope 1 account to 1 named service.

PreFlight

To start out, we need two accounts, the source account we will call Alice and the target account will be named Bob; The example domain to be transferred is example.davidjeddy.com.

Part 1: Create a New Hosted Zone in the Target (Bob) Account

https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingHostedZone.html

req

aws route53 help \
--profile Bob \
--region us-east-1 \
--name example.davidjeddy.com \
--caller-reference '2022-08-18-12:00'

res

{
    "Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/Z02205203TCTY653BIA2",
    "HostedZone": {
        "Id": "/hostedzone/REDACTED",
        "Name": "example.davidjeddy.com.",
        "CallerReference": "2022-08-18-12:00",
        "Config": {
            "PrivateZone": false
        },
        "ResourceRecordSetCount": 2
    },
    "ChangeInfo": {
        "Id": "/change/C02802112YUJ33OQQ76BR",
        "Status": "PENDING",
        "SubmittedAt": "2022-08-18T12:12:04.864000+00:00"
    },
    "DelegationSet": {
        "NameServers": [
            "ns-179.awsdns-22.com",
            "ns-1984.awsdns-56.co.uk",
            "ns-1468.awsdns-55.org",
            "ns-890.awsdns-47.net"
        ]
    }
}

Nice, success on the first try. Checking the web console we see the new hosted zone.

New hosted zone in Route53
New hosted zone in Route53

Part 2: Populate the Target Hosted Zone

Almost never does a hosted zone contain only the SOA and NS records. We needs to migrate the existing records from the source hosted zone. Some records will change, like for TLS cert validation. But it will not hurt to leave the existing records until a new cert is validated against the domain.

Get the output of the existing records from source account…

req

aws route53 list-resource-record-sets \
--profile Alice \
--region us-east-1 \
--hosted-zone-id Z05933361F5NB2U4L7ORN > hosted_zone_records.json 

Now we have a JSON formatted file for all the DNS records in the source hosted zone. Unfortunately some manual editing of the JSON is needed before importing the records into the target (Bob) account. I also removed the SOA and NS from the source as I wanted to use the records created in the target hosted zone.

The result should look similar to the example provided by AWS.

{
    "Comment": "string",
    "Changes": [
        {
            "Action": "CREATE",
            "ResourceRecordSet":{
                "ResourceRecords": [
                    {
                        "Value": "192.0.2.4"
                    }, 
                    {
                        "Value": "192.0.2.5"
                    }, 
                    {
                        "Value": "192.0.2.6"
                    }
                ], 
                "Type": "A", 
                "Name": "route53documentation.com.", 
                "TTL": 300
            }
        },
        {
            "Action": "CREATE",
            "ResourceRecordSet":{
                "AliasTarget": {
                    "HostedZoneId": "Z3BJ6K6RIION7M",
                    "EvaluateTargetHealth": false,
                    "DNSName": "s3-website-us-west-2.amazonaws.com."
            },
                "Type": "A",
                "Name": "www.route53documentation.com."
            }
        }
    ]
}

Now with the JSON payload primed and ready, time to import the records into the new target hosted zone.

req

aws route53 change-resource-record-sets \
--profile Bob \
--region us-east-1 \
--hosted-zone-id id-of-new-hosted-zone \
--change-batch file://path-to-file-that-contains-records

res

(I forgot to save the response, but it should indicate success).

Now compare the source hosted zone and the target hosted zone. Everything should be the same expect for the SOA and NS records.

Side note: the DNS records can also be exported/imported using the zone file format as well. Documentation for that process starts here: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-creating-import.html

Part 3: Execute the Domain Transfer

Now with the majority of the yak shaving out of the way we execute the actual transfer. From the source account (Alice) send the request to transfer the domain.

req:

aws route53domains transfer-domain-to-another-aws-account \
--profile Alice \
--region us-east-1 \
--account-id REDACTED \
--domain-name example.davvidjeddy.com

res:

{
"OperationId": "aa99ab3c-693e-4885-ba04-3c77c6ffbd51",
"Password": "REDACTED"
}

req

Now using the target account (Bob), accept the transfer.

aws route53domains accept-domain-transfer-from-another-aws-account \
--profile Bob \
--region us-east-1 \
--domain-name "example.davidjeddy.com" \
--password "REDACTED"

res

error: An error occurred (InvalidInput) when calling the AcceptDomainTransferFromAnotherAwsAccount operation: Password is incorrect.

Of course, it can never be easy can it? Nothing ever works the way you expect it the first time.

I tried using the backslash escape character, single quotes, double quotes. Nope, nothing. But, like all problems, time for the RTFM strategy

If you use the CLI command at accept-domain-transfer-from-another-aws-account , use JSON format as input instead of text because otherwise CLI will throw an error from domain transfer input that includes single quotes.

https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-skeleton.html

Ccreate a JSON payload and pass that with the request.

echo '{
"DomainName": "example.davidjeddy.com",
"Password": "REDACTED"
}' > domain_transfer.json

Trying accepting the transfer using a JSON payload…

aws route53domains accept-domain-transfer-from-another-aws-account \
--profile Bob \
--region us-east-1 \
--cli-input-json file://domain_transfer.json

res

{
"OperationId": "482bdaea-8f2b-4e7a-887a-REDACTED"
}

Nice, successfully accepted the transfer. To be sure double check the status of the transfer from both ends (source and target).

Source account (Alice):

req

aws route53domains get-operation-detail \
--profile Alice \
--region us-east-1 \
--operation-id "482bdaea-8f2b-4e7a-887a-REDACTED"

res

{
"OperationId": "482bdaea-8f2b-4e7a-887a-REDACTED",
"Status": "SUCCESSFUL",
"DomainName": "example.davidjeddy.com",
"Type": "INTERNAL_TRANSFER_IN_DOMAIN",
"SubmittedDate": "2022-08-12T19:20:22.004000+02:00"
}

Target account (Bob).

req

aws route53domains get-operation-detail \
--profile Bob \
--region us-east-1 \
--operation-id "aa99ab3c-693e-4885-ba04-REDACTED" \

res

{
"OperationId": "aa99ab3c-693e-4885-ba04-REDACTED",
"Status": "SUCCESSFUL",
"DomainName": "example.davidjeddy.com",
"Type": "INTERNAL_TRANSFER_OUT_DOMAIN",
"SubmittedDate": "2022-08-12T19:20:21.999000+02:00"
}


Nice, only a little bit of trouble handling the transfer password due to it containing special characters.

Part 4: Update the Domain glue records

Now the hosted zone has be replicated, the domain has been transferred, time to glue them together in the target account. This is easy and well documented. The short version is updating the list of nameservers on the Route53 domain record. I did this via the web console due to laziness.

Updating a Route53 domain glue record

Part 5: Confirmation and Cleanup

Now double check the hosted zone records match, wait 2 to 3 days while the new NS records propagate throughout the entire internet and remove the hosted zone from the source (Alice) account.

Wrap Up

In this article we transferred a domain from a source account named Alice to a target account named Bob. Additionally Route53 hosted zone records and the glue records were updated as well. Done correctly end users would experience zero interruption in service of the domain name.

Feel free to leave a comment below about your experience moving domains around accounts / service providers.

References

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.