debops.bind default variables

General configuration

bind__features

List of features which should be installed and enabled (if supported by the installed BIND version and local environment). See Features for details.

bind__features:
  - 'dns'
  - 'dnssec'
  - '{{ "dot" if bind__pki else [] }}'
  - '{{ "doh_https"
        if (bind__pki
            and not ansible_local.nginx.enabled | d(False)
            and not ansible_local.apache.enabled | d(False)
            and "debops_service_nginx" not in group_names
            and "debops_service_apache" not in group_names)
        else [] }}'
  - '{{ "doh_proxy"
        if (bind__pki and ansible_local.nginx.enabled | d(False)
            or "debops_service_nginx" in group_names)
        else [] }}'
  - '{{ "stats_proxy"
        if (bind__pki and ansible_local.nginx.enabled | d(False)
            or "debops_service_nginx" in group_names)
        else [] }}'
bind__version

The BIND version which is installed on the host. Obtained from Ansible local facts, but also defined here to simplify the role and to allow the version to be overridden.

bind__version: '{{ ansible_local.bind.version | d("0.0.0") }}'
bind__fqdn

The FQDN of the BIND server, used in case DNS over HTTP(S) is configured using debops.nginx as a proxy.

bind__fqdn: 'dns.{{ bind__domain }}'
bind__domain

The main domain of the BIND server, used the create the FQDN above.

bind__domain: '{{ ansible_domain }}'
bind__blocked_domains

Domains for which BIND should return NXDOMAIN rather than a proper response. See Clients using external DoT/DoH servers for an explanation of the default value.

bind__blocked_domains: [ 'use-application-dns.net' ]

UNIX environment

bind__user

Name of the UNIX account used by the BIND server.

bind__user: 'bind'
bind__additional_groups

List of additional UNIX groups the BIND account should have access to.

bind__additional_groups: [ 'ssl-cert' ]

APT packages

bind__base_packages

List of APT packages required for BIND.

bind__base_packages: [ 'bind9', 'bind9-dnsutils' ]
bind__packages

List of additional APT packages to install together with BIND.

bind__packages: []

Backup snapshots

These variables configure periodic backup snapshots of the BIND configuration and zones. See Backup and restore procedures for more details.

bind__snapshot_enabled

If True, the snapshot cron jobs will be configured to run the debops-bind-snapshot script periodically to create snapshots of the BIND configuration and zones. If False, the cron jobs will be removed.

bind__snapshot_enabled: True
bind__snapshot_cron_jobs

List of cron periods during which the debops-bind-snapshot script should be executed to create BIND snapshots.

bind__snapshot_cron_jobs: [ 'daily', 'weekly', 'monthly' ]

DNSSEC configuration

These variables control the signing of zones. See DNSSEC for further details.

bind__dnssec_use_nsec3

Whether DNSSEC signed zones should, by default, use NSEC3 instead of NSEC. NSEC3 makes it more difficult to enumerate a zone, but with some added computational complexity. See the DNSSEC Guide for more details.

bind__dnssec_use_nsec3: True
bind__dnssec_script_enabled

Whether the DNSSEC rollover script should be enabled. See Rollover Script for details. Note that the default value might change once a majority of registries/registrars support CDN/CDNSKEY based automatic updates (see Key Rollover).

bind__dnssec_script_enabled: '{{ True if "dnssec" in bind__features else False }}'
bind__dnssec_script_domains

Domains which the DNSSEC rollover script should monitor for key changes. List of strings in the form <domain> or <domain>/<view>. An empty list means the script will attempt to monitor all domains.

bind__dnssec_script_domains: []
bind__dnssec_script_method

The method to use when DNSSEC keys need to be published/withdrawn in the parent zone.

Supported values are:

log

Key updates will simply be logged to a file.

email

Emails will be sent to the admin email address for manual handling.

external

An external script will be executed when keys need to be updated.

bind__dnssec_script_method: 'email'
bind__dnssec_script_default_configuration

The default configuration for the DNSSEC rollover script.

bind__dnssec_script_default_configuration:
  - name: 'method'
    value: '{{ bind__dnssec_script_method }}'

  - name: 'log_file'
    value: '/var/log/debops-bind-rollkey.log'

  - name: 'email_to'
    value: '{{ ansible_local.core.admin_public_email[0]
               | d("root@" + ansible_domain) }}'

  - name: 'email_from'
    value: '{{ "noreply@" + ansible_domain }}'

  - name: 'email_host'
    value: 'localhost'

  - name: 'email_port'
    value: 25

  - name: 'email_subject'
    value: 'BIND DNSSEC key updates'

  - name: 'external_script'
    value: '/usr/local/sbin/debops-bind-rollkey-action'

  - name: 'zones'
    value: '{{ bind__dnssec_script_domains }}'
bind__dnssec_script_configuration

The configuration for the DNSSEC rollover script defined for all hosts in the Ansible inventory.

bind__dnssec_script_configuration: []
bind__dnssec_script_group_configuration

The configuration for the DNSSEC rollover script defined for all hosts in a specific Ansible inventory group.

bind__dnssec_script_group_configuration: []
bind__dnssec_script_host_configuration

