A while ago one of the major problems people faced to use Amazon EC2 into production environments was the dynamic state of the instances IPs. Every time one instance was started it was getting a new, dynamic IP. This has been addressed with the introduction of Amazon Elastic IP Addresses, but even when using this, the private IPs are still dynamic and most of the time people will want to communicate between several instances on the private allocated IPs and not on the public ones. This article will show how you can easily automate the process to update DNS hostnames for your EC2 instances, by adding to the AMI’s the logic for this. I will use for this a master DNS server running bind9, but this can be adapted to any other DNS server.
How to get the needed information (IPs, hostnames, etc.)
Amazon api provides us all the needed information. Any EC2 instance can get a lot of information about itself just by querying a web server using a REST-like API. Here is how we can get all the available metadata items:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
We have a direct interest in the public-ipv4 and local-ipv4 variables, but as we can see Amazon is providing many other useful information that can be used inside the instance for various purposes. For more details checkout the amazon docs.
Public and private IPs
This means that for getting the public and private ips we only have to make two calls like this:
We need a way to identify from inside the instance what hostname this should be configured. There are probably several ways to do this, but the most common is to specify this when the instance is started using the –user-data option of the ec2-run-instances command (or the short form -d). This will pass the custom data and make it available to the instance.
You will probably want to customize this based on your needs. Myself I assumed that I will use the same domain for all instances and I need to pass only the hostname. Since I don’t need any other parameters to the machine I can just do this:
If you use more user data, then you will probably use it like “hostname=myhostname
Now making a http request like this will give us the hostname this instance should have:
DNS Server configuration
Now that we have available inside the EC2 instance all the needed information, we need a way to allow the instance to update the DNS server. As I mentioned before, I will use for this a bind9 server, but this can by any other DNS server that allows this action to be scripted somehow (either using some api calls, or any way to use dynamic DNS update). For bind9 we will use the nsupdate utility to update the DNS server securely using the dnssec key mechanism.
Personally I don’t use the full domain for this, but delegate two subdomains (to the same nameservers) like this:
1 2 3 4 5
and allow update access only to those zones. Of course if you prefer that you can give direct access to your full domain zone.
Generate a key using the dnssec-keygen utility like this:
and this will create two files like this:
Using the information from the public key add to your dns server configuration the key:
1 2 3 4
where secret is the value from the public key, that in my example looks like this:
Finally we need to allow update access for the key:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bind will need to be restarted after making these changes.
Using nsupdate to update the hostname
Next we will need to upload the key we created on the EC2 image (later we will save it inside the AMI once all runs well) and test to see if it is working properly.
1 2 3 4 5 6 7 8
If this is working properly we can move on and put all this toghether in a script that will be running at the instance start time. If not, go back and see in your dns server logs if there are any issues why this is not working.
Finally automation :-)
Now we just have to put all the pieces together and using a simple script like this will do the job:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
You will probably want to run this at boot time either from rc.local or creating an initscript for it. I put all these EC2 related stuff under /usr/local/ec2 and in this case I just call it from rc.local with a line like this:
If all runs as you wanted you will probably want to save your AMI to include the script that will automatically update the dns hostname at instance boot time.
Hopefully you found this article interesting and it will be a starting point to create your own dns update script based on your needs.