636 lines
17 KiB
Markdown
636 lines
17 KiB
Markdown
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'` or `var: 'null'`, otherwise jinja will assume you want it to be empty/null. Normal integers would be defined as `var: 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 one of:
|
|
# <option> [ port <port> ] [ dscp <dscp> ] { <address> [ port <port> ] [ dscp <dscp> ]; ... }
|
|
# <option> [ port <port> ] [ dscp <dscp> ] { <address> [ port <port> ] [ key <key> ] [ tls <tls> ]; ... }
|
|
# 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:
|
|
1. bind9_default_config
|
|
2. bind9_group_config
|
|
3. bind9_leaf_config
|
|
4. 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
|
|
```
|