The configuration for the DNSSEC rollover script defined for a specific host in the Ansible inventory.

bind__dnssec_script_host_configuration: []
bind__dnssec_script_combined_configuration

The combined configuration for the DNSSEC rollover script. Used to create /etc/bind/debops-bind-rollkey.json.

bind__dnssec_script_combined_configuration: '{{
  bind__dnssec_script_default_configuration
  + bind__dnssec_script_configuration
  + bind__dnssec_script_group_configuration
  + bind__dnssec_script_host_configuration }}'

DNS over HTTP(S)

See DNS over TLS/HTTP(S) for further details.

bind__doh_endpoints

List of HTTP query paths on which to listen if DNS-over-HTTP(S) is enabled.

bind__doh_endpoints: [ '/dns-query' ]
bind__doh_proxy_port

Port on the loopback interface to use by named in case DNS over HTTP(S) is enabled using a real webserver as a proxy.

bind__doh_proxy_port: 83
bind__doh_proxy_allow

List of IP addresses or CIDR ranges which should have access to the DNS over HTTP(S) interface exposed using the proxy via the bind__doh_endpoints paths. Default: all local networks.

bind__doh_proxy_allow: >-
  {%- set cidrs = [] -%}
  {%- for item in ((ansible_interfaces
                    | map('extract', ansible_facts, 'ipv4')
                    | select('defined') | list | flatten) +
                   (ansible_interfaces
                    | map('extract', ansible_facts, 'ipv6')
                    | select('defined') | list | flatten)) | d([]) -%}
  {%-   if item.address | d() and not item.address | ipaddr('link-local') -%}
  {%-     set address = item.address -%}
  {%-     set prefix_or_mask = item.prefix | d(item.netmask) -%}
  {%-     set cidr = '{}/{}'.format(address, prefix_or_mask) -%}
  {%-     set _ = cidrs.append(cidr | ipaddr('network/prefix')) -%}
  {%-   endif -%}
  {%- endfor -%}
  {{ cidrs | unique | sort }}
bind__doh_proxy_access_policy

Name of the nginx access policy to use for the DNS over HTTP(S) proxy. See debops.nginx for more details.

bind__doh_proxy_access_policy: ''
bind__stats_proxy_port

Port on the loopback interface to use by named in case statistics should be provided over HTTP(S) using a real webserver as a proxy.

bind__stats_proxy_port: 84
bind__stats_proxy_allow

List of IP addresses or CIDR ranges which should have access to the DNS statistics web interface exposed using the proxy. Default: all local IP addresses.

bind__stats_proxy_allow: '{{ ["127.0.0.1", "::1"]
                             + ansible_all_ipv4_addresses | d([])
                             + (ansible_all_ipv6_addresses | d([])
                                | difference(ansible_all_ipv6_addresses | d([])
                                             | ipaddr("link-local")))
                             | unique | sort }}'
bind__stats_proxy_access_policy

Name of the nginx access policy to use for the statistics proxy. See debops.nginx for more details.

bind__stats_proxy_access_policy: ''

Main configuration file

These variables define the contents of the main /etc/bind/named.conf configuration file. See Main configuration for further details.

bind__default_configuration

The default configuration defined by the role.

