Recently I had a need for my AWS instances to dynamically update CNAME records each time they started. You’ll only get a dedicated IP if you purchase an Elastic IP, and then, only 5 per account unless you reach out to Amazon for more. Knowing that I’m both cheap and lazy, I wanted something that would be free, as well as, automatic. I found quite a few blogs and articles that were a big help, but no one ‘put it all together’ for me. After about 6 hours I’ve got a fully working solution, but please feel free to comment on where it can be improved.
This article makes the following assumptions: Ubuntu 14.04 LTS is being used as instance OS, External DNS domain is public, and hosted on Route 53.
I’m neither an AWS nor Linux daily user, so if you see something that could be improved, please do let me know.
Create AWS User, Group, and Policy for Dynamic DNS
- From the main AWS menu select “Route 53”
- Click “Hosted Zones” in the left hand column
- Click “Create Hosted Zone”
- Enter the Domain Name that will be updated by Servers, this can be a subdomain if desired.
- Type: Public Hosted Zone
- Click “Create”
- Once created, note the zone ID for later.
- From the main AWS menu select “Identity & Access Management”.
- Click “Policies” in the left hand pane
- Click “Get Started”
- Click “Create Policy”
- Click “Select” next to “Create Your Own Policy”
- Enter the following:
- Policy Name: change-dns-records
- Description: Allow Servers to update their own CNAME Records each time they reboot.
- Policy Document:
12345678910111213141516171819202122232425{"Version": "2012-10-17","Statement":[{"Action":["route53:ChangeResourceRecordSets","route53:GetHostedZone","route53:ListResourceRecordSets"],"Effect":"Allow","Resource":["arn:aws:route53:::hostedzone/<Zone ID>"]},{"Action":["route53:ListHostedZones"],"Effect":"Allow","Resource":["*"]}]} - NOTE: Replace <Zone ID> with the zone ID of the DNS zone the server needs to update.
- Click “Create Policy”
- Click “Groups” in the left hand pane
- Click “Create New Group”
- Name the group “DNS_Editors”, click “Next Step”
- Select the group policy “change-dns-records” and click “Next Step”
- Click “Create Group”
- Click “Users” in the left hand pane
- Click “Create New Users”
- In the “Enter User Names” box enter “dns-editor”
- Click “Create”
- Click “Show User Security Credentials”, note both the Access Key ID and Secret Access Key.
- Click “Close”
- Select the newly created user
- Click “Add User to Groups”
- Select “DNS_Editors” and then click “Add to Groups”
Install and configure CLI53
- Grab the URL for the most recent version from here: https://github.com/barnybug/cli53/releases/latest Make sure to download the proper version (I’m using AMD64)
- Login to Ubuntu instance and perform the following commands (Download cli53, move to /usr/local/bin, change permissions, create a sybolic link in /usr/bin, create route53 config file, and secure it):
123456789101112wget [url path]sudo mv cli53-linux-amd64 /usr/local/bin/cli53sudo chmod +x /usr/local/bin/cli53sudo chown root:root /usr/local/bin/cli53sudo ln -s /usr/local/bin/cli53 /usr/bin/cli53sudo mkdir /etc/route53sudo chmod 700 /etc/route53sudo touch /etc/route53/configsudo chmod 600 /etc/route53/config - Edit the
/etc/route53/config
file and enter the following:
1234AWS_ACCESS_KEY_ID="<dns-editor's access key ID>"AWS_SECRET_ACCESS_KEY="<dns-editor's secret access key>"ZONE="YourDomain.com"TTL="600" - NOTE: Replace <dns-editor’s access key ID> and <dns-editor’s secret access key> with appropriate values from the dns-editor user. Update YourDomain.com to match either your top level, or a subdomain of one of your domains.
- Next, create a file called
/usr/sbin/update-route53-dns.sh
Enter the following into the file:
123456789101112131415161718192021#!/bin/sh# Make sure only root can run our scriptif [ "$(id -u)" != "0" ]; thenecho "This script must be run as root" 1>&2exit 1fi# Load configuration. /etc/route53/config# Export access key ID and secret for cli53export AWS_ACCESS_KEY_IDexport AWS_SECRET_ACCESS_KEY# Use command line to get and public hostnamePUBLIC_HOSTNAME=$(ec2metadata | grep 'public-hostname:' | cut -d ' ' -f 2).# Delete the old record if it exists, and then create a new one.cli53 rrdelete $ZONE [Client_URL_ShortName] CNAMEcli53 rrcreate $ZONE "[Client_URL_ShortName] $TTL CNAME $PUBLIC_HOSTNAME" - NOTE: replace [Client_URL_ShortName] in the above text with whatever you want to CNAME to be, I use the hostname of the server, but you could use anything (www. testing. mail. ) etc.
- NOTE: it should not be necessary to have to delete the record and then re-create it, the –replace flag should be able to do that in a single command, however I could not get it to work in cli53 build 6.5.0, which is what was used here. I had to delete the existing CNAME and then re-create it. I also noticed that it is case sensitive, and always created as lower case, so in your delete command you need to make sure you are specifying the record to delete in all lowercase.
- NOTE: in some ami distributions ec2metadata needs to be replaced with ec2-metadata
- Lastly we need to add the script to the logon scripts that run during boot, enter the following commands:
12345sudo ln -s /usr/sbin/update-route53-dns.sh /etc/init.d/update-route53-dns.shsudo chmod 755 /etc/init.d/update-route53-dns.shsudo ln -s /etc/init.d/update-route53-dns.sh /etc/rc2.d/S99update-route53-dns.sh - Reboot instance and verify that it’s created a CNAME for itself.