Dynamic DNS (DDNS) in AWS for internal zones

6 minute read , Dec 27, 2014

The following configuration will resolve the internal (meaning inside VPC) domain queries for encompasshost.com and forward all other queries to the default VPC dns server. This will make possible to have more friendly and meaningful host names like app11.encompasshost.com instead of default one ip-10-122-0-211.ap-southeast-2.compute.internal inside the VPC.

Server Setup

We will use BIND9 as DNS server since it provides the needed functionality.

Installation

On Ubuntu/Debian this is simple as:

root@ip-10-122-0-211:~# aptitude install bind9 dnsutils

BIND9 Configuration

We need to configure the RNDC key file for DDNS authorization, the main named config file and the zone files of course. If the key file config is not generated by default (depends on the bind version installed) we can create one:

root@ip-10-122-0-211:~# rndc-confgen -a -b 128

This will generate just the key clause and write it to keyfile /etc/bind/rndc.key. The key length will be 128 which is default one and may be up to 512 bits.

key "rndc-key" {
    algorithm hmac-md5;
    secret "1KJjYVuDxsJpcmGIJs/0Uw==";
};

Next we put some options we need in the bind config file /etc/bind/named.conf.options:

options {
    directory "/var/cache/bind";
    dnssec-validation no;
    auth-nxdomain no;    # conform to RFC1035
    listen-on-v6 { none; };
    version "get lost";
    allow-transfer { none; };
    allow-query { any; };
    minimal-responses yes;
    forwarders {
        // AWS DNS server for the VPC
        10.122.0.2;
    };
};

and populate the local config file /etc/bind/named.conf.local with our settings and zones where we specify who and how can update our zones and access the DNS server in general:

//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
include "/etc/bind/zones.rfc1918";
 
// logging
logging{
    channel encompasshost_log{
       file "/var/log/named/encompasshost.log" versions 3 size 2m;
       severity info;
       print-severity yes;
       print-time yes;
       print-category yes;
    };
    category default{
      encompasshost_log;
    };
};
 
// ACLs
acl "internals" {
    127.0.0.0/8;
    10.122.0.0/16;
};
 
controls {
    inet 127.0.0.1 allow { "internals"; } keys { "rndc-key"; };
};
 
// Add local zone definitions here.
zone "encompasshost.com" {
    type master;
    file "encompasshost.com.db";
    allow-update { key "rndc-key"; };
    notify yes;
};
 
zone "122.10.in-addr.arpa" {
    type master;
    file "10.122.db";
    allow-update { key "rndc-key"; };
    notify yes;
};
 
include "/etc/bind/rndc.key";

Next we create the master zone file /var/cache/bind/encompasshost.com.db we have referenced in the above setup:

$ORIGIN .
$TTL 259200    ; 3 days
encompasshost.com    IN SOA    ns1.encompasshost.com. root.ns1.encompasshost.com. (
                2012122209 ; serial
                28800      ; refresh (8 hours)
                7200       ; retry (2 hours)
                2419200    ; expire (4 weeks)
                86400      ; minimum (1 day)
                )
            NS    ns1.encompasshost.com.
            A     10.122.0.211
            MX    10 mail.encompasshost.com.
            SPF   "v=spf1 ip4:54.252.148.126 ~all"
$ORIGIN encompasshost.com.
_domainkey       TXT    "t=y\; o=~\;"
amq-db11         A    10.122.1.189
amq11            A    10.122.1.215
amq21            A    10.122.11.29
app11            A    10.122.0.43
app21            A    10.122.10.35
$TTL 30    ; 30 seconds
camel            A    54.206.211.21
                 A    54.206.25.89
$TTL 259200    ; 3 days
db11             A    10.122.2.146
db12             A    10.122.2.132
db21             A    10.122.22.198
gfs11            A    10.122.1.245
gfs21            A    10.122.11.254
gw               A    10.122.0.2
                 TXT    "Network gateway"
mail             A    54.252.148.126
                 TXT    "v=spf1 a -all"
ns1              A    10.122.0.211
$TTL 86400    ; 1 day
somehost         A    10.122.1.250
$TTL 259200    ; 3 days
www              CNAME    encompasshost.com.

and the reverse zone file /var/cache/bind/10.122.db too:

;
; Filename: 10.122.db
;
; Reverse Zone file for 10.122.x.x
;
$TTL 3D
@       IN      SOA     ns1.encompasshost.com. root.ns1.encompasshost.com. (
                        2014122201 ; Serial, todays date + todays serial
                        8H      ; Refresh
                        2H      ; Retry
                        4W      ; Expire
                        1D)     ; Minimum TTL
                IN      NS      ns1.encompasshost.com.
$ORIGIN 0.122.10.in-addr.arpa.
211     IN     PTR     ns1.encompasshost.com.
43      IN     PTR     app11.encompasshost.com.
$ORIGIN 1.122.10.in-addr.arpa.
245     IN     PTR     gfs11.encompasshost.com.
215     IN     PTR     amq11.encompasshost.com.
189     IN     PTR     amq-db11.encompasshost.com.
$ORIGIN 2.122.10.in-addr.arpa.
146     IN     PTR     db11.encompasshost.com.
132     IN     PTR     db12.encompasshost.com.
$ORIGIN 10.122.10.in-addr.arpa.
35      IN     PTR     app21.encompasshost.com.
$ORIGIN 11.122.10.in-addr.arpa.
254     IN     PTR     gfs21.encompasshost.com.
29      IN     PTR     amq21.encompasshost.com.
$ORIGIN 22.122.10.in-addr.arpa.
198     IN     PTR     db21.encompasshost.com.

We also add host name resolution for the DNS server it self in the hosts file /etc/hosts:

10.122.0.211    ns1.encompasshost.com ns1