bind__default_configuration:

  - name: 'debops-tls'
    option: 'tls "debops-tls"'
    comment: 'TLS options for DoH and DoT'
    state: '{{ "present" if bind__features | intersect(["dot", "doh_https"])
               else "absent" }}'
    options:

      - name: 'ciphers'
        value: '"{{ bind__tls_cipher_list }}"'

      - name: 'dhparam-file'
        value: '"{{ bind__tls_dh_file }}"'
        state: '{{ "present" if bind__dhparam else "absent" }}'

      - name: 'cert-file'
        value: '"{{ bind__pki_path + "/" + bind__pki_realm + "/" + bind__pki_crt }}"'

      - name: 'key-file'
        value: '"{{ bind__pki_path + "/" + bind__pki_realm + "/" + bind__pki_key }}"'

      - name: 'protocols'
        options:

          - name: 'protocols'
            raw: '{{ bind__tls_protocols | d([]) | join("; ") }};'

      - name: 'session-tickets'
        value: 'no'

      - name: 'prefer-server-ciphers'
        value: 'yes'

      - name: 'ca-file'
        state: 'absent'

      - name: 'remote-hostname'
        state: 'absent'

  - name: 'http "debops-http"'
    comment: 'DoH options'
    state: '{{ "present"
               if bind__features | intersect(["doh_https", "doh_proxy", "doh_http"])
               else "absent" }}'
    options:

      - name: 'endpoints'
        options:

          - name: 'endpoints'
            raw: "{{ bind__doh_endpoints | map('regex_replace', '^(.*)$', '\"\\1\";') | join(' ') }}"

      - name: 'listener-clients'
        state: 'absent'

      - name: 'streams-per-connection'
        state: 'absent'

  - name: 'statistics-channels'
    comment: 'Make stats available via a reverse proxy'
    state: '{{ "present" if "stats_proxy" in bind__features else "absent" }}'
    options:

      - name: 'statistics-localhost'
        raw: 'inet 127.0.0.1 port {{ bind__stats_proxy_port }} allow { any; };'

  - name: 'options'
    options:

      - name: 'directory'
        comment: 'For storage of non-authoritative/secondary zones'
        value: '"/var/cache/bind"'

      - name: 'forwarders'
        state: 'absent'
        options:

          - name: 'forwarder-1'
            raw: '1.1.1.1;'

      - name: 'zone-statistics'
        comment: 'Collect stats for all zones, available via rndc stats'
        value: 'yes'

      - name: 'listen-dns-v4'
        option: 'listen-on'
        comment: 'Regular DNS (Do53) - IPv4'
        state: '{{ "present" if "dns" in bind__features else "absent" }}'
        options:

          - name: 'any'
            raw: 'any;'

      - name: 'listen-dot-v4'
        option: 'listen-on port 853 tls debops-tls'
        comment: 'DNS over TLS (DoT) - IPv4'
        state: '{{ "present" if "dot" in bind__features else "absent" }}'
        options:

          - name: 'any'
            raw: 'any;'

      - name: 'listen-doh-https-v4'
        option: 'listen-on port 443 tls debops-tls http debops-http'
        comment: 'DNS over HTTPS (DoH) - IPv4'
        state: '{{ "present" if "doh_https" in bind__features else "absent" }}'
        options:

          - name: 'any'
            raw: 'any;'

      - name: 'listen-doh-http-v4'
        option: 'listen-on port 80 tls none http debops-http'
        comment: 'DNS over HTTP (DoH) - IPv4'
        state: '{{ "present" if "doh_http" in bind__features else "absent" }}'
        options:

          - name: 'localhost'
            raw: 'any;'

      - name: 'listen-doh-proxy-v4'
        option: 'listen-on port {{ bind__doh_proxy_port | d("83") }} tls none http debops-http'
        comment: 'DNS over HTTP (DoH), behind proxy - IPv4'
        state: '{{ "present" if "doh_proxy" in bind__features else "absent" }}'
        options:

          - name: 'localhost'
            raw: '127.0.0.1;'

      - name: 'listen-dns-v6'
        option: 'listen-on-v6'
        comment: 'Regular DNS (Do53) - IPv6'
        state: '{{ "present" if "dns" in bind__features else "absent" }}'
        options:

          - name: 'any'
            raw: 'any;'

      - name: 'listen-dns-dot-v6'
        option: 'listen-on-v6 port 853 tls debops-tls'
        comment: 'DNS over TLS (DoT) - IPv6'
        state: '{{ "present" if "dot" in bind__features else "absent" }}'
        options:

          - name: 'any'
            raw: 'any;'

      - name: 'listen-doh-https-v6'
        option: 'listen-on-v6 port 443 tls debops-tls http debops-http'
        comment: 'DNS over HTTPS (DoH) - IPv6'
        state: '{{ "present" if "doh_https" in bind__features else "absent" }}'
        options:

          - name: 'any'
            raw: 'any;'

      - name: 'listen-doh-http-v6'
        option: 'listen-on-v6 port 80 tls none http debops-http'
        state: '{{ "present" if "doh_http" in bind__features else "absent" }}'
        comment: 'DNS over HTTP (DoH) - IPv6'
        options:

          - name: 'localhost'
            raw: 'any;'

      - name: 'listen-doh-proxy-v6'
        option: 'listen-on-v6 port {{ bind__doh_proxy_port | d("83") }} tls none http debops-http'
        comment: 'DNS over HTTP (DoH), behind proxy - IPv6'
        state: '{{ "present" if "doh_proxy" in bind__features else "absent" }}'
        options:

          - name: 'localhost'
            raw: '127.0.0.1;'

      - name: 'qname-minimization'
        comment: 'Perform strict QNAME minimization (RFC7816)'
        value: 'strict'
        state: 'comment'

      - name: 'dnssec-validation'
        comment: 'This is for when BIND acts as a resolver'
        value: 'auto'

      - name: 'key-directory'
        comment: 'For storage of DNSSEC keys'
        value: '"/var/lib/bind/dnssec-keys"'
        state: '{{ "present" if "dnssec" in bind__features else "absent" }}'

      - name: 'dnssec-dnskey-kskonly'
        comment: 'https://gitlab.isc.org/isc-projects/bind9/-/issues/1316'
        state: '{{ "present" if "dnssec" in bind__features else "absent" }}'
        value: 'yes'

      - name: 'response-policy-blocked-domains'
        raw: 'response-policy { zone "rpz.local"; } break-dnssec yes;'
        state: '{{ "present" if bind__blocked_domains | d([]) | length > 0 else "absent" }}'

      - name: 'max-udp-size'
        comment: 'https://www.isc.org/blogs/dns-flag-day-2020-2/'
        value: '1220'

      - name: 'edns-udp-size'
        comment: 'https://www.isc.org/blogs/dns-flag-day-2020-2/'
        value: '1220'

      - name: 'serial-update-method'
        comment: 'Make the serial numbers meaningful to a human admin'
        value: 'date'

  - name: 'logging'
    state: 'absent'
    options:

      - name: 'channel client_spam_channel'
        options:

          - name: 'file'
            value: '"/var/log/named/named_recent_client.log" versions 3 size 5m suffix increment'

          - name: 'severity'
            value: 'info'

          - name: 'print-time'
            value: 'yes'

          - name: 'print-category'
            value: 'yes'

          - name: 'print-severity'
            value: 'yes'

          - name: 'buffered'
            value: 'no'

      - name: 'channel server_spam_channel'
        options:

          - name: 'file'
            value: '"/var/log/named/named_recent_server.log" versions 3 size 5m suffix increment'

          - name: 'severity'
            value: 'info'

          - name: 'print-time'
            value: 'yes'

          - name: 'print-category'
            value: 'yes'

          - name: 'print-severity'
            value: 'yes'

          - name: 'buffered'
            value: 'no'

      - name: 'category client'
        options:

          - name: 'channel-1'
            raw: 'client_spam_channel;'

      - name: 'category query-errors'
        options:

          - name: 'channel-1'
            raw: 'client_spam_channel;'

      - name: 'category resolver'
        options:

          - name: 'channel-1'
            raw: 'client_spam_channel;'

      - name: 'category security'
        options:

          - name: 'channel-1'
            raw: 'client_spam_channel;'

      - name: 'category spill'
        options:

          - name: 'channel-1'
            raw: 'client_spam_channel;'

      - name: 'category cname'
        options:

          - name: 'channel-1'
            raw: 'server_spam_channel;'

      - name: 'category edns-disabled'
        options:

          - name: 'channel-1'
            raw: 'server_spam_channel;'

      - name: 'category lame-servers'
        options:

          - name: 'channel-1'
            raw: 'server_spam_channel;'

  - name: 'generated-keys'
    comment: 'Keys defined by the Ansible role'
    state: '{{ "present"
               if bind__combined_keys
                  | flatten
                  | debops.debops.parse_kv_items
                  | selectattr("state", "equalto", "present")
                  | length > 0
               else "absent" }}'
    autovalue: 'keys'

  - name: 'acl debops-acl'
    state: '{{ "present"
               if "debops-key" in (bind__combined_keys
                                   | flatten
                                   | debops.debops.parse_kv_items
                                   | selectattr("state", "equalto", "present")
                                   | map(attribute="name"))
               else "absent" }}'
    options:

      - name: 'debops-key'
        raw: 'key debops-key;'

  - name: 'dnssec-policy-csk'
    option: 'dnssec-policy "csk"'
    comment: 'Single CSK without rollover (BINDs default policy)'
    state: '{{ "present" if "dnssec" in bind__features else "absent" }}'
    options:

      - name: 'keys'
        options:

          - name: 'csk'
            value: 'key-directory lifetime unlimited algorithm ecdsap256sha256'

      - name: 'nsec3param'
        comment: |
          If you consider changing these values, first read:
          https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-nsec3-guidance-10#section-3.1
        state: '{{ "present" if bind__dnssec_use_nsec3 | d(False) else "absent" }}'
        value: 'iterations 0 optout no salt-length 0'

      - name: 'dnskey-ttl'
        comment: 'Key timings'
        separator: True
        value: '3600'

      - name: 'publish-safety'
        value: '1h'

      - name: 'retire-safety'
        value: '1h'

      - name: 'purge-keys'
        value: 'P90D'

      - name: 'signatures-refresh'
        comment: 'Signature timings'
        separator: True
        value: '5d'

      - name: 'signatures-validity'
        value: '14d'

      - name: 'signatures-validity-dnskey'
        value: '14d'

      - name: 'max-zone-ttl'
        comment: 'Zone parameters'
        separator: True
        value: '86400'

      - name: 'zone-propagation-delay'
        value: '300'

      - name: 'parent-ds-ttl'
        comment: 'Parent parameters'
        separator: True
        value: '86400'

      - name: 'parent-propagation-delay'
        value: '1h'

  - name: 'dnssec-policy-csk-rollover'
    option: 'dnssec-policy "csk-rollover"'
    comment: 'Single CSK with rollover'
    state: '{{ "present" if "dnssec" in bind__features else "absent" }}'
    options:

      - name: 'keys'
        options:

          - name: 'csk'
            value: 'key-directory lifetime 365d algorithm ecdsap256sha256'

      - name: 'nsec3param'
        comment: |
          If you consider changing these values, first read:
          https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-nsec3-guidance-10#section-3.1
        state: '{{ "present" if bind__dnssec_use_nsec3 | d(False) else "absent" }}'
        value: 'iterations 0 optout no salt-length 0'

      - name: 'dnskey-ttl'
        comment: 'Key timings'
        separator: True
        value: '3600'

      - name: 'publish-safety'
        value: '1h'

      - name: 'retire-safety'
        value: '1h'

      - name: 'purge-keys'
        value: 'P90D'

      - name: 'signatures-refresh'
        comment: 'Signature timings'
        separator: True
        value: '5d'

      - name: 'signatures-validity'
        value: '14d'

      - name: 'signatures-validity-dnskey'
        value: '14d'

      - name: 'max-zone-ttl'
        comment: 'Zone parameters'
        separator: True
        value: '86400'

      - name: 'zone-propagation-delay'
        value: '300'

      - name: 'parent-ds-ttl'
        comment: 'Parent parameters'
        separator: True
        value: '86400'

      - name: 'parent-propagation-delay'
        value: '1h'

  - name: 'dnssec-policy-kskzsk'
    option: 'dnssec-policy "kskzsk"'
    comment: 'Separate KSK and ZSK without rollover'
    state: '{{ "present" if "dnssec" in bind__features else "absent" }}'
    options:

      - name: 'keys'
        options:

          - name: 'ksk'
            value: 'key-directory lifetime unlimited algorithm ecdsap256sha256'

          - name: 'zsk'
            value: 'key-directory lifetime unlimited algorithm ecdsap256sha256'

      - name: 'nsec3param'
        comment: |
          If you consider changing these values, first read:
          https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-nsec3-guidance-10#section-3.1
        state: '{{ "present" if bind__dnssec_use_nsec3 | d(False) else "absent" }}'
        value: 'iterations 0 optout no salt-length 0'

      - name: 'dnskey-ttl'
        comment: 'Key timings'
        separator: True
        value: '3600'

      - name: 'publish-safety'
        value: '1h'

      - name: 'retire-safety'
        value: '1h'

      - name: 'purge-keys'
        value: 'P90D'

      - name: 'signatures-refresh'
        comment: 'Signature timings'
        separator: True
        value: '5d'

      - name: 'signatures-validity'
        value: '14d'

      - name: 'signatures-validity-dnskey'
        value: '14d'

      - name: 'max-zone-ttl'
        comment: 'Zone parameters'
        separator: True
        value: '86400'

      - name: 'zone-propagation-delay'
        value: '300'

      - name: 'parent-ds-ttl'
        comment: 'Parent parameters'
        separator: True
        value: '86400'

      - name: 'parent-propagation-delay'
        value: '1h'

  - name: 'dnssec-policy-kskzsk-rollover'
    option: 'dnssec-policy "kskzsk-rollover"'
    comment: 'Separate KSK and ZSK with rollover (the traditional policy)'
    state: '{{ "present" if "dnssec" in bind__features else "absent" }}'
    options:

      - name: 'keys'
        options:

          - name: 'ksk'
            value: 'key-directory lifetime 365d algorithm ecdsap256sha256'

          - name: 'zsk'
            value: 'key-directory lifetime 60d algorithm ecdsap256sha256'

      - name: 'nsec3param'
        comment: |
          If you consider changing these values, first read:
          https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-nsec3-guidance-10#section-3.1
        state: '{{ "present" if bind__dnssec_use_nsec3 | d(False) else "absent" }}'
        value: 'iterations 0 optout no salt-length 0'

      - name: 'dnskey-ttl'
        comment: 'Key timings'
        separator: True
        value: '3600'

      - name: 'publish-safety'
        value: '1h'

      - name: 'retire-safety'
        value: '1h'

      - name: 'purge-keys'
        value: 'P90D'

      - name: 'signatures-refresh'
        comment: 'Signature timings'
        separator: True
        value: '5d'

      - name: 'signatures-validity'
        value: '14d'

      - name: 'signatures-validity-dnskey'
        value: '14d'

      - name: 'max-zone-ttl'
        comment: 'Zone parameters'
        separator: True
        value: '86400'

      - name: 'zone-propagation-delay'
        value: '300'

      - name: 'parent-ds-ttl'
        comment: 'Parent parameters'
        separator: True
        value: '86400'

      - name: 'parent-propagation-delay'
        value: '1h'

  - name: 'generated-zones'
    comment: 'Views/zones defined by the Ansible role'
    autovalue: 'zones'
    weight: 10000
