AWS Route 53: How to migrate a hosted zone from one account to another completely?
You can also use jq ("sed for JSON") to convert the JSON output of list-resource-record-sets
to the JSON input to change-resource-record-sets
:
jq '.ResourceRecordSets
|{"Changes":[.[]
|select(.Type!="SOA")
|select(.Type!="NS")
|{"Action":"CREATE","ResourceRecordSet":.}]}'
This assumes you have already created the new hosted zone and that it is empty except for the SOA
and NS
records, which are therefore removed from the JSON file. (The line breaks are for readability; remove them to use the command.)
This is trivial using the AWS CLI. First, get your hosted zone id:
$ aws route53 list-hosted-zones
{
"HostedZones": [
{
"ResourceRecordSetCount": 15,
"CallerReference": "A5A5A3AF-C239-39FB-DA4C-556BA9FD1767",
"Config": {},
"Id": "/hostedzone/Z1LVCQHJBJUCM5",
"Name": "example.com."
}
]
}
Then export the list of resources for that hosted zone:
$ aws route53 list-resource-record-sets --hosted-zone Z1LVCQHJBJUCM5
This will output a json blob of your records, which is very close to the format you'll need to re-import into the new zone, using the change-resource-record-sets
command. Look through the documentation, examining the output format of list-resource-record-sets
and the input format of change-resource-record-sets
and it'll be clear what you need to do to import the records.
Once you have the records in place in the new zone, update your domain registrar to point to the set of Route53 nameservers for this zone.
I just created a tool for this very problem.
https://github.com/andersjanmyr/route53copy
$ route53copy
Usage: route53copy-linux <source_profile> <dest_profile> <domain>
A more updated answer. This is how I did it without external tools, just aws
and a text editor.
First, according to the CLI docs: "You can't create a hosted zone for a top-level domain (TLD) such as .com" (or .org, .net etc.).
No biggie, go to the new account and create it manually, it's a concise thing:
Now that you have created a Hosted Zone, it's just a matter of fill it with records. So, get the records from the old account into a .json file for comfort:
$ aws route53 list-resource-record-sets --hosted-zone YOURHOSTZONEID --output json --profile account1 > records.json
You can get your YOURHOSTZONEID directly from the web console ("Hosted Zone ID" column in the previous image) or from your terminal: $ aws route53 list-hosted-zones --profile account1
.
This --profile account1
option is a reference to the potentially multiple account configuration, originally stored in ~/.aws folder: files config
and credentials
. If you haven't configured them, you can edit the two files manually (adding all the accounts you want, including IAMs), but I recommend using $ aws configure
explained here.
Now, when you use any aws command with a particular --profile
, it will know what account you want to use.
The JSON we downloaded needs to be "adapted" to the actual JSON structure the change-resource-record-sets
is expecting. For some reason, using the --generate-cli-skeleton
should give you an exemplar to know what structure is expected. Still, in this case, it's different (and therefore wrong), don't know why, from what is expected (which you can find here, first JSON example). This is a reduced and a bit concealed version, but with the right structure:
{
"Comment": "",
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "domain.org.",
"Type": "A",
"TTL": 300,
"ResourceRecords": [
{
"Value": "11.111.111.111"
}
]
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "domain.org.",
"Type": "MX",
"TTL": 300,
"ResourceRecords": [
{
"Value": "20 mx1.domain.com"
},
{
"Value": "10 mx2.domain.com"
},
{
"Value": "50 mx3.domain.com"
}
]
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "domain.org.",
"Type": "NS",
"TTL": 172800,
"ResourceRecords": [
{
"Value": "number.awsdns-28.com."
},
{
"Value": "number.awsdns-23.org."
},
{
"Value": "number.awsdns-31.co.uk."
},
{
"Value": "number.awsdns-49.net."
}
]
}
}
]
}
As you can see, you have to insert each ResourceRecordSets
' JSON from the account1 into each object, starting with "Action"
in the JSON to send to the account2. Then we send it like so:
$ aws route53 change-resource-record-sets --hosted-zone-id Z3IVB20ZV4QU6O --change-batch file://adaptedfile.json --profile account2
Notice that files in aws CLI are referenced with the file:// schema.
Bonus tip: if you encounter errors, you can add a --debug
option that may help you figure out what's wrong.