Configuring BIND 9 to forward to Consul

Consul is one of those services which has many features, including service discovery through its catalog, configuration storage through its key-value store, and also it acts as a normal DNS service if queried on the right port.

Consul by default listens on port 8600 for DNS queries, and you can issue a normal dig command to query it, so if we have a service registered with the following json:

{
  "Name": "sample-service",
  "Address": "10.0.10.10",
  "Port": 80,
  "Tags": []
}

Then we can issue the following dig query to get a response (assuming 10.0.10.1 is the Consul service):

dig @10.0.10.1 -p 8600 sample-service.service.consul. ANY  

This should return something similar to:

; <<>> DiG 9.10.3-P4-Ubuntu <<>> @10.0.10.1 -p 8600 sample-service.service.consul. ANY
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64305
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;sample-service.service.consul.    IN  ANY

;; ANSWER SECTION:
sample-service.service.consul. 0    IN  A   10.0.10.10

;; Query time: 2 msec
;; SERVER: 10.0.10.1#8600(192.168.1.15)
;; WHEN: Fri Mar 03 22:45:31 GMT 2017
;; MSG SIZE  rcvd: 62

What this means is that you can use standard DNS queries to discover your services, so long as you use standard ports for them (as ports arent returned in DNS).

Heres how to configure BIND 9 to forward all queries for the consul. zone.

Firstly, you need to add the zone:

zone "consul" {  
        type forward;
        forwarders {
                10.0.10.1 port 8600;
                };
        };

Make sure that the above zone is loaded - there are a number of ways in which BIND configurations are laid out, so just follow the convention of another zone file.

Then you need to allow recursion, so in the options configuration block, add the following:

recursion yes;  
allow-query { any; };  

You also need to ensure that dnssec-validation is set to false, otherwise Consul lookups fail, so either add the following to the options configuration block, or if it already exists, alter it:

dnssec-validation false;  

Now restart BIND and you should be able to query the BIND server for consul services:

$ host sample-service.service.consul

Using domain server:  
Name: 10.0.10.99  
Address: 10.0.10.99#53  
Aliases:

sample-service.service.consul has address 10.0.10.10

And thats it.

Sidenote: you can also setup Consul to serve multiple datacenters, with the default being DC1 - if you don't add multiple datacenters, then you don't have to include it in the query, but the following does indeed work just the same:

$ host sample-service.service.dc1.consul

Using domain server:  
Name: 10.0.10.99  
Address: 10.0.10.99#53  
Aliases:

sample-service.service.dc1.consul has address 10.0.10.10

Note the service.dc1.consul rather than simply service.consul.

This way, you can have the same service registered in multiple datacenters and query each one for a different result. Handy if you need to scale to that level.