bind__configuration

The configuration defined for all hosts in the Ansible inventory.

bind__configuration: []
bind__group_configuration

The configuration options defined for hosts in a specific Ansible inventory group.

bind__group_configuration: []
bind__host_configuration

The configuration defined for a specific host in the Ansible inventory.

bind__host_configuration: []
bind__combined_configuration

This variable combines the other configuration variables for use in the /etc/bind/named.conf template.

bind__combined_configuration: '{{ bind__default_configuration
                                   + bind__configuration
                                   + bind__group_configuration
                                   + bind__host_configuration }}'

Key configuration

These variables control the automated generation of keys which can be used e.g. by remote hosts for dynamic updates via nsupdate and which can be automatically included in the /etc/bind/named.conf configuration. See Keys for more details.

bind__default_keys

The default keys defined by the role.

bind__default_keys:

  - name: 'debops-key'
    algorithm: 'hmac-sha512'
    type: 'tsig'
bind__keys

The keys defined for all hosts in the Ansible inventory.

bind__keys: []
bind__group_keys

The keys defined for hosts in a specific Ansible inventory group.

bind__group_keys: []
bind__host_keys

The keys defined for a specific host in the Ansible inventory.

bind__host_keys: []
bind__combined_keys

The variable that combines all keys for use in the role tasks and templates.

