17 KiB
bind9
A feature-complete ansible role for installing and configuring bind9. The purpose of this role is to fully template out the entire official bind9 configuration file format.
What the role does:
- Fully configures named.conf
- Checks that the config is valid
- Loads the config into bind
What the role does not do:
- Manage your zones and records
- Maintain every aspect of bind (rndc config, etc)
- Auto-generate and manage your secrets
Bugs
Or, as I call them "happy accidents".
- If you need a variable to be 0 or null, you need to define it as
var: '0'orvar: 'null', otherwise jinja will assume you want it to be empty/null. Normal integers would be defined asvar: 1, letting jinja type it as an integer. - If a named configuration option has the name 'key' or 'keys', it will be referenced as 'keyname' or 'keylist' respectively. key/keys are reserved values in most languages.
Configuration Grammar
The bind9 role tries to replicate the official ISC bind9 configuration format as close as possible, only re-implementing them in YAML format. This means that for the most part, section names are the same as in named.conf but kebab-case ('var-name') is replaced with snake_case ('var_name') If you are missing some statements in your resulting config, it is most likely because of this.
The main configuration variable used are a series of bind_*_config variables (See [Role Variables]) that have the following syntax
Every config starts by defining the file name. Each file can contain any amount of top-level statements, as permitted by named.conf
bind9_host_config:
- name: FILENAME # The filename of your desired config file.
# You also need to specify a corresponding `include:` for the file
SECTION_NAME: # The section name of the bind config you want to define.
# Can be 'acl', 'options', 'zone', etc.
# See: https://bind9.readthedocs.io/en/v9_18_4/reference.html#configuration-file-grammar
SECTION_2_NAME: # Every file can have as many sections as needed. Generally, try to keep
# all definitions and references together in a file.
Any option that can be defined multiple times in a named.conf, must be defined as a list
bind9_host_config:
- name: named.conf.local
acl:
- name: ELEMENT_NAME
addresses:
- 127.0.0.1
- 127.0.0.2
- name: ELEMENT_2_NAME
addresses:
- 127.0.0.3
Simple options are defined just as that.
SIMPLE_OPTION: string, boolean or integer value
Some options have several optional parameters. For those, a somewhat flexible configuration format has been created
IP_PORT_DSCP_OPTION: # Any option that is defined as:
# <option> [ port <port> ] [ dscp <dscp> ] { <address> [ port <port> ] [ dscp <dscp> ]; ... }
# has a few optional syntaxes
# Example 1: Simple address list
- ADDRESS1
- ADDRESS2
# Example 2: To define source port/dscp, use 'addresses' sub-element
[ port: PORT ]
[ dscp: DSCP ]
addresses:
- ADDRESS1
- ADDRESS2
- 127.0.0.1
# Example 3: To define target port/dscp, use 'addresses' as a list of dicts
addresses:
- address: ADDRESS
[ port: PORT ]
[ dscp: DSCP ]
- address: 127.0.0.1
port: 53
- address: 127.0.0.1
dscp: 42
- address: 127.0.0.1
port: 5353
dscp: 42
# Example 4: The various formats can be mixed and matched within the main element
- ADDRESS1
- address: ADDRESS2
port: PORT
Role Variables
bind configuration is set through the various bind9_*_config parameters. These are, in order of precedence:
- bind9_default_config
- bind9_group_config
- bind9_leaf_config
- bind9_host_config
All these configuration parameters are merged in a way where each successing config supercedes the previous one at a config-file level. To illustrate:
bind9_default_config:
- name: named.conf.options
options:
recursion: true
bind9_group_config:
- name: named.conf.options
options:
recursion: false
notify: primary-only
- name: named.conf.local
zone:
- name: "."
type: mirror
bind9_leaf_config:
- name: named.conf.local
zone:
- name: "."
type: hint
file: /etc/share/dns/root.hints
The resulting precedence and overwriting of variables will result in the following bind9_config passed to the configuration generator:
bind9_config:
- name: named.conf.options
options:
recursion: false
- name: named.conf.local
zone:
- name: "."
type: hint
file: /etc/share/dns/root.hints
The named.conf.options block in bind9_default_config got completely overwritten by the bind9_group_config, and the bind9_leaf_config completely overwrote named.conf.local, however, named.conf.options was left intact after merging with bind9_leaf_config.
Dependencies
No dependencies
Example Playbook
Simple sample config of a recursive BIND server that allows your localnetwork to resolve addresses via
- hosts: servers
roles:
- bind9
vars:
bind9_host_config:
- name: named.conf.local
acl:
- name: mylan
addresses:
- 10.0.0.0/8
- name: named.conf.options
options:
forwarders:
- 1.1.1.1
allow-query:
- mylan
allow-recursion:
- mylan
License
BSD
Author Information
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
options:
forwarders:
- 1.1.1.1
- 1.0.0.1
fetches_per_server: 200 fail
prefetch: 4 10
version: none
hostname: l33t.h4x0r
avoid_v4_udp_ports:
- "range 5132 5232"
- "range 1337 31337"
servfail_ttl: 0
allow_notify:
- 10.0.0.0/8
allow_query:
- "!10.0.2.1"
- 0/0
blackhole:
- 192.168.0.0/16
allow_recursion: []
empty_server: "empty.server.string"
dns64_server: "server.name"
dns64_contact: "dak.keepit.com"
directory: "{{ bind9_cachedir }}"
key_directory: "{{ bind9_cachedir }}/keys"
statistics_file: "{{ bind9_cachedir }}/named.stats"
rrset_order:
- type: A
name: foo.isc.org
order: random
- type: AAAA
name: foo.isc.org
order: cyclic
- name: bar.isc.org
order: random
- name: "*.bar.isc.org"
order: random
- name: "*.baz.isc.org"
order: cyclic
response_policy:
zones:
- zone: smorg.bop
max_policy_ttl: 30S
min_update_interval: 30S
policy: disabled
add_soa: true
log: true
recursive_only: false
nsip_enable: true
nsdname_enable: true
max_policy_ttl: 30S
min_update_interval: 30S
min_ns_dots: 2
add_soa: false
break_dnssec: false
nsip_wait_recurse: true
nsdname_wait_recurse: true
qname_wait_recurse: true
recursive_only: true
nsip_enable: true
nsdname_enable: true
dnsrps_enable: false
dnsrps_options:
- simple
- item
- list
response_padding:
block_size: 4096
addresses:
- 0/0
rate_limit:
all_per_second: 0
errors_per_second: 0
responses_per_second: 0
referrals_per_second: 0
nodata_per_second: 0
nxdomains_per_second: 0
ipv4_prefix_length: 24
ipv6_prefix_length: 54
max_table_size: 20000
min_table_size: 500
qps_scale: 250
slip: 2
window: 15
log_only: true
exempt_clients:
- 192.168.0.1
- 10.20.30.40
query_source_v6:
address: "*"
port: "*"
dscp: 42
parental_source_v6:
address: "*"
port: "*"
dscp: 42
notify_source_v6:
address: "*"
notify_source:
address: "*"
listen_on:
- port: 53
addresses:
- 0.0.0.0
- port: 5353
dscp: 42
addresses:
- 0.0.0.0
- 127.0.0.1
listen_on_v6:
- port: 5353
dscp: 42
addresses:
- "::"
- "de:ad::be:ef"
dialup: false
minimal_responses: true
zone_statistics: full
ixfr_from_differences: master
dual_stack_servers:
port: 4492
addresses:
- address: hostname.com
port: 4421
dscp: 42
- address: 10.128.128.182
- address: de:ad::be:ef
dnstap:
- type: auth
- type: client
log: response
- type: resolver
log: query
dnstap_output:
output_type: file
output_file: /tmp/dnstap
size: 10M
versions: 200
suffix: increment
- name: named.conf.local
acl:
localstuff:
- 10.0.0.0/8
- 192.168.0.0/16
- 172.16.0.0/12
external:
- 185.181.220.77
- "!0.0.0.0/0"
controls:
- type: inet
address: 127.0.0.1
port: 533
allow:
- 127.0.0.0/8
- "!127.13.37.1"
readonly: false
- type: inet
address: 10.20.30.40
allow:
- 100.0.0.0/8
view:
- name: recursive-view
match_clients:
- localstuff
match_destinations:
- remote
match-recursive-only: true
options:
transfer_source:
address: 0.0.0.0
port: '*'
dscp: 42
allow_recursion:
- localstuff
zones:
- name: google.com
type: forward
forward: only
forwarders:
- 1.1.1.1
- 1.0.0.1
dnssec_policy:
- name: mypolicy
keylist:
- role: ksk
key_directory: true
lifetime: unlimited
algorithm: rsasha256
keysize: 2048
- role: zsk
lifetime: P30D
algorithm: 8
- role: csk
lifetime: P6MT12H3M15S
algorithm: ecdsa256
max_zone_ttl: P4D
parent_ds_ttl: P14D
nsec3param:
iterations: '0'
optout: false
salt_length: '0'
dyndb:
- name: sample
driver: example.so
parameters:
- example.nil. arpa.
- example2.nil. arpa.
http:
- name: dohconf
endpoints:
- /dns-query
- /dns
- /query
listener_clients: 4
streams_per_connection: 1024
keylist:
- name: certbot.
algorithm: hmac-sha512
secret: "agyMWst4ZcbhGKqGuR6Pjgz1KJSHdcM0s5tz06n+ZxpfZYVWP67E2cr7Mru+HQRLl7HEBE5Zl4vS3S+SA4kXrA=="
- name: certbot2.
algorithm: hmac-sha512
secret: "agyMWst4ZcbhGKqGuR6Pjgz1KJSHdcM0s5tz06n+ZxpfZYVWP67E2cr7Mru+HQRLl7HEBE5Zl4vS3S+SA4kXrA=="
logging:
categories:
- name: default
channels:
- default_syslog
- default_debug
- tv2
- dr1
- name: unmatched
channels:
- tv3
channels:
- name: tv2
buffered: true
file:
name: /var/log/named.log
versions: 7
size: 20m
suffix: increment
print_category: false
print_severity: false
print_time: iso8601-utc
severity: info
- name: tv3
'null': true
- name: dr1
syslog: daemon
- name: kanalkobenhavn
stderr: true
severity: debug 3
parental_agents:
- name: parents
port: 53353
dscp: 42
addresses:
- address: 10.20.30.40
port: 53
key: certbot.
- address: 20.30.40.50
port: 53
- address: 30.40.50.60
key: certbot2.
- address: 40.50.60.70
- name: notparents
addresses:
- address: 10.20.30.40
- address: 30.40.50.60
- address: 40.50.60.70
primaries:
- name: parents
port: 53353
dscp: 42
addresses:
- address: 10.20.30.40
port: 53
key: certbot.
- address: 20.30.40.50
port: 53
- address: 30.40.50.60
key: certbot2.
- address: 40.50.60.70
- name: notparents
addresses:
- address: 10.20.30.40
- address: 30.40.50.60
- address: 40.50.60.70
tls:
- name: certbot
cert_file: /etc/ssl/private/snakeoil.pem
key_file: /etc/ssl/private/snakeoil.key
dhparam_file: /etc/ssl/dhparam.pem
ca_file: /etc/ssl/certs/ca-certificates.crt
remote_hostname: yourhostname
ciphers: HIGH:!aNULL:!MD5:!SHA1:!SHA256:!SHA384
protocols:
- TLSv1.2
- TLSv1.3
prefer_server_ciphers: true
session_tickets: true
trust_anchors:
- name: .
type: initial-key
flags: 257
protocol: 3
algorithm: 8
key: "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="
- name: hugs.dk
type: static-ds
flags: 64335
protocol: 7
algorithm: 2
key: "D6AAECB1BA13D51F072A229C957ACADEA18118FB17DA2DC7D45A963428091372"
server:
- prefix: 1.1.1.1
bogus: false
edns: true
tcp_only: false
tcp_keepalive: false
edns_version: '0'
padding: '0'
transfers: '0'
keyname: certbot.
query_source:
address: "*"
port: "*"
statistics_channels:
- address: 0.0.0.0
port: 8080
allow:
- 0/0
- name: named.conf.zones
backup: false
zones:
- name: "_acme-challenge.hugs.dk"
type: master
file: master/_acme-challenge.hugs.dk.zone
allow_query:
- any
dnssec_policy: default
inline_signing: true
serial_update_method: date
update_policy:
- permission: grant
identity: certbot.
ruletype: name
name: _acme-challenge.hugs.dk
types: txt
- name: forward.net
type: forward
forwarders:
port: 53
addresses:
- address: 1.1.1.1
port: 53
dscp: 42
- address: 4.2.2.4
port: 53
- name: stub.com
type: static-stub
allow_query:
- any
server_addresses:
- 1.1.1.1
- 8.8.8.8
zone_statistics: full
- name: example.com
type: slave
allow_query:
- 127.0.0.1
- 10.0.0.1
- 128.15.14.13
allow_query_on:
- 127.0.0.1
primaries:
port: 5522
dscp: 42
addresses:
- address: 127.0.0.1
port: 55222
- address: 10.20.30.40
- name: smorg.bop
type: slave
primaries:
addresses:
- address: 127.0.0.1
allow_query:
- 15.14.13.12
- 10.20.30.40
- 28.25.23.24
- "!10.13.14.15"
forwarders:
port: 53
dscp: 42
addresses:
- address: 127.0.0.1
port: 53
dscp: 42
- address: 10.20.30.40
port: 53
- address: 20.30.40.50
- address: 30.40.50.60
port: 53
allow_transfer:
port: 5522
transport: tls
addresses:
- 192.168.122.1
also_notify:
port: 5523
dscp: 42
addresses:
- address: 127.0.0.1
port: 5523
- address: 127.0.0.2
auto-dnssec: allow
dnskey_sig_validity: 0
dnssec-dnskey-kskonly: true
dnssec_loadkeys_interval: 0
file: "string"
forward: first
inline_signing: true
ixfr_from_differences: true
masterfile_format: raw
masterfile_style: full
max_ixfr_ratio: unlimited
max_journal_size: default
max_records: 0
max_transfer_idle_out: 0
max_transfer_time_out: 0
notify: true
notify_delay: '0'
notify_to_soa: false
parental_agents:
port: 44332
dscp: 42
addresses:
- address: 127.0.0.1
port: 53
sig_signing_nodes: '0'
sig_signing_signatures: '0'
sig_signing_type: 65281
zero_no_soa_ttl: true
zone_statistics: full