diff --git a/README.md b/README.md index 3771e6e..1c57f9d 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,13 @@ [![Build Status](https://github.com/systemli/ansible-role-bind9/workflows/Integration/badge.svg?branch=main)](https://github.com/systemli/ansible-role-bind9/actions?query=workflow%3AIntegration) [![Ansible Galaxy](http://img.shields.io/badge/ansible--galaxy-bind9-blue.svg)](https://galaxy.ansible.com/systemli/bind9/) -This role installs and configures the Bind9 nameserver on Debian. +This role installs and configures [BIND9](https://www.isc.org/bind/) on Debian to set a Name Server. Features: -* Support for configuring an authoritative nameserver for DNS zones and/or a DNS recursor +* Support for configuring BIND9 according to a set of template: + * default templates can implement an authoritative nameserver for DNS zones and/or a DNS recursor with or without forwarders, + * a set named `strict_authoritative` for a secure and easy configuration of a set of authoritative servers, primaries and secundaries, * Extensive DNSSEC support: * automatic KSK and ZSK key creation * automatic zone DNSSEC configuration @@ -18,8 +20,12 @@ Features: * Basic support for so called "dynamic" zones, i.e. defined from variables yaml variables sets ## Basic server configuration + +Lest's start by a simple but complete configuration of two servers: + ### Master server -* set vars for your master server, for instance in `host_vars/master_name/vars/XX_bind.yml`, here with an example.com static zones and forwarder: + +* set vars for your master server, for instance in `host_vars/master_name/vars/XX_bind.yml`, here with an example.com static zone and forwarder: ```yaml bind9_authoritative: yes bind9_zones_static: @@ -37,7 +43,7 @@ bind9_our_neighbors: - slave_ip_2 - slave_ip_3 ``` -* Place your BIND zone file in ansible directory (not in role directory): `files/bind/zones/db.example.com +* Place your BIND zone file in ansible directory (not in role directory): `files/bind/zones/db.example.com`. The role will check the validity of this file. ### Slave servers @@ -54,11 +60,15 @@ bind9_masters: - { name: master_name, addresses: [master_ip] } bind9_recursor: our_network ``` -### Dynamic zones -So called "dynamic" zones' records are defined through YAML ansible variable `bind9_zones_dynamic` which is parsed by [`bind/zones/db.template.j2`](templates/bind/zones/db.template.j2) template. -As there can be several zones, and zone definitions can be long, zone vars are worthily defined in a different vars file, for instance `host_vars/master_name/vars/YY_zones.yml`. `bind9_zones_dynamic` can be split in several variables, which can be defined in specific files, as in the example below. +* deploy role to your servers! + +## Static zones and Dynamic zones + +In previous example, zones' ressource records are defined by a classic BIND9 zone's file, which validity is checked, but that you have to maintain. These are the so called "static zones", raw defined by a `db.` file. + +So called "dynamic" zones' files are built form ansible variables. Their ressource records are defined through YAML ansible structure `bind9_zones_dynamic` which is parsed by [`bind/zones/db.template.j2`](templates/bind/zones/db.template.j2) template. -In `YY_zones.yml` we may have: +As there can be several zones, and zones' definitions can be long, zones' vars are worthly defined in a different vars' file, for instance `host_vars/master_name/vars/YY_zones.yml`, and `bind9_zones_dynamic` can be split in several variables, that can be defined in specific files. In `YY_zones.yml` we may have: ```yaml bind9_zones_dynamic: > {{ zones_my_domains @@ -75,7 +85,7 @@ bind9_zones_static: - name: static_dom3.org type: slave ``` -And in other vars files: +And in other vars' files: ```yaml zones_my_domains: # This is the variables set for my domain @@ -87,7 +97,7 @@ zones_my_domains: retry: 2H expire: 1000H # NS and other pre-formatted records values must be given as full qualified domain names, with or without final dot, but not relative to the zone - primary: ns1.dyn_domain.org # Optional, if you don't define it, firs NS is taken + master: ns1.dyn_domain.org # Optional, if you don't define it, firs NS is taken admin: postmaster.dyn_domain.org ns_records: - ns1.dyn_domain.org @@ -105,18 +115,117 @@ zones_my_domains: - {label: webserver, ttl: 86400, type: AAAA, rdata: 2001:db8:6a::23} ``` -And similarly `zone_my_reverse_inaddr_arpa` and `zone_my_reverse_ip6_arpa` for IP reverse DNS resolution. Note that we adopted for generic NS records the terminology defined in [RFC 1034, Section 3.6](https://datatracker.ietf.org/doc/html/rfc1034#section-3.6) +And similarly `zone_my_reverse_inaddr_arpa` and `zone_my_reverse_ip6_arpa` for IP reverse DNS resolution. Note that for generic NS records we adopted the terminology defined in [RFC 1034, Section 3.6](https://datatracker.ietf.org/doc/html/rfc1034#section-3.6) -* deploy role to your servers +## Configurable templates' set -## Dependencies +Basically the role builds bind9 configuration, i.e. `/etc/bind/named.conf.*` files, as well as zone definition files, which are placed in `/etc/bind/zones/` directory. -For the XMPP notification feature, `python-xmpp` needs to be installed. +Configuration is based on a set of templates, and the role can handle several ones. Presently two sets of templates are proposed: +* the default one, a general purpose set of templates that has evolved with the role, +* a "_strict authoritative_" NS templates' set, that: + * denies by default any query, recursion or transfer, and only allows queries from any and transfers from slaves for zones the server is authoritative on. + * automates, for each zone, the inclusion of secundary NS servers and also-notify IPs in the allow-transfer permissions. + +Templates' set is defined by variable `bind9_templates`. You should set it to the absolute path or the relative path to the `templates/` directory of the role. For [strict authoritative NS config](templates/strict_authoritative/), define in your vartiables: +```yaml +bind9_templates: strict_authoritative/ +``` +Several variables of the role define options and values in the set of templates you use. Note that the same role's variable of the role may have slightly different meanings, or no meaning at all, depending on the choosen set of templates. + +You can develop your own set of templates and set, for instance: +```yaml +bind9_templates: "{{ playbook_dir }}/host_vars//templates/" +``` +PRs with good BIND9 configs templates are welcome! + +### `strict_authoritative` templates' set + +[This templates' set](templates/strict_authoritative) is designed to configure strict [Authoritative Name Servers](https://bind9.readthedocs.io/en/latest/chapter3.html#config-auth-samples), primaries or secondaries: +* queries are refused except for the zones we are authoritative for, +* transfers are selectively set by zone and no recursion at all, +* when we answer, we give th same answer to the whole internet (for public internet zones, baroque configurations that restrict answers or, worse, give different answers to different clients, such as with views, are bad ideas that break the internet, considering DNS is a core part of it), +* by default, zone transfer are allowed, zone by zone, to secundaries and also-notify elements +* customizations should allow to configure all kind of sets of primaries or secudaries, visible or hideden. + +Therefore, when you set `bind9_templates: strict_authoritative/`, in `options` BIND configuration section, these templates always set: +``` +recursion no; +allow-query { none; }; +allow-transfer { none; }; +allow-recursion { none; }; +``` + +Default configuration values are set with `bind9_` role variables, that can be overwritten for each zone with specific values in the `.` field in the corresponding zone's element in `bind9_zones_static` or `bind9_zones_static`. + +Depending on the parameter considered, templates implement the default value either in the `options` section of BIND config files (`notify`, `also-notify`), either picking default values and set them in the zone's configuration section (`allow-query`, `allow-transfer`). With ACLs and setting parameter values per zone, the role can handle all sort of particular cases for some zones. + +The YAML structure of ther variables allows to overcome and unify (at least for simplified configurations the role permits) BIND's management of two kind of lists: masters and acl. Templates take advantage of this characteristic to automatically configure secundary NS IPs and also-notify IPs in the zone's `allow-transfer` configuration directive for zones we are master for. Zone parameters are defined to extend or to overwrite this list of allow-transfer. -## Role varibles +### `strict_authoritative` use cases -See `defaults/main.yml` for a list of role variables. +* `bind9_masters` and `bind9_slaves` should be enough for standard internet zones and if you have the same set of NS authoritative servers for all your zones. You don't have to care about `allow-transfer` for slaves in the master server: the role does the job. +* Use `bind9_also_notify` if you have some hidden NS servers. Don't worry neither about `allow-transfer` to those hosts, the role also does the job. +* If some of your zones have specific configuration: + * `bind9_masters_extra` can help you for different sets of masters for your secundary zones, + * `bind9_acl`, along with specific values per zone set in `bind9_zones_static` or `bind9_zones_dynamic`, will help to set all kind of transfers, notifications and even to restric queries for eventual private zones. +* zone by zone, the templates also takes care of including slaves and also-notify hosts for allow-transfer. + +### Role's variables for `strict_authoritative` templates + +Explicitely, you can use the following variables to configure your NS server and its zones: +* `bind9_masters`: default primary (or master) NS servers for zones we are secondary (or slave) for. + ```yaml + bind9_masters: + my_primariy: + - IPv4_1 + - IPv6_1 + my_fault_back_primary: + - IPv4_1 + - IPv6_1 + ``` + With these lists the template builds the [primaries' or masters' list(s)](https://bind9.readthedocs.io/en/latest/reference.html?highlight=primaries%20list#primaries-statement-grammar) to be used by default as `masters` for zones we are slave for, when masters are not specifically set for the zone. Note that masters' list can only other masters' lists names or individual IPs. IPv4 or IPv6, but not network IPs range, ending with a / and a mask length. + +* `bind9_masters_extra` is a similar structure that also sets primaries' lists, but which are not the role's default values for zones declared. + + __Magic-mix of acls and masters' lists__: Thanks to the similarity of these YAML structure with `bind9_acl` variable hereafter, for each element of `bind9_masters` and `bind9_masters_extra` the templates build, moreover the primaries' list, an [Access Control List (ACL)](https://bind9.readthedocs.io/en/latest/chapter6.html#access-control-lists) with the same name and content. Therefore, contrarily than when working directly on BIND9 configuration files, we can use masters' list names, not only in [the variables that define] `masters` or `also-notify` clauses of a zone, but also in [the variables that define] clauses which work with ACLs, such as `allow-transfer` or `allow-query`. Taking advantage of this trick, the role can automatically include a similar content into a notify-also clause (which requires a masters' list) as well as in the allow-transfer ones (which require an ACL). See hereafter. + +* `bind9_acl` has a quite similar structure with keywords and list of IPs but, in BIND configuration, it builds global [Access Control lists](https://bind9.readthedocs.io/en/latest/chapter6.html#access-control-lists), to be used in appropriate parameters, particularly in the `allow-xxx` per zone. Note that `bind9_acl` can contain not noly IPs (IPv4 and IPv6) but also network IPs ranges, ending with a / and a mask length, as well as a literal reference to recursively include another ACL. As ACLs are already defined for masters, so do not use for ACL a name you already used in a masters' list. + +* `bind9_slaves` defines the default secundary or slave NS servers for zones we are primary or master for. It's a list of IPs, or eventually ACLs defined with previous variable. For zones we are primary for, templates also include these secondaries IPs in those allowed to transfer the zone, except if the `.slaves` or the `.allow_transfer` parameter hereafter is defined for the zone. + +* `bind9_notify` can take the values `master-only`, `explicit`, `yes` or `no`. It defines the defaut behavior for notification, wich is set in [`options` section](templates/strict_authoritative/bind/named.conf.options.j2#L41). Letting `bind9_notify` undefined doesn't set the directive and therefore leads to BIND's default behavior, i.e. `notify: yes`. We don't want to overwrite BIND's default behavior, but for most purposes of these templates, we recommend to set notify to `master-only`. + +* `bind9_also_notify` is a list that defines the global `also-noitfy`. As such, it can contain IPs or masters' lists, that can be set with the variables `bind9_masters` and `bind9_masters_extra` hereabove. Except if `.also_notify` or `.allow_transfer` is explicitely set for the zone, templates take advantage of the masters' lists _and_ ACLs built for `bind9_masters` and `bind9_masters_extra` to include the content of `bind9_also_notify` in the zone's `allow-transfer` directive, what would not be possible with BIND's syntax and grammar alone. Names are interpreted as masters' lists in `also-noitfy` clauses and as ACLs in `allow-transfer` ones, but the templates have defined both with the same name and content. Globally or per zone, also-notify option is useful when you have hidden NS servers. + +* `bind9_also_allow_transfer` is a variable that can contain a list of IPs, network ranges of IPs and ACL names defined with `bind9_acl`, that will be added, by default for zones we manage, to the `allow-transfer` inferred by the role, which already includes secundaries and also-notify elements, as documented hereabove. This option may be useful for some very strange configuration, where NS servers are not notified but should be allowed to transfer zones. + +* `bind9_allow_transfer` is a variable that can contain a list of IPs, network ranges of IPs and ACL names, defined with `bind9_acl`. If defined, it will cancel the mechanism previously defined to include secundaries and also-notify in allow-transfer zone's clause. Except if `.allow_transfer` is defined for the zone, the content of `bind9_allow_transfer` and only this will populate the `allow-transfer` zone's clause. + +Zone by zone, in `bind9_zones_static` as well as in `bind9_zones_dynamic` list's elements, the following zone configuration parameters can be defined: + +* `.allow-query`: a list of IPs and/or acls to restrict the clients that can ask for the zone. Default value is `any`. (breaks the internet if you publish an NS record: use with care, only for private zones) +* `.type`: that defines de BIND9 type of zone: `master`, `slave`, `forward`, `stub` +* `.masters`: can be defined for the zones we are slave for. You can put there anything that BIND9 accepts but, to take advantage of this role to avoid data duplication, we recommend to declare all your NS hosts in `bind9_masters` and `bind9_masters_extra`, and reference them by name. +* `.slaves`: can be defined for zones we are master for. It has a similar structure than `bind9_slaves`, that it will overwrite for the zone. The hosts it contains will be allowed for transfer, except if the parameter `.allow_transfer` hereafter is defined. +* `.notify`: `explicit`, `yes` or `no` (`master-only` has no really useful for a single zone). Sets notification behavior for the zone, +* `.also_notify`: can be defined zone by zone we are master for, with a similar structure than `bind9_also_notify`, that it will overwrite for the zone. and the hosts it contains will be allowed for transfer, except if the parameter `.allow_transfer` hereafter is defined. +* `.also_allow_transfer`: is a list similar to an ACL, that will overwrite `bind9_also_allow_transfer` if defined, wich will be added to the `allow-transfer` statement content inferred by the role as described hereabove. +* `.allow_transfer`: is a list similar to an ACL, that will overwrite `bind9_allow_transfer` for the zone. Its content and only this will populate the `allow-transfer` zone's clause. + +Finally, note that this set of templates no longer uses several variables that use the default templets, such as `bind9_recursor` or `bind9_our_neighbors`, for instance. However, `bind9_authoritative`, whilst not used in the templates is tested by the role as conditionnal of several tasks. Therefore, it _must_ be set to true (as does de defaults' definition). + +### Default templates and other roles's variables + +Default templates have evolved with the role and try to set all kind of BIND9 configuration, as authoritative, resolver or forwarder. However, as initially there was no per zone BIND configuration, they have a different logic. + +See also [`defaults/main.yml`](defaults/main.yml) for a list of role's variables, including those which are used by default templates and not by `strict_authoritative/` ones. + + +## Dependencies + +For the XMPP notification feature, `python-xmpp` needs to be installed. Testing & Development --------------------- diff --git a/defaults/main.yml b/defaults/main.yml index a052a75..4800d58 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -7,11 +7,36 @@ bind9_group: bind # Listen on IPv6 interfaces bind9_ipv6: yes +# bind9_templates: Directory for bind9 files templates +# The role can handle different sets of templates for bind and zones configuration. +# It presently proposes two sets of templates: +# +# * the defaults one, "", wich is a general purpose configuration set, that has evolved with the role. +# It's files live in {{ role_path }}/templates/ directory +# * a second new set for a strict authoritative bind NS server: `strict_authoritative` It accepts DNS queries +# only for zones it is authoritative for. Templates try to be smart: `allow-transfer` for secunday NS servers +# and `notify-also` for hidden slaves are automatically set, and can be overwitten zone by zone, as well as +# `allow-query` and `notify` clauses. +# It's files live in {{ role_path }}/templates/strict_authoritative/ directory +# Note that several default variables `bind9_*` have different meanings than with default templates' set. +# +# bind9_templates must be set as an absolute directory or relative to the `templates` directory of the role, and +# must include it's trailing "/". For instance, for the `strict_authoritative` set of templates, you can define: +# +# bind9_templates: strict_authoritative/ +# +# You can design and set your own templates (PRs welcome!), for example with: +# bind9_templates: "{{ playbook_dir }}/host_vars//templates/" +bind9_templates: "" + # Run bind as a DNS recursor? +# variable used only by default templates, not strict_authoritative bind9_recursor: no # Run bind as authoritative nameserver? -bind9_authoritative: no +# variable used by default templates and as conditionnal of several tasks +# If using `strict_authoritative/` templates, this variable _must_ be true +bind9_authoritative: "{{ true if bind9_templates == 'strict_authoritative/' else false }}" # run bind with forwarding? bind9_forward: no @@ -35,12 +60,17 @@ bind9_notify_explicit: no # Default zone type bind9_zone_type: master +## //!\\ Several of the following variables have different meanings or (no meaning at all) depending on the templates' set you use +## See here after bind9_template variable. + # Permitted hosts/networks for recursion (when configured as recursor) +# variable used only by default templates, not strict_authoritative bind9_our_networks: - localhost - localnets # Permitted hosts/networks for zone transfers +# variable used only by default templates, not strict_authoritative bind9_our_neighbors: - localhost - localnets @@ -49,21 +79,53 @@ bind9_our_neighbors: bind9_rndc_algorithm: hmac-md5 # bind9_rndc_key: -# Global primaries for all zones (if configured as secondary) -# bind9_masters: -# - name: ns-primary -# addresses: -# - 1.2.3.4 - -# Primaries for particular zones (if configured as secondary) -# bind9_masters_extra: -# - name: ns-primary -# addresses: -# - 1.2.3.4 - -# Global secondaries for all zones (if configured as primary) -# bind9_slaves: -# - 1.2.3.4 +# Global primaries for all zones (if configured as secondary), default masters if not defined in the zone +# bind9_masters: +# - name: ns-primary +# addresses: +# - 1.2.3.4 + +# Primaries for particular zones (if configured as secondary), that can also be used in also-notify directives +# bind9_masters_extra: +# - name: "ns-primary" +# addresses: +# - 1.2.3.4 +# - name: ... +# addresses: +# - ... + +# Note that the role wil create masters lists _as well as_ ACLs for each element of `bind9_masters` and `bind9_masters_extra` +# allowing the magic to be able to put the same _names_ in the following parameters + +# Global secondaries for all zones (if configured as primary), default slaves if not specifically defined for the zone +# bind9_slaves: +# - 1.2.3.4 +# - ns-primary +# - ... +# This variable, that can be overwritten zone by zone (see README) is mainly used to build the `allow-transfer` clause of +# each zone. +# Notice that we set here the name `ns-primary` defined above. This wouldn't be possible in BIND9 configuration, if +# `ns-primary` is a masters list. Here, for slaves, i.e. to set `allow-transfer` at the masters level, we are in fact +# referring to the ACL weith the same name. + +# bind9_acl: +# undefined by default, this variable allows to define a set of access control lists (ACL) to use in slaves, allow-query +# or allow-transfer definitions. In YAML, `bind9_acl` has the same format as `bind9_masters`, except that, morover IPs, it can +# contain networks definitions (IP/MASK). + +## The following variables are default values for all zones, that can be overwritten zone by zone. + +# bind9_also_notify: +# undefined by default, a list of IPs or masters lists that defines the global `also-notify` clause in configuration. +# By default, `bind9_also_notify` items are automatically included in `allow-transfer` clause in each zone. + +# bind9_also_allow_transfer: +# As stated above, by default, slaves and also-notify hosts are automatically included in the allow-transfer clauses of zones. +# You can define here any _additional_ IP or ACL you would like, by default, to also allow transfer. + +# bind9_allow_transfer: +# Defining this variables bypasses the previous mechanism of including slaves and also-notify hosts in the allow-transfer clause +# of the zone in its master servers, and sets the `allow-transfer` to its content. # Enable BIND's XML statistics-channels (for monitoring purposes) bind9_statistics_enabled: False @@ -75,6 +137,11 @@ bind9_statistics_enabled: False bind9_zones_dynamic: [] bind9_zones_static: [] +# With this value, the `copy` module will look for zone files in `files/bind/zones/` in the playbook directory +bind9_zone_files: bind/zones/ +# Overwrite, for instance if you want to put your db.* zone files in your host vars: +# bind9_zone_files: '{{ playbook_dir }}/host_vars/{{ ansible_hostname }}/files/bind/zones/' + # Authoritative include files bind9_authoritative_includes: [] @@ -111,12 +178,6 @@ bind9_packages: - bind9 - dnsutils -# Directory for bind9 files templates -bind9_templates: "" -# The default value takes templates form the {{ role_path }}/templates/ directory of the role -# You can set your own templates, for example with: -# bind9_templates: "{{ playbook_dir }}/host_vars//templates/" - # Logging bind9_named_logging: False bind9_log_path: /var/log/bind diff --git a/meta/main.yml b/meta/main.yml index 2483dbc..3dd2d6d 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -5,7 +5,7 @@ galaxy_info: description: Role to install and maintain the Bind9 nameserver on Debian company: systemli.org license: GPLv3 - min_ansible_version: "2.4" + min_ansible_version: '2.10' galaxy_tags: - bind9 - dns diff --git a/tasks/main.yml b/tasks/main.yml index 11d6ffe..d1755d6 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -16,7 +16,7 @@ notify: - restart bind9 -- name: Setup logs +- name: bind9 logs configuration block: - name: ensure existence of the log directory file: @@ -144,6 +144,19 @@ - item.type|default(bind9_zone_type) == 'master' - item.update_keyfile|default() +- name: view zones + debug: + var: item + verbosity: 2 + with_items: + - '{{ bind9_zones_dynamic | union( bind9_zones_static ) }}' + when: + - bind9_authoritative|default() + - bind9_dnssec|default() or item.dnssec|default(bind9_dnssec_zones_default_enabled) + - item.dnssec|default(bind9_dnssec_zones_default_enabled) + tags: + - role:bind9:dnssec + # TODO: DNSSEC: implement key rollover - name: determine if DNSSEC keys for zones already exist find: @@ -151,7 +164,7 @@ patterns: "K{{ item.name }}.+008+*" register: bind9_reg_dnssec_keys_tmp with_items: - - "{{ bind9_zones_dynamic }} + {{ bind9_zones_static }}" + - '{{ bind9_zones_dynamic | union( bind9_zones_static ) }}' when: - bind9_authoritative|default() - bind9_dnssec|default() or item.dnssec|default(bind9_dnssec_zones_default_enabled) @@ -160,7 +173,7 @@ - role:bind9:dnssec # Filter out all skipped results (e.g. if item.dnssec is set to False) -- name: Set bind9_reg_dnssec_keys +- name: set bind9_reg_dnssec_keys fact set_fact: bind9_reg_dnssec_keys: "{{ bind9_reg_dnssec_keys_tmp.results|selectattr('skipped', 'undefined')|list }}" @@ -315,7 +328,7 @@ - name: install static bind9 zone files copy: - src: bind/zones/db.{{ item.name }} + src: '{{ bind9_zone_files }}db.{{ item.name }}' dest: /etc/bind/zones/db.{{ item.name }} owner: root group: "{{ bind9_group }}" diff --git a/templates/bind/named.conf.local.j2 b/templates/bind/named.conf.local.j2 index 1bc87fb..a2d5ebb 100644 --- a/templates/bind/named.conf.local.j2 +++ b/templates/bind/named.conf.local.j2 @@ -5,8 +5,14 @@ // Consider adding the 1918 zones here, if they are not used in your // organization //include "/etc/bind/zones.rfc1918"; +{% if bind9_statistics_enabled %} +statistics-channels { + inet 127.0.0.1 port 8053 allow { 127.0.0.1; }; +}; +{% endif %} {% if bind9_masters|default() %} +// masters for zones and allow-notify {% for master in bind9_masters %} masters {{ master.name }} { {% for addr in master.addresses %} @@ -24,11 +30,16 @@ masters {{ master.name }} { }; {% endfor %} {% endif %} +{% if bind9_acl is defined %} -{% if bind9_statistics_enabled %} -statistics-channels { - inet 127.0.0.1 port 8053 allow { 127.0.0.1; }; + // Custom acls +{% for acl_item in bind9_acl %} +acl {{ acl_item.name }} { +{% for item_address in acl_item.addresses %} + {{ item_address }}; +{% endfor %} }; +{% endfor %} {% endif %} // The following zones are managed by this DNS Server // @@ -38,44 +49,63 @@ zone "{{ zone.name }}" { type {{ zone_type }}; {% if zone_type == 'master' %} file "/etc/bind/zones/db.{{ zone.name }}"; -{% if bind9_notify_explicit|default() %} +{% if zone.allow_query is defined %} + allow-query { +{% for allow_query_item in zone.allow_query %} + {{ allow_query_item }}; +{% endfor %} + }; +{% endif %} +{% if zone.allow_transfer is defined %} + allow-transfer { +{% for allow_transfer_item in zone.allow_transfer %} + {{ allow_transfer_item }}; +{% endfor %} + }; +{% endif %} +{% if bind9_notify_explicit %} notify explicit; -{% elif zone.notify|default(true) %} - notify yes; +{% elif zone.notify | default(true) %} + notify {{ zone.notify | default(true) | ternary ('yes','no') }}; {% endif %} -{% if (bind9_dnssec|default() or zone.dnssec|default()) and zone.dnssec|default(bind9_dnssec_zones_default_enabled) %} +{% if zone.also_notify is defined %} + also-notify { +{% for also_notify_item in zone.also_notify %} + {{ also_notify_item }}; +{% endfor %} + }; +{% endif %} +{% if (bind9_dnssec or zone.dnssec | default() ) and zone.dnssec | default( bind9_dnssec_zones_default_enabled ) %} auto-dnssec maintain; inline-signing yes; {% endif %} -{% if zone.update_policy_grant|default() %} +{% if zone.update_policy_grant | default() %} update-policy { grant {{ zone.name }}_ddns_update {{ zone.update_policy_grant }}; }; {% endif %} {% elif zone_type == 'slave' %} file "/var/lib/bind/db.{{ zone.name }}"; -{% if zone.masters|default() or bind9_masters|default() %} +{% if zone.masters | default() or bind9_masters | default() %} notify no; masters { -{% if zone.masters|default() %} +{% if zone.masters | default() %} {% for master in zone.masters %} {{ master }}; {% endfor %} -{% elif bind9_masters|default() %} +{% elif bind9_masters | default() %} {% for master in bind9_masters %} {{ master.name }}; {% endfor %} {% endif %} }; {% endif %} -{% else %} -{% if zone_type == 'forward' %} +{% elif zone_type == 'forward' %} forwarders { -{% for fwd in zone.forwarders %} +{% for fwd in zone.forwarders %} {{ fwd }}; -{% endfor %} +{% endfor %} }; -{% endif %} {% endif %} }; {% endfor %} diff --git a/templates/bind/named.conf.options.j2 b/templates/bind/named.conf.options.j2 index e0d7446..a0a33b3 100644 --- a/templates/bind/named.conf.options.j2 +++ b/templates/bind/named.conf.options.j2 @@ -1,3 +1,6 @@ +// BIND 9 Configuration - generated by systemli.bind9 ansible role +// DO NOT edit, change your ansible config and re-run your ansible playbooks + options { directory "/var/cache/bind"; @@ -12,9 +15,9 @@ options { {% if bind9_forward|default() %} forwarders { - {% for forwarder in bind9_forward_servers %} +{% for forwarder in bind9_forward_servers %} {{ forwarder }}; - {% endfor %} +{% endfor %} }; {% endif %} @@ -89,8 +92,8 @@ acl our_neighbors { {% endfor %} {% endif %} }; - {% if bind9_named_logging %} + logging { channel bind_log { file "{{ bind9_log_path }}/bind.log" versions {{ bind9_log_versions }} size {{ bind9_log_size }}; @@ -99,8 +102,8 @@ logging { print-severity yes; print-time yes; }; - {% for category in bind9_log_categories %} +{% for category in bind9_log_categories %} category {{ category.name }} { {{ category.destination }}; }; - {% endfor %} +{% endfor %} }; {% endif %} diff --git a/templates/strict_authoritative/bind/default.j2 b/templates/strict_authoritative/bind/default.j2 new file mode 120000 index 0000000..0bab1c2 --- /dev/null +++ b/templates/strict_authoritative/bind/default.j2 @@ -0,0 +1 @@ +../../bind/default.j2 \ No newline at end of file diff --git a/templates/strict_authoritative/bind/named.conf.local.j2 b/templates/strict_authoritative/bind/named.conf.local.j2 new file mode 100644 index 0000000..e467678 --- /dev/null +++ b/templates/strict_authoritative/bind/named.conf.local.j2 @@ -0,0 +1,127 @@ +// BIND 9 Configuration - named.conf.local - generated by systemli.bind9 ansible role +// DO NOT edit, change your ansible config and re-run your ansible playbooks +// + +// Consider adding the 1918 zones here, if they are not used in your +// organization +//include "/etc/bind/zones.rfc1918"; + +{% if bind9_statistics_enabled %} + +statistics-channels { + inet 127.0.0.1 port 8053 allow { 127.0.0.1; }; +}; +{% endif %} +{% if bind9_masters is defined or bind9_masters_extra is defined %} + +// masters lists for masters' secondary zones and also-notify statements +// and ACLs with same name and content, to be used in allow-transfer clauses +{% for master in bind9_masters | default ([]) + bind9_masters_extra | default ([]) %} +masters {{ master.name }} { +{% for addr in master.addresses %} + {{ addr }}; +{% endfor %} +}; +acl {{ master.name }} { +{% for addr in master.addresses %} + {{ addr }}; +{% endfor %} +}; + +{% endfor %} +{% endif %} +{% if bind9_acl is defined %} + + // Custom acls +{% for acl_item in bind9_acl %} +acl {{ acl_item.name }} { +{% for acl_address in acl_item.addresses %} + {{ acl_address }}; +{% endfor %} +}; +{% endfor %} +{% endif %} + +// The following zones are managed by this DNS Server // +{% for zone in ( bind9_zones_static + bind9_zones_dynamic ) | sort( attribute='name' ) %} +{% set zone_type = zone.type | default( bind9_zone_type | default( 'master' ) ) %} +zone "{{ zone.name }}" { + type {{ zone_type }}; +{# ############################### Type zone specific statements ####################################### #} +{% if zone_type == 'master' %} + file "/etc/bind/zones/db.{{ zone.name }}"; +{% elif zone_type == 'slave' %} + file "/var/lib/bind/db.{{ zone.name }}"; +{% if zone.masters is defined or bind9_masters is defined %} + masters { +{% if zone.masters is defined %} +{% for master in zone.masters %} + {{ master }}; +{% endfor %} +{% else %} {# so bind9_masters is defined #} +{% for master in bind9_masters %} + {{ master.name }}; +{% endfor %} +{% endif %} + }; +{% endif %} +{% elif zone_type == 'forward' %} + forwarders { +{% for fwd in zone.forwarders %} + {{ fwd }}; +{% endfor %} + }; +{% endif %} +{# ############################### Common statements to all zone types ####################################### #} + allow-query { +{% if zone.allow_query is defined and zone.allow_query | length() > 0 %} +{% for allow_query_item in zone.allow_query | list %} + {{ allow_query_item }}; +{% endfor %} + }; +{% else %} + any; + }; +{% endif %} +{% if zone.notify is defined %} + notify {{ zone.notify }}; +{% endif %} +{% set zone_also_notify = zone.also_notify | default( bind9_also_notify | default( [] ) ) %} +{% if zone.also_notify is defined and zone.also_notify | length() > 0 %} + also-notify { +{% for also_notify_item in zone.also_notify | list %} + {{ also_notify_item }}; +{% endfor %} + }; +{% endif %} +{% set zone_also_allow_transfer = zone.also_allow_transfer | default( bind9_also_allow_transfer | default( [] ) ) %} +{# ############################### Primary zones must consider secundaries ########################################### #} +{% if zone_type == 'master' %} +{% set zone_calc_allow_transfer = zone.slaves | default( bind9_slaves | default( [] ) ) | union( zone_also_notify | union ( zone_also_allow_transfer ) ) %} +{% else %} +{% set zone_calc_allow_transfer = zone_also_notify | union( zone_also_allow_transfer ) %} +{% endif %} +{% set zone_allow_transfer = zone.allow_transfer | default ( bind9_allow_transfer | default( ( zone_calc_allow_transfer ) | unique ) ) %} +{% if zone_allow_transfer | length > 0 %} + + // allow transfer from secundaries, also-notify hosts and other allow-transfer specified + allow-transfer { +{% for allow_transfer_item in zone_allow_transfer %} + {{ allow_transfer_item }}; +{% endfor %} + }; +{% endif %} +{# ############################### Primary zones are concerned by dnssec ########################################### #} +{% if zone_type == 'master' %} +{% if ( bind9_dnssec or zone.dnssec | default() ) and zone.dnssec | default( bind9_dnssec_zones_default_enabled ) %} + auto-dnssec maintain; + inline-signing yes; +{% endif %} +{% if zone.update_policy_grant | default() %} + update-policy { + grant {{ zone.name }}_ddns_update {{ zone.update_policy_grant }}; + }; +{% endif %} +{% endif %} +}; +{% endfor %} \ No newline at end of file diff --git a/templates/strict_authoritative/bind/named.conf.options.j2 b/templates/strict_authoritative/bind/named.conf.options.j2 new file mode 100644 index 0000000..76e99d6 --- /dev/null +++ b/templates/strict_authoritative/bind/named.conf.options.j2 @@ -0,0 +1,91 @@ +// BIND 9 Configuration - named.conf.options - generated by systemli.bind9 ansible role +// DO NOT edit, change your ansible config and re-run your ansible playbooks + +options { + directory "/var/cache/bind"; + + // If there is a firewall between you and nameservers you want + // to talk to, you may need to fix the firewall to allow multiple + // ports to talk. See http://www.kb.cert.org/vuls/id/800113 + + // If your ISP provided one or more IP addresses for stable + // nameservers, you probably want to use them as forwarders. + // Uncomment the following block, and insert the addresses replacing + // the all-0's placeholder. + +{% if bind9_forward|default() %} + forwarders { +{% for forwarder in bind9_forward_servers %} + {{ forwarder }}; +{% endfor %} + }; +{% endif %} + + //======================================================================== + // If BIND logs error messages about the root key being expired, + // you will need to update your keys. See https://www.isc.org/bind-keys + //======================================================================== + dnssec-validation {{ bind9_dnssec_validation }}; +{% if ansible_distribution_major_version|int >= 11 %} + qname-minimization {{ bind9_qname_minimization }}; +{% endif %} + auth-nxdomain no; # conform to RFC1035 + listen-on-v6 { any; }; + + // Yes, we are strict authoritative: only allow per zone. + recursion no; + allow-query { none; }; + allow-transfer { none; }; + allow-recursion { none; }; + +{% if bind9_notify is defined %} +{% if bind9_notify == 'explicit' %} + + // Notify only nameservers from also-notify, not from NS RRs in zones + notify explicit; +{% else %} + notify {{ bind9_notify | ternary ('yes','no') }}; +{% endif %} +{% endif %} +{% if bind9_also_notify is defined and bind9_also_notify | length() > 0 %} + also-notify { +{% for notify_item in bind9_also_notify | list %} + "{{ notify_item }}"; +{% endfor %} + }; +{% endif %} +{% if bind9_dnssec|default() %} + + // Look here for DNSSEC keys + key-directory "/etc/bind/keys"; +{% endif %} +}; +{% if bind9_zones_static | selectattr( 'update_keyfile', 'defined' ) | list | default() %} +{% for zone in bind9_zones_static | selectattr('update_keyfile','defined') | list | default([]) %} +{% if zone_type | default( bind9_zone_type | default('master') ) == 'master' %} +{% if loop.first %} + +// The following keys are used for dynamic DNS updates +{% endif %} +key "{{ zone.name }}_ddns_update" { + algorithm {{ zone.update_key_algorithm|default('hmac-sha512') }}; + secret "{{ zone.update_key_secret|default() }}"; +}; +{% endif %} +{% endfor %} +{% endif %} +{% if bind9_named_logging %} + +logging { + channel bind_log { + file "{{ bind9_log_path }}/bind.log" versions {{ bind9_log_versions }} size {{ bind9_log_size }}; + severity {{ bind9_log_severity }}; + print-category yes; + print-severity yes; + print-time yes; + }; +{% for category in bind9_log_categories %} + category {{ category.name }} { {{ category.destination }}; }; +{% endfor %} +}; +{% endif %} diff --git a/templates/strict_authoritative/bind/rndc.key.j2 b/templates/strict_authoritative/bind/rndc.key.j2 new file mode 120000 index 0000000..a23d177 --- /dev/null +++ b/templates/strict_authoritative/bind/rndc.key.j2 @@ -0,0 +1 @@ +../../bind/rndc.key.j2 \ No newline at end of file diff --git a/templates/strict_authoritative/bind/zones b/templates/strict_authoritative/bind/zones new file mode 120000 index 0000000..5b64f95 --- /dev/null +++ b/templates/strict_authoritative/bind/zones @@ -0,0 +1 @@ +../../bind/zones \ No newline at end of file diff --git a/templates/strict_authoritative/logrotate.d b/templates/strict_authoritative/logrotate.d new file mode 120000 index 0000000..0d2c3aa --- /dev/null +++ b/templates/strict_authoritative/logrotate.d @@ -0,0 +1 @@ +../logrotate.d \ No newline at end of file