bind__combined_keys: '{{ bind__default_keys
                          + bind__keys
                          + bind__group_keys
                          + bind__host_keys }}'

Zone configuration

These variables define zones which are to be controlled via Ansible and which can be automatically included in the configuration. See Zones and Views for further details.

bind__default_zone_ttl

The default TTL value for generated zones.

bind__default_zone_ttl: '1D'
bind__default_zone_soa_primary

The default primary server for generated zones, a FQDN with a trailing period. Used in the SOA RR.

bind__default_zone_soa_primary: '{{ ansible_fqdn | regex_replace("\.*$", ".") }}'
bind__default_zone_soa_email

The default contact email address for generated zones, with the @ replaced by a period and a trailing period. Periods can be escaped using a backslash.

For example:
  • hostmaster@example.com -> hostmaster.example.com.

  • john.doe@example.com -> john\.doe.example.com.

Used in the SOA RR.

bind__default_zone_soa_email: '{{ "hostmaster." + ansible_domain + "." }}'
bind__default_zone_soa_serial

The default initial serial number for generated zones (may be automatically updated by the bind server, e.g. due to automatic DNSSEC signing or dynamic DNS updates, which is why the YYYYMMDDnn is not followed). Used in the SOA RR.

bind__default_zone_soa_serial: 1
bind__default_zone_soa_refresh

