Reminder: this blog reflects my opinions and thoughts, and not those of my employer, Chef Software, Inc.
Like any good sysadmin, I have my own domain for email and other purposes. I actually have had a couple, but this post is about my current one. I originally set it up through Google Apps a couple years ago, including registering the new domain with Google Apps’ default registrar, GoDaddy. For the most part, it was pretty simple and painless to set up, including private registration via Domains by Proxy. Yay!
However, as I automated more components of my home network with Chef, I found the lack of API driven DNS rather frustrating. At last count, I had 15 distinct networked devices, counting all the computers, consoles, mobile devices, etc. This does not count the virtual machines that I manage as a part of my daily job in doing Chef cookbook development and testing, which should all have their own DNS entries, since I’ll access them over the network, and remembering IPs is ridiculous.
Internal DNS Server
I use DJB’s tinydns as my DNS server,
and it is automated with the
Opscode Chef Cookbook.
The first incarnation of this setup was a single monolithic template
file containing all the entries in my local network zone, delivered by
djbdns::tinydns-internal recipe, like so:
1 2 3 4 5
This was great, and simple to manage for this single purpose setup. At
some point, I wrote cookbooks for
powerdns, as I was
evaluating whether one or the other might be easier to modularize. In
the process, I created a data bag of all my DNS entries that I could
step through in templates, so I could use the same data without caring
which software was going to consume it. In the end, I extended the
djbdns cookbook with a lightweight resource and provider, and added
usage to the
djbdns::tinydns-internal recipe like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
The data bag itself looks something like this:
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
I am pretty pleased with this approach in that this data can be used no matter what DNS resolver software I choose. While this is great for the more static part of my network, as I mentioned I do have some dynamic usage where I create new virtual machines, and I really want them to register themselves in DNS automatically.
A few months ago I decided to switch over to DNSimple. The service was compelling over the alternatives for a few reasons:
- Low cost ($3/mo) for my size of account.
- Very simple interface
- API for managing records (!)
- Reputation for great service
However, for various reasons I procrastinated the switchover. After all, my existing solution worked ok for my purposes. Then after seeing GoDaddy show up on the SOPA supporters list, and being one a contributing author to the legislation(*), I decided that was the last straw and I busted a move to finish the switch.
Honestly, from the DNSimple side, it couldn’t have been a better experience. They have one-click services for managing DNS records for a variety of common services – including Google Apps! It took some time and hassle to move my domain out of GoDaddy, since their interface is rather clunky, and I had to unprotect things through Domains by Proxy to make the move, but after a couple hours everything was fine. DNSimple has some tips for migrating, no matter who your current registrar is.
Now for the truly fun part!
Automated DNS with Chef
Using the dnsimple cookbook is very straightforward. You create an “A” record like this:
1 2 3 4 5 6 7 8 9 10
Yes, that is a private network IP, and yes it is going to be registered in public DNS. It really doesn’t matter that much in my (and others’) opinion. Especially given that zomg, I just created a DNS entry with Chef!
By default, the cookbook does assume, and use, node attributes for storing the username and password. This can be set by a role, but it means that all nodes will have the data. For my use, I decided to put these values in a data bag, and because they are sensitive, I used an encrypted data bag. I also wanted to reuse the data bag from my earlier DNS example, so I wrote a recipe like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
I put that recipe in my “dnsserver” role, ran Chef, and boom, all my DNS entries are updated on systems I don’t have to manage, and all around the world.
% host cask.int.example.com 184.108.40.206 Using domain server: Name: 220.127.116.11 Address: 18.104.22.168#53 Aliases: cask.int.example.com has address 10.10.20.20
What a wonderful redundant distributed key value store :–).
Note that the
encrypted_data_bag_item method used in the recipe is in a cookbook
library. I wrote about that in an
earlier blog post.
It is pretty simple:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
While conveniently reusing the data I already had for my DNS entries,
dnsimple_record provider does take about a second on my internet
connection for each entry to check if it’s there. This makes the DNS
server’s Chef client run take over a minute, where it used to be less
than 12 seconds. Many of the entries that are in the DNS data bag are
on systems that can add their own records, and will soon once I
refactor things a bit.
A number of the entries in the DNS data bag are CNAMEs for services that run on my home LAN server. I have internal services like Netatalk/Time Machine, Samba, or Munin. I also have external services like OpenVPN, SSH and Teamspeak. I’ll add DNSimple records for each of these so the recipes can automatically register new DNS entries, eliminating a step in bringing up a new service.
Open Source is Awesome
Chef is open source, of course, as is the dnsimple cookbook that I’m using. While working with the cookbook as describe above over the last couple days, I made some improvements and I sent a pull request, which has been merged and released. Thanks Darrin!
If you use Chef and are looking for an API driven way to manage DNS
entries for your systems, I strongly recommend DNSimple as a provider,
dnsimple cookbook to tie it all together.
(*) This isn’t a political-blog-soap-box, but this really was the final motivator.