Create the log dir:

root@ip-10-122-0-211:~# mkdir -p /var/log/named
root@ip-10-122-0-211:~# chown bind\: /var/log/named

Now all is ready to restart the server:

root@ip-10-122-0-211:~# service bind9 restart

DDNS setup

Setting the DNS is not enough. Since everything in AWS is dynamic we also want to dynamically update our zone too. We will use nsupdate tool for that purpose. First we create nsupdate file my-nsupdate.txt:

server 127.0.0.1
zone encompasshost.com
prereq nxdomain somehost2.encompasshost.com
update add somehost2.encompasshost.com. 86400 A 10.122.0.250
show
send

and then run the nsupdate to add a new host record for example:

root@ip-10-122-0-211:~# nsupdate -k /etc/bind/rndc.key -v my-nsupdate.txt
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;encompasshost.com.        IN    SOA
 
;; PREREQUISITE SECTION:
somehost2.encompasshost.com. 0    NONE    ANY
 
;; UPDATE SECTION:
somehost2.encompasshost.com. 86400 IN    A    10.122.0.250

The server log confirms the record being inserted:

23-Dec-2014 10:36:54.086 update-security: info: client 127.0.0.1#56635/key rndc-key: signer "rndc-key" approved
23-Dec-2014 10:36:54.086 update: info: client 127.0.0.1#56635/key rndc-key: updating zone 'encompasshost.com/IN': adding an RR at 'somehost2.encompasshost.com' A

Now if we check for that host resolution:

root@ip-10-122-0-211:~# dig +short somehost2.encompasshost.com
10.122.0.250

but only after issuing:

root@ip-10-122-0-211:~# rndc sync

OR in case that didn’t work:

root@ip-10-122-0-211:~# rndc freeze && rndc thaw

we can see the zone file updated as well. This is due to the DDNS caching so the above is needed only in cases when we want immediate update of the zone file.

Now we can update our reverse zone as well. We create a new file my-reverse-nsupdate.txt:

server 127.0.0.1
zone 122.10.in-addr.arpa
update add 250.0.122.10.in-addr.arpa. 86400 IN PTR somehost2.encompasshost.com.
show
send

and run nsupdate:

root@ip-10-122-0-211:~# nsupdate -k /etc/bind/rndc.key -v my-reverse-nsupdate.txt
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;122.10.in-addr.arpa.        IN    SOA
 
;; UPDATE SECTION:
0.122.10.in-addr.arpa.    86400    IN    PTR    somehost2.encompasshost.com.

The server log should confirm the record being added:

23-Dec-2014 10:43:16.692 update-security: info: client 127.0.0.1#54217/key rndc-key: signer "rndc-key" approved
23-Dec-2014 10:43:16.692 update: info: client 127.0.0.1#54217/key rndc-key: updating zone '122.10.in-addr.arpa/IN': adding an RR at '0.122.10.in-addr.arpa' PTR

To remove records we replace add with delete in the ddns files. In case we want to add/delete multiple records in the same go, the update lines have to be separated by an empty line in the nsupdate file. For example:

server 127.0.0.1
zone 122.10.in-addr.arpa
update delete 250.0.122.10.in-addr.arpa. 86400 IN PTR somehost2.encompasshost.com.
 
update delete 251.0.122.10.in-addr.arpa. 86400 IN PTR somehost3.encompasshost.com.
show
send

As we mentioned before DDNS uses caching. It creates journaling files for the zones:

root@ip-10-122-0-211:~# ls -l /var/cache/bind/*.jnl
total 20
-rw-r--r-- 1 bind bind  802 Dec 23 10:43 10.122.db.jnl
-rw-r--r-- 1 bind bind 1313 Dec 23 10:36 encompasshost.com.db.jnl

and this journal gets flushed to the zone files on regular intervals, 15 minutes by default, except when forced via rndc as shown above.

Worth mentioning here is that once the zone has been put under control of DDNS the zone files should not be updated manually any more.

Client Setup

On the clients we need to introduce our new DNS server and extend the search stanza in the DNS resolver so we can find the hosts by their short name. Since the DNS resolution in VPC hosts is set via DHCP on the primary interface we need to add the following options to the DHCP client setup in /etc/dhcp/dhclient.conf file:

prepend domain-name-servers 10.122.0.211;
append domain-name " encompasshost.com";

After restarting the networking the resolution file /etc/resolv.conf will look like this:

nameserver 10.122.0.211
nameserver 10.122.0.2
search ap-southeast-2.compute.internal encompasshost.com

which will enable the hosts to use our DNS server.

Testing

We can test the dns resolution from one of the servers in the VPC:

root@ip-10-122-0-43:~# dig +short @10.122.0.211 app21.encompasshost.com
10.122.10.35

and the reverse resolution as well:

root@ip-10-122-0-43:~# dig +short @10.122.0.211 -x 10.122.10.35
app21.encompasshost.com.

We can also confirm that the resolution of the default ap-southeast-2.compute.internal domain is still working:

root@ip-10-122-0-43:~# dig +short @10.122.0.211 ip-10-122-11-29.ap-southeast-2.compute.internal
10.122.11.29
 
root@ip-10-122-0-43:~# dig +short @10.122.0.211 -x 10.122.11.29
amq21.encompasshost.com.
 
root@ip-10-122-0-43:~# host ip-10-122-11-29.ap-southeast-2.compute.internal
ip-10-122-11-29.ap-southeast-2.compute.internal has address 10.122.11.29
 
root@ip-10-122-0-43:~# host ip-10-122-11-29
ip-10-122-11-29.ap-southeast-2.compute.internal has address 10.122.11.29

All was left now is package all this into Ansible role for our automated deployments.

Leave a Comment