The default refresh time for generated zones (how often secondary servers should query the master to detect zone changes). This and the following defaults follow the recommendations from this internet draft. Used in the SOA RR.

bind__default_zone_soa_refresh: '1D'
bind__default_zone_soa_retry

The default retry time for generated zones (how often secondary servers should reattempt querying the master to detect zone changes upon failure, must be smaller than the bind__default_zone_soa_refresh value. Used in the SOA RR.

bind__default_zone_soa_retry: '2H'
bind__default_zone_soa_expire

The default expiry time for generated zones (how long before secondary servers should stop answering requests for this zone if the master is unreachable, must be larger than bind__default_zone_soa_refresh plus bind__default_zone_soa_retry. Used in the SOA RR.

bind__default_zone_soa_expire: '1000H'
bind__default_zone_neg_ttl

The default TTL for negative responses for generated zones. Used in the SOA RR.

bind__default_zone_soa_neg_ttl: '2D'
bind__default_zones

The default bind configuration options defined by the role. See Syntax for details. The reason that the blocklist is defined here and not in bind__default_generic_zones is that it is unlikely to be desirable to have the blocklist present in multiple views (e.g. in a setup with an external/internal view).

bind__default_zones:

  - name: 'rpz.local'
    force: True
    comment: 'Domain blocklist'
    state: '{{ "present" if bind__blocked_domains | d([]) | length > 0 else "absent" }}'
    options:

      - name: 'type'
        value: 'master'

      - name: 'file'
        autovalue: 'zone_file_path'

    content: '{{ ["@  IN NS localhost."]
                 + bind__blocked_domains | d([]) | map("regex_replace", "^(.*)$", "\1 CNAME .")
              }}'
bind__zones

The bind configuration options defined for all hosts in the Ansible inventory.

bind__zones: []
bind__group_zones

The bind configuration options defined for hosts in a specific Ansible inventory group.

bind__group_zones: []
bind__host_zones

The bind configuration options defined for a specific host in the Ansible inventory.

bind__host_zones: []
bind__combined_zones

The variable that combines other bind configuration options for use in the /etc/bind/named.conf template.

bind__combined_zones: '{{ bind__default_zones
                           + bind__zones
                           + bind__group_zones
                           + bind__host_zones }}'

Generic zone configuration

These variables definel the zones which are to be included in all views (e.g. root server hints and RFC 1912 zones). See Generic Zones for further details.

bind__default_generic_zones

The default generic zones defined by the role.

bind__default_generic_zones:

  - name: '.'
    comment: 'prime the server with knowledge of the root servers'
    options:

      - name: 'type'
        value: 'hint'

      - name: 'file'
        value: '"/usr/share/dns/root.hints"'

  - name: 'localhost'
    comment: be authoritative for the localhost forward zone (RFC1912, 4.1)
    options:

      - name: 'type'
        value: 'master'

      - name: 'file'
        value: '"/etc/bind/db.local"'

  - name: '127.in-addr.arpa'
    comment: be authoritative for the localhost reverse zone (RFC1912, 4.1)
    options:

      - name: 'type'
        value: 'master'

      - name: 'file'
        value: '"/etc/bind/db.127"'


  - name: '0.in-addr.arpa'
    comment: be authoritative for this network (RFC1912, 4.1)
    options:

      - name: 'type'
        value: 'master'

      - name: 'file'
        value: '"/etc/bind/db.0"'


  - name: '255.in-addr.arpa'
    comment: be authoritative for the broadcast zone (RFC1912, 4.1)
    options:

      - name: 'type'
        value: 'master'

      - name: 'file'
        value: '"/etc/bind/db.255"'
bind__generic_zones

The generic zones defined for all hosts in the Ansible inventory.

bind__generic_zones: []
bind__group_generic_zones

The generic zones defined for hosts in a specific Ansible inventory group.

