Zones and Views
Introduction
The bind__*_zones
variables (not to be confused with the
bind__*_generic_zones
variables, see the next section) define the zones
which should be maintained via Ansible (and which are made available for use
in the bind__*_configuration
variables using the autovalue feature, see
the corresponding Syntax).
The toplevel items in the bind__*_zones
lists must be dicts containing
either name
keys (for zones) or view
keys (in case you are using
views, also known as split-horizon DNS, see RFC 6950). Each view
can, in turn, contain a number of zones, defined in its zones
parameter.
Warning
Mixing view
and name
entries at the top level will result in an
error during the execution of the role. Either all zones need to be in
a view, or all of them need to be outside any view.
Generic Zones
The bind__*_generic_zones
is similar to bind__*_zones
, but define zones
which should be present in every view. They will automatically be added to
every view (if you are using views), or simply added at the end of the list of
zones (if you are not using views). That also means that you cannot define
view
items in bind__*_generic_zones
.
Other than that, the configuration syntax for bind__*_generic_zones
is the
same as that of bind__*_zones
, and the following sections are equally
applicable to both sets of variables.
Zone content
The role can be used to define the initial content of zones and to
automatically generate the corresponding zone files for BIND to use. This is
controlled using the content
parameter. If you already have zone files at
hand, or plan to use some alternative source of zone files (including
hand-written zone files which could be transferred to the remote host running
BIND using e.g. the debops.resources role), the content
parameter
should not be defined for a zone.
Note
As a minimum, BIND expects a valid zone to contain a NS
record. Zones
lacking such a resource record will result in named logging an
error and not loading the zone. If you want to create an empty zone, you
should therefore set content
to something like @ IN NS localhost.
.
If the nameserver is in the zone itself, it also needs at least one A
or AAAA
record.
Dynamic zone updates
BIND supports dynamic zone updates if the update-policy or allow-update
options have been defined for a zone. By default, any updates to a zone file
are written by the named daemon to a separate journal file (by
default, the same path as the zone file, with an additional .jnl
extension).
The changes which are stored in the separate journal files can, and will,
be merged back into the original zone file (see, e.g. the sync
command for
the rndc utility, but named will also automatically sync
changes at various points in time, e.g. during restarts).
Warning
This means that a zone file and its journal file can get out of sync if the zone file is changed from an outside tool, like Ansible/DebOps, while there are unmerged changes in the zone's journal file. That, in turn, may lead to BIND refusing to load the zone on restart.
Enabling DNSSEC means that BIND will also update the zone on its own, for example, to add signing records. In other words, there are many different ways in which a zone might be dynamic.
While the role attempts to minimise the risk of creating such inconsistencies, it can never be guaranteed in the presence of both dynamic and "static" zone changes. The recommended approach is therefore to always perform dynamic updated on dynamic zones, e.g. using nsupdate (which can make use of Keys to authenticate requests). For example (this example assumes that it is executed on the Ansible controller):
# nsupdate -k ansible/secret/bind/foobar/debops-key.key
> server foobar.example.com
> ttl 3600
> zone example.com
> delete oldhost.example.com A
> add newhost.example.com A 192.168.2.99
> send
> quit
See nsupdate(1) for further details and examples.
Further remarks on using views
Note that if you use views, some options may have to be moved from the toplevel
option block in /etc/bind/named.conf
to the per-view equivalent.
For example, if you use the bind__blocked_domains
feature together
with views, you may define something like this in the Ansible inventory (in
effect, moving the response-policy
option and rpz.local
zone down from
the global to the view level):
bind__configuration:
- name: 'options'
options:
- name: 'response-policy-blocked-domains'
state: 'absent'
bind__default_zones: []
bind__zones:
- view: 'internal-view'
options:
- name: 'response-policy-blocked-domains'
raw: 'response-policy { zone "rpz.local"; } break-dnssec yes;'
zones:
- name: 'rpz.local'
options:
- name: 'type'
value: 'master'
- name: 'file'
autovalue: 'zone_file_path'
content: ...
Examples
See bind__default_generic_zones
for some simple examples.
A more complex example (without a view
) could look something like this:
bind__zones:
- name: 'example.com'
comment: 'My main domain'
options:
- name: 'type'
value: 'master'
- name: 'allow-transfer'
options:
- name: 'allow-transfer-1'
raw: '192.168.1.2; 192.168.1.3;'
- name: 'update-policy'
options:
- name: 'update-policy-local-ddns'
raw: 'grant local-ddns zonesub any;'
- name: 'update-policy-debops'
raw: 'grant debops-key zonesub any;'
- name: 'dnssec-policy'
value: '"kskzsk-rollover"'
content:
Here's an example using multiple view
entries, DNSSEC, and multiple keys to
differentiate between the views:
bind__keys:
- name: 'internal-key'
type: 'tsig'
algorithm: 'hmac-sha512'
- name: 'external-key'
type: 'tsig'
algorithm: 'hmac-sha512'
bind__configuration:
- name: 'acl-internal'
option: 'acl internal-acl'
comment: 'ACL matching internal users'
options:
- name: 'not-external-key'
raw: '!key external-key;'
- name: 'internal-key'
raw: 'key internal-key;'
- name: 'internal-ipv4'
raw: '192.168.1.0/24;'
- name: 'internal-ipv6'
raw: 'fd27:f00f:f00f::/48;'
- name: 'internal-localhost'
raw: 'localhost;'
- name: 'acl-external'
option: 'acl external-acl'
comment: 'ACL matching external users'
options:
- name: 'not-internal-key'
raw: '!key internal-key;'
- name: 'external-key'
raw: 'key external-key;'
- name: 'any'
raw: 'any;'
bind__zones:
- view: 'internal-view'
comment: 'Internal view'
options:
- name: 'match-clients'
options:
- name: 'internal-acl'
raw: 'internal-acl;'
- name: 'allow-recursion'
options:
- name: 'internal-acl'
raw: 'interal-acl;'
zones:
- name: 'example.com'
comment: 'My main domain'
options:
- name: 'type'
value: 'master'
- name: 'allow-transfer'
options:
- name: 'allow-transfer-1'
raw: '192.168.1.2; 192.168.1.3;'
- name: 'update-policy'
options:
- name: 'update-policy-local-ddns'
raw: 'grant local-ddns zonesub any;'
- name: 'update-policy-debops'
raw: 'grant debops-key zonesub any;'
- name: 'dnssec-policy'
value: '"kskzsk"'
content: ...
View syntax
Views are defined using a list of YAML dictionaries as toplevel items in the
bind__*_zones
variables. The following keys are valid in a view
dict:
view
Required, string. Name of a given view. Multiple views with the same
view
are merged together.state
Optional, string. If not specified or
present
, a given view will be present in the generated configuration. Otherwise, the view will not be included in the generated configuration.comment
Optional, string. A comment for the view which will be included in the generated configuration for documentation purposes.
zones
Optional, list of YAML dictionaries defining zones belonging to the given view. See Zone syntax.
options
Optional, list of YAML dictionaries defining options for the given view. The possible configuration options are listed here and the valid dict parameters are the same as for bind__*_configuration.
Zone syntax
Configuration sections are defined using a list of YAML dictionaries, each dictionary uses specific parameters:
name
Required, string. Name of a given zone (with or without a trailing period), this must be a valid domain name (e.g.
example.com
). Multiple configuration entries with the samename
are merged together.comment
Optional, string. A comment for the zone which will be included in the generated configuration for documentation purposes.
state
Optional, string. If not specified or
present
, a given zone will be present in the generated configuration. Otherwise, the zone will not be included in the generated configuration.dir
Optional, string. The directory in which the zone file should be created. Defaults to
/var/lib/bind/<view>/<zone>/
. Note that changing the default may clash with security policies defined by e.g.AppArmor
. Has no effect unlesscontent
has been defined.owner
Optional, string. The UNIX user owning the zone file. Defaults to
root
. Has no effect unlesscontent
has been defined.group
Optional, string. The UNIX group owning the zone file. Defaults to
bind
. Has no effect unlesscontent
has been defined.mode
Optional, octal mode string. The mode of the zone file. Defaults to
0775
. Has no effect unlesscontent
has been defined.force
Optional, boolean. Whether an existing zone file should be overwritten if the
content
(see below) has changed. Default:False
. Changing the default value can have undesirable consequences if dynamic updates are also enabled for the zone (see Dynamic zone updates for details). Has no effect unlesscontent
has been defined.ttl
Optional, string or integer. The default
TTL
of the zone. Integers define a TTL in seconds, while a string can be used to define a TTL in a more human-readable format (e.g.1d
,2m
,1h
).origin
Optional, string. This can be used to define the domain name which a given zone is for. If not defined (recommended), the
name
will be used as theorigin
for the zone.soa_primary
Optional, string. The primary server for this zone. Must be a valid domain name. If not defined,
bind__default_zone_soa_primary
is used.soa_email
Optional, string. The email address of the person responsible for the zone. If not defined,
bind__default_zone_soa_email
is used.soa_serial
Optional, string or integer. The serial number of the zone (a number which changes every time the zone is modified, and which is automatically incremented by the named server in response to dynamic updates). If not defined,
bind__default_zone_soa_serial
is used.soa_refresh
,soa_retry
,soa_expire
,soa_neg_ttl
Optional, string or integer. These values have the same format as the
ttl
value and are used to complete the SOA record for the zone. If not defined, the defaults frombind__default_zone_soa_*
are used.options
Optional, list of YAML dictionaries defining options for the given zone. The format is the same as for the
options
parameter for views (see the View syntax above). Valid configuration options can be found here and the valid dict parameters are the same as for bind__*_configuration.content
Optional, string or a list of strings/dicts. The resource records which should be present in the zone file in addition to the
SOA
record (which is always present). If this value is defined (even as an empty list), the zone file will be generated for apresent
zone. If defined as a string or list of strings, the string(s) will be added as-is to the zone file.If defined as a list of dicts, the valid dict options are:
name
Required, string. Name of a given resource record. Multiple resource records with the same
name
are merged together. Note that a resource record which doesn't end with a period will be interpreted by BIND as being a relative record and have the zone'sorigin
appended to it (so, assuming anorigin
ofexample.com.
,test.example.com
will be interpreted astest.example.com.example.com.
whiletest
ortest.example.com.
will both refer totest.example.com.
).state
Optional, string. If not specified or
present
, the resource record will be present in the generated configuration. Ifcomment
, the resource record will be present but commented out. Any other value means that the resource record will not be included in the generated zone file.comment
Optional, string. A comment to include before the resource record in the zone file.
raw
Optional, string. A string which will be included verbatim in the zone file. If this option is defined, the options below will be ignored.
owner
Optional, string. The owner (read: name) of the resource record. If not defined,
name
will be used as the owner/name of the resource record.ttl
Optional, string or integer. The TTL of the resource record (defined in the same way as the zone
ttl
above).class
Optional, string. The class of the resource record. It is quite unlikely that any other class than
IN
(the default) is desired.type
Required, string. The type of the resource record (e.g.
A
,AAAA
, orCNAME
).value
,rdata
Required, string. The data for the resource record (e.g.
192.168.2.1
for a record of typeA
).value
andrdata
are synonyms.