This Ansible role will deploy a Docker container running the ISC Bind DNS service and configure it to your liking.
The container used is
jonasal/bind
from here.
This repository does not have any dependencies, so just move into your roles/
folder and run the following:
git clone [email protected]:JonasAlfredsson/ansible-role-bind_dns.git bind
If you would like to download any updates for this role in the future, you may use the following command from within the previously cloned folder:
git pull
When the configuration is complete you may then just include this role in your main playbook like this:
- hosts: dns_servers
name: Install Bind DNS server
roles:
- bind
Bind has a ton of configuration possibilities so it is absolutely impossible for me to create a role that covers every conceivable usecase, but I have tried to make the most common ones easy to achieve and some more advanced stuff possible by allowing freestyle text in the variables available.
I like this for reading about what options are available, but even that does not cover everything.
To add some kind of structure to the example configuration I will split it into four different categories.
The settings grouped in the Container options section have more of an impact on the host and the actual Docker container than the Bind program. One setting that probably should be changed is the base directory in which the container will find the configuration files and write its logs:
bind_container_base_dir: "/srv/bind"
Then there is the following setting:
bind_use_host_network: false
which, when set to true
, make the container use the host
network (and thus
ignore anything listed in bind_container_networks
and bind_container_ports
).
This will most likely be necessary in case you want to enable IPv6 support,
but please read this section before you do.
Don't forget to update
bind_container_command
andbind_listen_on_v6
if you do enable IPv6.
Logging is important, and Bind is not very good at it. By default the container
is configured so that Bind tries to load its logging configuration from a file,
but if anything fails during startup it will not output any information. The
only way around this is then to force all log output to stderr
(i.e. the
console) by setting this.
bind_log_force_stderr: true
When you know everything works you may turn this off again and load the proper
configuration from the
named.cong.logging
file. This
resource is pretty good at explaining how the logging works, but important to
know here is that I have defined a default "console" channel which always try
to output to stderr. The severity of that one is controlled with
bind_log_channel_console_severity: "info"
and the obligatory "default" category will have this "console" channel included unless you manually change it to something else.
bind_log_category_default: [ "console" ]
Beyond that you may define your own channels and categories like this
bind_log_channels:
"custom_channel_1":
severity: "warning"
"custom_channel_2":
severity: "debug 1"
print_time: no
print_severity: no
print_category: no
bind_log_categories:
"client":
- "custom_channel_1"
"database":
- "custom_channel_2"
- "console"
Looking in the defaults file, and then in the named.conf.options file, it should be quite easy to see what is going on here.
Unless you try to do something very advanced you can actually get away with
the options
block being pretty sparse. But, as was mentioned at the beginning,
there exists a ton of options here and there is no way to prepare for all
of them. As a workaround for this it is possible to add some "raw" text into
the options file like this.
bind_options_raw: |
custom_option_1 yes;
custom_option_2 {
"list_item";
};
The |
character here allows you to write a multiline text (with empty lines!),
so you just need to make sure that noting is indented less than the first line.
It is in this file where most of the action will take place. Here you define the controls and the zones you intend to serve. To begin with we take a look at the controls setting and how you configure it.
bind_controls:
"name_of_key_1":
inet: '*'
port: '953'
allow: [ 'localhost' ]
secret: "abcdef"
"name_of_key_2":
secret: "ghijkl"
The name needs to be unique, which is why it is used as the key in the map
above. The only thing that is required is the secrets
value, and that may
be created by following these steps.
Of the following two settings you should set the rfc1918
one to false
if
you want your Bind instance to be able to respond with IP addresses that
are in private ranges.
bind_include_default_zones: true
bind_include_rfc1918: true
Then we come to the largest variable in this entire role, as it allows you to configure all your zones from a single location. Any value that does not have a comment after it will default to the value written here.
bind_zones:
"example.com":
type: "primary" # Required
allow_transfer: [ "none" ]
also_notify: []
ttl: "1h"
refresh: "3h"
retry: "1h"
expire: "1w"
neg_cache: "1h"
nameservers: # Must be at least 1 long if "primary"
- "ns0.example.com"
rname: "admin.example.com"
hosts:
"192.168.0.4":
name: "ns0"
cnames: [ "main-computer", "main" ]
"192.168.0.5":
name: "www"
custom_records:
"MX":
- name: ""
data: "10 mail.example.com."
"SRV":
- name: "_http._tcp.example.com."
data: "0 5 80 www.example.com."
"upstream.com":
type: "secondary" # Required
primaries: # Must be present in case of "secondary"
- "10.0.0.4"
raw_options: |
zero-no-soa-ttl yes;
zone-statistics full;
So while I can try to explain all of these settings I think it is easier to just add the files outputted here instead so you can see how each value will be printed.
Also, read the section about
rname
to understand its formatting.
zone "example.com" {
type primary;
file "/var/cache/bind/example.com/soa.conf";
allow-transfer {
none;
};
};
zone "upstream.com" {
type secondary;
file "/var/cache/bind/db.upstream.com.secondary";
primaries {
10.0.0.4;
};
zero-no-soa-ttl yes;
zone-statistics full;
};
$TTL 1h
$ORIGIN example.com.
@ IN SOA ns0.example.com. admin.example.com. (
1658264049 ; serial
3h ; refresh
1h ; retry
1w ; expire
1h ; negative caching TTL
)
@ IN NS ns0.example.com.
ns0 IN A 192.168.0.4
main-computer IN CNAME ns0
main IN CNAME ns0
www IN A 192.168.0.5
IN MX 10 mail.example.com
_http._tcp.example.com. IN SRV 0 5 80 www.example.com.