bind__group_generic_zones: []
bind__host_generic_zones

The generic zones defined for a specific host in the Ansible inventory.

bind__host_generic_zones: []
bind__combined_generic_zones

This variable combines the other generic zone variables for use in the role tasks and templates.

bind__combined_generic_zones: '{{ bind__default_generic_zones
                                   + bind__generic_zones
                                   + bind__group_generic_zones
                                   + bind__host_generic_zones }}'

PKI / TLS configuration

bind__pki

Enable or disable support for DNS over HTTPS/TLS using debops.pki.

bind__pki: '{{ True
               if (ansible_local.pki.enabled | d(False) | bool
                   and bind__version is version("9.18.0", ">="))
               else False }}'
bind__pki_path

Base PKI directory.

bind__pki_path: '{{ ansible_local.pki.path | d("/etc/pki/realms") }}'
bind__pki_realm

Default PKI realm.

bind__pki_realm: '{{ ansible_local.pki.realm | d("domain") }}'
bind__pki_ca

Name of the Root Certificate Authority certificate file, relative to the PKI realm directory.

bind__pki_ca: '{{ ansible_local.pki.ca | d("CA.crt") }}'
bind__pki_crt

Default certificate, relative to the bind__pki_realm variable.

bind__pki_crt: '{{ ansible_local.pki.crt | d("default.crt") }}'
bind__pki_key

Default private key, relative to the bind__pki_realm variable.

bind__pki_key: '{{ ansible_local.pki.key | d("default.key") }}'
bind__tls_ca_cert_dir

Directory containing X509 Certification Authority certificates.

bind__tls_ca_cert_dir: '/etc/ssl/certs/'
bind__tls_protocols

List of TLS cipher(s) to support. TLS version 1.2 and higher are supported by BIND. The default assumes that all clients support recent TLS versions since DoH/DoT/etc are quite recent concepts.

bind__tls_protocols: [ "TLSv1.3" ]
bind__tls_cipher_list

SSL ciphers to use.

bind__tls_cipher_list: 'HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384'
bind__pki_hook_name

Name of the debops.pki hook script.

bind__pki_hook_name: 'bind'
bind__pki_hook_path

Directory for the debops.pki hooks.

bind__pki_hook_path: '{{ ansible_local.pki.hooks | d("/etc/pki/hooks") }}'
bind__pki_hook_action

Specify how changes in PKI should affect BIND, either 'reload' or 'restart'.

bind__pki_hook_action: 'reload'

Diffie-Hellman parameters

bind__dhparam

Enable or disable support for custom Diffie-Hellman parameters managed by the debops.dhparam Ansible role. Note that having this enabled is essential for enabling perfect forward secrecy capable ciphers in TLSv1.2.

bind__dhparam: '{{ ansible_local.dhparam.enabled | d(False) }}'
bind__dhparam_set

Name of the Diffie-Hellman parameter set to use. See the debops.dhparam Ansible role for more details.

bind__dhparam_set: 'default'
bind__tls_dh_file

Absolute path to the Diffie-Hellman parameters file which should be used.

bind__tls_dh_file: '{{ ansible_local.dhparam[bind__dhparam_set] | d("") }}'

Network access

bind__tcp_ports

List of TCP service names of the ports on which BIND will listen for network connections. These ports will be opened in the firewall so that other hosts can contact the DNS service.

bind__tcp_ports:

  # Regular DNS queries via TCP (used e.g. by :command:`nsupdate` for
  # large requests and for AXFR/zone transfer requests)
  - '{{ "domain" if "dns" in bind__features else [] }}'

  # DNS-over-TLS, DoT (RFC7858)
  - '{{ "domain-s" if "dot" in bind__features else [] }}'

  # DNS-over-HTTP, DoH (RFC8484)
  - '{{ "http" if "doh_http" in bind__features else [] }}'

  # DNS-over-HTTPS, DoH (RFC8484)
  - '{{ "https" if "doh_https" in bind__features else [] }}'
bind__udp_ports

List of UDP service names of the ports on which BIND will listen for network connections. These ports will be opened in the firewall so that other hosts can contact the DNS service.

bind__udp_ports:

  # Regular DNS queries
  - '{{ "domain" if "dns" in bind__features else [] }}'

  # DNS-over-DTLS (RFC8094), not supported
  #- 'domain-s'

  # DNS-over-HTTP3/QUIC, DoH3/DoQ (RFC9250), not supported
  #- 'https'
bind__accept_any

If True, the role will configure the firewall to accept connections to the BIND server from any network. Specific IP addresses and/or subnets can be blocked using the bind__*_deny variables.

If False, the role will block connections to the BIND server by default; hosts/subnets which are allowed to connect must be specified via the bind__*_allow variables.

bind__accept_any: '{{ True
                      if bind__features
                         | intersect(["dns", "dot", "doh_http", "doh_https"])
                      else False }}'
bind__deny

List of IP addresses or CIDR subnets which should be blocked from access to the BIND server, defined on all hosts in the Ansible inventory.

bind__deny: []
bind__group_deny

