Update Route 53 dynamically¶
Route 53 is the DNS service on Amazon Web Services. It does everything from domain registration to the hosting and management of domain names.
What problem are we trying to solve?¶
Before we talk about Route 53, let's explore a number of challenges you may have when designing workloads on AWS. One issue I face from time to time is the ability to reach workloads that may run in a temporary space. Say for example, I spin up an EC2 instance with a public IP address. When that instance is shut down, and started up again, its IP address will change. There are a few ways to combat this problem, for example:
- Allocate a fixed IP address (at a cost of course)
- Create a load balancer and attach the EC2 instance in the ELB's target group (again at a cost)
- Use Route 53
How do we use Route 53?¶
Route 53 is the DNS service. Assuming you have your domain's hosted zone in your account, you can create the following design.
- An EC2 instance boots up
- Upon startup, the instance registers its public IP address with Route 53
- Within a few minutes, the DNS name points to the public IP address, and your service becomes available.
- Upon a server crash, or the reinitialisation of the instance, a new public IP address will be issued, and the DNS will be repointed to the instance.
How do we do this?¶
First of all, you need two pieces of information.
- The DNS name that this server will utilise
- The hosted zone ID for the domain (found in Route 53)
Next, it is assumed that your EC2 instance is using an Instance Profile. An instance profile allows your instance to gain access to AWS resources without the need to physically log on. If you get the urge to simply use an AWS Access Key, don't. Instance profiles is what you should be using.
Having the instance profile is one thing, you also need to make sure that the profile has a policy attached to update the Route 53 record. Add an inline policy with the following defintion. Do remember to update the hosted zone id with the hosted zone from your account.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [ "route53:ChangeResourceRecordSets" ],
"Resource": [ "arn:aws:route53:::hostedzone/Z000000000000000000000" ]
}
]
}
- Use the UserData feature when starting the server for the first time
- Edit the
/etc/rc.d/rc.local
file on the instance to ensure the script is executed everytime the server boots up.
Add some code¶
The following code example can be inserted on your server to automatically update the Route 53 record to that of the public IP address of the server.
- Be sure to update the hosted zone ID
- Update the Record name as well
- Update any other attribute as required.
The TTL (time-to-live) value may require some adjustment. Be careful not to make this value too big, as it may result in the service being unavailable for that time before the DNS server will be queried for the updated address.
aws route53 change-resource-record-sets \
--hosted-zone-id HOSTEDZONEID \
--change-batch '{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "server.example.com.",
"Type": "A",
"TTL": 60,
"ResourceRecords": [
{
"Value": "$(curl -s http://checkip.amazonaws.com)"
}
]
}
}
]
}'
Is this for EC2 only?¶
Not at all! You can use the code on Fargate too!
What can go wrong?¶
While the code does serve a purpose, it is not fool proof. If for example you spin up multiple instances, the last one to start up will take the DNS entry. You may need to adust the code to interrogate EC2 for all other running instances, and add multiple IP addresses. That's a little outside the scope of what we're doing here.
From a security perspective, the EC2 instance will now have access to update DNS entries. If for whatever reason, the EC2 instance is compromised, the attacker will be able to point any DNS entry in the hosted zone to another IP address. To mitigate this, you could do the following:
- Create a Lambda function to perform the DNS update on behalf of the EC2 instance, thus avoiding the EC2 instance from having direct access to update any Route 53 record.
- Have a separate hosted zone just for the automated records, and keep all other production DNS entries in its own zone.