Here's a handy way to automatically update an A-Record in Amazon Route 53 whenever an EC2 instance changes IP address.
Scenario: You have a domain...
For further actions, you may consider blocking this person and/or reporting abuse
Nice idea, sounds very useful! But I'm still stuck with one question.
Doesn't this introduce a major security risk ? When your ec2 would get compromised, the attacker has the permissions to update your hosted zone. Because of this, he/she could potentially point your domain to their site.
Or I might be missing something, not quite sure.
I love your phraseology: "When your ec2 would get compromised", rather than "If". With a pessimistic attitude like that, you'd make a good security professional! (We're hiring!)
You are correct — it is always important to grant only the permissions that are required, lest the credentials accidentally, or intentionally, are used for other purposes. The above policy limits the potential changes that a specific Hosted Zone. I'm not sure whether it is possible to lock-down further to a specific Record Set.
For the really security-minded, you could have the instance call an AWS Lambda function that makes the call on its behalf. This way, the instance would not have any permissions to change the Route 53 information. The Lambda function would require such permission, but Lambda could be considered more "locked-down" than an Amazon EC2 instance.
You should be able to use CloudWatch Events to trigger the Lambda on EC2 instance state-changes. This way you don't even need to grant permissions to Lambda. Something like aws.amazon.com/premiumsupport/know...
Thank you for clearing that up! The lambda could also do some validation when updating the record set, so that the record could only point to targets that you own yourself.
In case anybody else is concerned about this, AWS now supports resource record set permissions with Route53, so you can dial in the EC2 IAM Role policy to allow route53:ChangeResourceRecordSets only on a given record set. Back when this article was originally written, it wasn't possible:
Announcement: aws.amazon.com/about-aws/whats-new...
Examples: docs.aws.amazon.com/Route53/latest...
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "route53:ChangeResourceRecordSets",
"Resource": "arn:aws:route53:::hostedzone/Z11111112222222333333",
"Condition": {
"ForAllValues:StringEquals":{
"route53:ChangeResourceRecordSetsNormalizedRecordNames": ["acme.example.com"]
}
}
}
]
}
Great article.
I just tried it out, and there was just one little detail that I was banging my head against for the last hour: the shell script needs to start with a shebang like:
#!/bin/bash
.Until, I made this change to the script, it was not executing properly on each boot, and I was constantly running into this error in
/var/log/cloud-init.log
:I got the hint that the shebang line was needed from this:
that I found over here. Your script is working great now!
I'd also like to point out that you might want to change this line:
"Resource": "arn:aws:route53:::hostedzone/Z3NAOAAAA11BB22"
to something like
"Resource": "arn:aws:route53:::hostedzone/<YOUR_ROUTE53_ZONE_ID_here>"
. Just in case someone is not alert enough to modify the literal ZoneId in their IAM policy, when copy+pasting from the article :)Overall, super-useful post. Thank you!
Oops! Sorry for causing you that problem. I've now updated the post.
Is there any other setting required for the the script to run on boot? I followed exactly same steps mentioned in this article but the script doesn't fire up, no log entry in the cloud-init.log as well. I'm able to execute the script manually and the record set is getting updated.
Nevermind I managed to fix it, the script had to be made executable and also had to update
/etc/cloud/cloud.cfg
file's- scripts-per-boot
to- [scripts-per-boot, always]
It worked for me in 2024 by simply putting the script in .../per-boot/ like the article mentioned
Hi guys, took me a while but i was able to create a batch script to have this done for windows server.
Hope it helps.
For posterity, another version of the script that works with Amazon Linux 2023 using
ec2-metadata
instead of the curl commands.You can even use
ec2-metadata
to extract the tags, but it is ugly (see above).Then I installed
cronie
(crontab) and just ran the script on reboot with cron:@reboot /home/ec2-user/bin/update-dns-on-boot.sh
Update: The method for running scripts on "every boot" appears to have changed with Amazon Linux 2. You might need to find the newer method for starting the script on every boot. (See other comments too.)
Hi,
I followed your instructions (I guess...) and I am getting the following error :
An error occurred (AccessDenied) when calling the ChangeResourceRecordSets operation: User: arn:aws:sts::6XXXXXXXX118:assumed-role/UpdateRoute53/i-XXXXXXXXX is not authorized to perform: route53:ChangeResourceRecordSets on resource: arn:aws:route53:::hostedzone/XXXXXXXX2I
I add the policy to the EC2 instance and the user (mine respectively) but I still get this error. Do you have an idea of what I could have done wrong ?
thanks in advance,
Olivier
That's odd!
The IAM policy is specifically granting permission to call ChangeResourceRecordSets on the Hosted Zone. All I can suggest is that you check that you have put the correct HOSTED_ZONE_ID in the IAM Policy. It should start with a 'Z'.
Thanks John, as usual the problem was between the chair and the keyboard. This was exactly my mistake.
For anyone trying to use this tutorial after 2023.
The bash script will fail because the api for retrieving meta-data has changed. You need to first fetch a token and pass it as a header to subsequent api calls.
Here's the working script :
Great article! I love the way you used tags similar to ENV variables.
Thank you for taking time to share!
Great Article,
I just tried this and it work. The explanation is quite simple to understand but I am having a bit difficulty understanding the script.
Can someone help?