List of IP addresses or CIDR subnets which should be blocked from access to the BIND server, defined on hosts in a specific Ansible inventory group.

bind__group_deny: []
bind__host_deny

List of IP addresses or CIDR subnets which should be blocked from access to the BIND server, defined on specific hosts in the Ansible inventory.

bind__host_deny: []
bind__allow

List of IP addresses or CIDR subnets which should have access to the BIND server, defined on all hosts in the Ansible inventory.

bind__allow: []
bind__group_allow

List of IP addresses or CIDR subnets which should have access to the BIND server, defined on hosts in a specific Ansible inventory group.

bind__group_allow: []
bind__host_allow

List of IP addresses or CIDR subnets which should have access to the BIND server, defined on specific hosts in the Ansible inventory.

bind__host_allow: []

Configuration variables for other Ansible roles

bind__ferm__dependent_rules

Firewall configuration managed by the debops.ferm Ansible role.

bind__ferm__dependent_rules:

  - name: 'reject_bind_tcp'
    type: 'accept'
    protocol: 'tcp'
    dport: '{{ q("flattened", bind__tcp_ports) }}'
    multiport: True
    saddr: '{{ bind__deny + bind__group_deny + bind__host_deny }}'
    weight: '45'
    by_role: 'debops.bind'
    target: 'REJECT'
    rule_state: '{{ "present"
                    if (bind__deny + bind__group_deny + bind__host_deny)
                    else "absent" }}'

  - name: 'reject_bind_udp'
    type: 'accept'
    protocol: 'udp'
    dport: '{{ q("flattened", bind__udp_ports) }}'
    multiport: True
    saddr: '{{ bind__deny + bind__group_deny + bind__host_deny }}'
    weight: '45'
    by_role: 'debops.bind'
    target: 'REJECT'
    rule_state: '{{ "present"
                    if (bind__deny + bind__group_deny + bind__host_deny)
                    else "absent" }}'

  - name: 'accept_bind_tcp'
    type: 'accept'
    protocol: 'tcp'
    dport: '{{ q("flattened", bind__tcp_ports) }}'
    multiport: True
    saddr: '{{ bind__allow + bind__group_allow + bind__host_allow }}'
    accept_any: '{{ bind__accept_any }}'
    weight: '50'
    by_role: 'debops.bind'

  - name: 'accept_bind_udp'
    type: 'accept'
    protocol: 'udp'
    dport: '{{ q("flattened", bind__udp_ports) }}'
    multiport: True
    saddr: '{{ bind__allow + bind__group_allow + bind__host_allow }}'
    accept_any: '{{ bind__accept_any }}'
    weight: '50'
    by_role: 'debops.bind'
bind__nginx__dependent_servers

Server configuration for the debops.nginx role. Used to setup a DNS over HTTPS proxy, if requested.

bind__nginx__dependent_servers:

  - name: '{{ bind__fqdn }}'
    filename: 'debops.bind'
    by_role: 'debops.bind'
    type: 'default'
    webroot_create: False
    state: '{{ "present"
               if bind__features | intersect(["doh_proxy", "stats_proxy"])
               else "absent" }}'
    root: False
    maintenance: False

    toplevel_options: |-
      {% if "doh_proxy" in bind__features | d([]) %}
      # address and port of the DoH server, serving unencrypted HTTP/2
      upstream http2-doh {
              server 127.0.0.1:{{ bind__doh_proxy_port }};
      }{% endif %}

    location_list: >-
      {%- set locations =  [{
                "pattern": "/",
                "options": "proxy_pass http://127.0.0.1:"
                            + bind__stats_proxy_port | string + ";",
                "allow": bind__stats_proxy_allow,
                "access_policy": bind__stats_proxy_access_policy,
                "enabled": True if "stats_proxy" in bind__features else False
          }] -%}
      {%- for endpoint in bind__doh_endpoints | d([]) -%}
      {%-   set _ = locations.append({
                      "pattern": endpoint,
                      "options": "grpc_pass grpc://http2-doh;",
                      "allow": bind__doh_proxy_allow,
                      "access_policy": bind__doh_proxy_access_policy,
                      "enabled": True if "doh_proxy" in bind__features else False
            }) -%}
      {%- endfor -%}
      {{ locations }}
bind__logrotate__dependent_config

Configuration for the debops.logrotate Ansible role.

bind__logrotate__dependent_config:

  - filename: 'debops-bind-rollkeys'
    state: '{{ "present"
                if ("dnssec" in bind__features and
                    bind__dnssec_script_enabled | d(False))
                else "absent" }}'
    sections:

      - logs: '/var/log/debops-bind-rollkey.log'
        options: |
          notifempty
          missingok
          yearly
          rotate 10
          compress
        comment: 'BIND DNSSEC key rollover logs'
bind__apt_preferences__dependent_list

Configuration for the debops.apt_preferences Ansible role.

bind__apt_preferences__dependent_list:

  - packages: [ 'bind9', 'bind9-dnsutils', 'bind9-libs', 'bind9-utils' ]
    backports: [ 'bullseye' ]
    reason: 'Support for DNS-over-TLS/HTTPS'
    by_role: 'debops.bind'