Initial Commit

This commit is contained in:
Markus Pesch 2022-02-21 21:41:31 +01:00
commit 57dc81f353
Signed by: volker.raschek
GPG Key ID: 852BCC170D81A982
15 changed files with 779 additions and 0 deletions

29
README.md Normal file
View File

@ -0,0 +1,29 @@
# bind
With following role can be bind installed and configured.
## Supported distributions
- Arch Linux
- Rocky Linux 8
- Ubuntu 20.04
## Features
- Installing bind/named
- Configuring bind/named
- TSIG-Keys
- Simple Zones
- Zones with different views
- DYNDNS
## Configuring
In the default directory are examples how to configure `named`. Copy the
defaults into your `host_vars` or `group_vars` and adapt the examples.
## Individual host-templates
Each host has his own zones templates. Store the template in
`templates/<hostname>/etc/named/zones/<name-of-view>/zone.conf`. For example:
`templates/ns1.example.com/etc/named/zones/internal/db.de.example`.

93
defaults/main.yml Normal file
View File

@ -0,0 +1,93 @@
---
bind9_acls:
- name: internalnets
permissions: []
# - "111.222.111.222"
bind9_logging:
categories:
- name: "security"
channels:
- "security_file"
channels:
- name: "security_file"
file:
path: "/var/log/named/security.log"
options: "versions 3 size 30m"
severity: "dynamic"
print_times: "yes"
bind9_options:
allow_query: []
allow_query_on: []
allow_query_cache: []
allow_query_cache_on: []
allow_recursion:
- "localhost"
- "localnets"
- "internalnets"
allow_recursion_on: []
allow_transfer: []
allow_update: []
allow_update_forwarding: []
auth_nxdomain: false
blackhole: []
dnssec_validations: true
forwarders:
- "8.8.8.8" # Google IPv4
- "8.8.4.4" # Google IPv4
- "2001:4860:4860::8888" # Google IPv6
- "2001:4860:4860::8844" # Google IPv6
- "208.67.222.222" # OpenDNS IPv4
- "208.67.220.220" # OpenDNS IPv4
- "2620:0:ccc::2" # OpenDNS IPv6
- "2620:0:ccd::2" # OpenDNS IPv6
interface_interval: 0
listen_on_ipv4:
- "127.0.0.1"
listen_on_ipv6:
- "::1"
max_transfer_time: "60"
minimal_responses: "no"
notify: "yes"
recursion: "yes"
transfer_format: "many-answers"
bind9_tsigkeys: []
# - name: "name"
# algorithm: "algorithm"
# secret: "secret"
bind9_views: []
# - name: external
# match_clients:
# - "!internalnets"
# - "any"
# zones:
# - allow_notify: []
# allow_query:
# - "any"
# allow_query_on: []
# allow_update: []
# allow_update_forwarding: []
# allow_transfer: []
# file: zones/external/db.local.example
# origin: "example.local."
# type: master
# - name: internal
# match_clients:
# - "!192.168.178.1"
# - "internalnets"
# - "127.0.0.0/8"
# zones:
# - allow_notify: []
# allow_query:
# - "any"
# allow_query_on: []
# allow_update: []
# allow_update_forwarding: []
# allow_transfer: []
# file: zones/internal/db.local.example
# origin: "example.local."
# type: master

7
handlers/main.yml Normal file
View File

@ -0,0 +1,7 @@
---
- name: restart named
systemd:
name: "{{ bind_service_name }}"
state: restarted
daemon_reload: true

23
meta/main.yml Normal file
View File

@ -0,0 +1,23 @@
galaxy_info:
author: Markus Pesch
description: set up native bind
company: Cryptic Systems
license: MIT
min_ansible_version: 2.1
platforms:
- name: Archlinux
versions:
- all
- name: Ubuntu
versions:
- 20.04
- name: RockyLinux
versions:
- 8.5
galaxy_tags:
- named
- bind
- dyndns
dependencies: []

70
tasks/main.yml Normal file
View File

@ -0,0 +1,70 @@
---
- name: include special distribution-dependent variables
include_vars: "{{ ansible_os_family }}.yml"
- name: install bind and dependencies
package:
name: "{{ item }}"
state: present
with_items: "{{ bind_package_names }}"
- name: create logging directory
file:
path: "{{ bind_log_directory }}"
owner: "{{ bind_unix_user }}"
group: "{{ bind_unix_group }}"
mode: 0755
state: directory
recurse: yes
- name: remove existing journal files
block:
- name: find existing journal files
find:
path: "{{ bind_config_directory }}"
recurse: yes
patterns: "*.jnl"
register: files_to_delete
- name: delete existing journal files
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ files_to_delete.files }}"
# - name: copy zone files
# include_tasks: copy_zone_files.yml
# with_items:
# - "{{ bind9_views }}"
# loop_control:
# loop_var: view
- name: template zone files
include_tasks: template_zone_files.yml
with_items:
- "{{ bind9_views }}"
loop_control:
loop_var: view
- name: set up global bind config
template:
src: "{{ item }}.j2"
dest: "/etc/{{ item }}"
owner: "{{ bind_unix_user }}"
group: "{{ bind_unix_group }}"
mode: 0644
with_items:
- named.conf
- named/named.conf.acl
- named/named.conf.logging
- named/named.conf.options
- named/named.conf.tsigkeys
- named/named.conf.views
notify: restart named
- name: start and enabled named
systemd:
name: named
state: started
enabled: yes

View File

@ -0,0 +1,27 @@
---
- name: create directory for zone {{ zone.file | dirname }}
file:
path: "{{ bind_config_directory }}/{{ zone.file | dirname }}"
owner: "{{ bind_unix_user }}"
group: "{{ bind_unix_group }}"
mode: 0755
state: directory
with_items:
- "{{ view.zones }}"
loop_control:
loop_var: zone
- name: "template view {{ view.name }}"
template:
src: "{{ inventory_hostname }}/etc/named/{{ zone.file }}.j2"
dest: "{{ bind_config_directory }}/{{ zone.file }}"
owner: "{{ bind_unix_user }}"
group: "{{ bind_unix_group }}"
mode: 0644
with_items:
- "{{ view.zones }}"
loop_control:
loop_var: zone
when: zone.type == 'master'
notify: restart named

12
templates/named.conf.j2 Normal file
View File

@ -0,0 +1,12 @@
# zone "." IN {
# type hint;
# file "named.ca";
# };
include "/etc/named/named.conf.acl";
include "/etc/named/named.conf.logging";
include "/etc/named/named.conf.options";
include "/etc/named/named.conf.tsigkeys";
include "/etc/named/named.conf.views";
# include "/etc/named.rfc1912.zones";
# include "/etc/named.root.key";

View File

@ -0,0 +1,12 @@
#
# {{ ansible_managed }}
#
{% for acl in bind9_acls %}
acl "{{ acl.name }}" {
{% for permission in acl.permissions %}
{{ permission }};
{% endfor %}
};
{% endfor %}

View File

@ -0,0 +1,31 @@
#
# {{ ansible_managed }}
#
logging {
{% for category in bind9_logging.categories %}
category {{ category.name }} {
{% for channel in category.channels %}
{{ channel }};
{% endfor %}
};
{% endfor %}
{% for channel in bind9_logging.channels %}
channel {{ channel.name }} {
{%if channel.file.path is defined and channel.file.options is defined %}
file "{{ channel.file.path }}" {{ channel.file.options }};
{% endif %}
{%if channel.file.path is defined and channel.file.options is not defined %}
file "{{ channel.file.path }}";
{% endif %}
{%if channel.severity is defined %}
severity {{ channel.severity }};
{% endif %}
print-time yes;
};
{% endfor %}
};

View File

@ -0,0 +1,233 @@
#
# {{ ansible_managed }}
#
options {
# This specifies which hosts are allowed to ask ordinary DNS questions.
# allow-query may also be specified in the zone statement, in which case it
# overrides the options allow-query statement. If not specified, the default
# is to allow queries from all hosts.
# https://bind9.readthedocs.io/en/latest/reference.html#access-control
{% if bind9_options.allow_query is defined and bind9_options.allow_query | length > 0 %}
allow-query {
{% for entry in bind9_options.allow_query %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-query {};
{% endif %}
# This specifies which hosts are allowed to get answers from the cache. If
# allow-recursion is not set, BIND checks to see if the following parameters
# are set, in order: allow-query-cache and allow-query (unless recursion no;
# is set). If neither of those parameters is set, the default (localnets;
# localhost;) is used.
# https://bind9.readthedocs.io/en/latest/reference.html#access-control
{% if bind9_options.allow_query_on is defined and bind9_options.allow_query_on | length > 0 %}
allow-query-on {
{% for entry in bind9_options.allow_query_on %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-query-on {};
{% endif %}
# This specifies which hosts are allowed to get answers from the cache. If
# allow-recursion is not set, BIND checks to see if the following parameters
# are set, in order: allow-query-cache and allow-query (unless recursion no;
# is set). If neither of those parameters is set, the default (localnets;
# localhost;) is used.
# https://bind9.readthedocs.io/en/latest/reference.html#access-control
{% if bind9_options.allow_query_cache is defined and bind9_options.allow_query_cache | length > 0 %}
allow-query-cache {
{% for entry in bind9_options.allow_query_cache %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-query-cache {};
{% endif %}
# This specifies which local addresses can send answers from the cache. If
# allow-query-cache-on is not set, then allow-recursion-on is used if set.
# Otherwise, the default is to allow cache responses to be sent from any
# address. Note: both allow-query-cache and allow-query-cache-on must be
# satisfied before a cache response can be sent; a client that is blocked by
# one cannot be allowed by the other.
# https://bind9.readthedocs.io/en/latest/reference.html#access-control
{% if bind9_options.allow_query_cache_on is defined and bind9_options.allow_query_cache_on | length > 0 %}
allow-query-cache-on {
{% for entry in bind9_options.allow_query_cache_on %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-query-cache-on {};
{% endif %}
# This specifies which hosts are allowed to receive zone transfers from the
# server. allow-transfer may also be specified in the zone statement, in which
# case it overrides the allow-transfer statement set in options or view. If
# not specified, the default is to allow transfers to all hosts.
# The transport level limitations can also be specified. In particular, zone
# transfers can be restricted to a specific port and/or DNS transport protocol
# by using the options port and transport. Either option can be specified; if
# both are used, both constraints must be satisfied in order for the transfer
# to be allowed. Zone transfers are currently only possible via the TCP and
# TLS transports.
{% if bind9_options.allow_recursion is defined and bind9_options.allow_recursion | length > 0 %}
allow-recursion {
{% for entry in bind9_options.allow_recursion %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-recursion {};
{% endif %}
# allow-recursion-on defines the server interface(s) from which
# recursive queries are accepted and can be useful where a server is
# multi-homed, perhaps in conjunction with a view clause. Defaults to
# allow-recursion-on {any;}; meaning that recursive queries are
# accepted on any server interface.
#
# NOTE:
# - The statement is only relevant if recursion yes; is present or
# defaulted.
# - The statements may be used in a view or a global options clause.
{% if bind9_options.allow_recursion_on is defined and bind9_options.allow_recursion_on | length > 0 %}
allow-recursion-on {
{% for entry in bind9_options.allow_recursion_on %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-recursion-on {};
{% endif %}
# allow-transfer defines a match list e.g. IP address(es) that are
# allowed to transfer (copy) the zone information from the server
# (master or slave for the zone). The default behaviour is to allow
# zone transfers to any host. While on its face this may seem an
# excessively friendly default, DNS data is essentially public (that's
# why its there) and the bad guys can get all of it anyway. However if
# the thought of anyone being able to transfer your precious zone file
# is repugnant, or (and this is far more significant) you are
# concerned about possible DoS attack initiated by XFER requests, then
# use the following policy.
#
# NOTE:
# - This statement may be used in a zone, view or global options clause.
{% if bind9_options.allow_transfer is defined and bind9_options.allow_transfer | length > 0 %}
allow-transfer {
{% for entry in bind9_options.allow_transfer %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-transfer {};
{% endif %}
# When set in the zone statement for a primary zone, this specifies which
# hosts are allowed to submit Dynamic DNS updates to that zone. The default is
# to deny updates from all hosts.
# Note that allowing updates based on the requestors IP address is insecure;
# see Dynamic Update Security for details.
{% if bind9_options.allow_update is defined and bind9_options.allow_update | length > 0 %}
allow-update {
{% for entry in bind9_options.allow_update %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-update {};
{% endif %}
# When set in the zone statement for a secondary zone, this specifies which
# hosts are allowed to submit Dynamic DNS updates and have them be forwarded
# to the primary. The default is { none; }, which means that no update
# forwarding is performed.
# To enable update forwarding, specify allow-update-forwarding { any; }; in
# the zone statement. Specifying values other than { none; } or { any; } is
# usually counterproductive; the responsibility for update access control
# should rest with the primary server, not the secondary.
{% if bind9_options.allow_update_forwarding is defined and bind9_options.allow_update_forwarding | length > 0 %}
allow-update-forwarding {
{% for entry in bind9_options.allow_update_forwarding %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-update-forwarding {};
{% endif %}
directory "/etc/named";
dnssec-validation {{ bind9_options.dnssec_validation | default('no') }};
# dump-file "/var/bind/named.dump";
{% if bind9_options.forwarders is defined and bind9_options.forwarders | length > 0 %}
forwarders {
{% for forwarder in bind9_options.forwarders %}
{{ forwarder }};
{% endfor %}
};
{% else %}
# forwarders {};
{% endif %}
geoip-directory "/usr/share/GeoIP";
# This is the hostname the server should report via a query of the name
# hostname.bind with type TXT and class CHAOS. This defaults to the hostname
# of the machine hosting the name server, as found by the gethostname()
# function. The primary purpose of such queries is to identify which of a
# group of anycast servers is actually answering the queries. Specifying
# hostname none; disables processing of the queries.
# https://bind9.readthedocs.io/en/latest/reference.html?highlight=hostname#built-in-server-information-zones
hostname none;
{% if bind9_options.listen_on_ipv4 is defined and bind9_options.listen_on_ipv4 | length > 0 %}
listen-on port 53 {
{% for ip in bind9_options.listen_on_ipv4 %}
{{ ip }};
{% endfor %}
};
{% endif %}
{% if bind9_options.listen_on_ipv6 is defined and bind9_options.listen_on_ipv6 | length > 0 %}
listen-on-v6 port 53 {
{% for ip in bind9_options.listen_on_ipv6 %}
{{ ip }};
{% endfor %}
};
{% endif %}
# managed-keys-directory "/var/named/dynamic";
# memstatistics-file "/var/bind/named.memstats";
minimal-responses {{ bind9_options.minimal_responses }};
notify {{ bind9_options.notify }};
pid-file "/run/named/named.pid";
recursion {{ bind9_options.recursion }};
# statistics-file "/var/bind/named.stats";
transfer-format {{ bind9_options.transfer_format }};
# This is the version the server should report via a query of the name
# version.bind with type TXT and class CHAOS. The default is the real version
# number of this server. Specifying version none disables processing of the
# queries.
# https://bind9.readthedocs.io/en/latest/reference.html?highlight=hostname#built-in-server-information-zones
version none;
zone-statistics yes;
};

View File

@ -0,0 +1,11 @@
#
# {{ ansible_managed }}
#
{% for key in bind9_tsigkeys %}
key "{{ key.name }}" {
algorithm {{ key.algorithm }};
secret "{{ key.secret }}";
};
{% endfor %}

View File

@ -0,0 +1,191 @@
#
# {{ ansible_managed }}
#
{% for view in bind9_views %}
view "{{ view.name }}" {
match-clients {
{% for clients in view.match_clients %}
{{ clients }};
{% endfor %}
};
{% for zone in view.zones %}
zone "{{ zone.origin }}" {
# Hosts which are allowed to issue queries to the server. If not specified all
# hosts are allowed to make queries (defaults to allow-query {any;};
#
# NOTE:
# - The statements may be used in a zone, view or a global options
# clause.
{% if zone.allow_query is defined and zone.allow_query | length > 0 %}
allow-query {
{% for entry in zone.allow_query %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-query {};
{% endif %}
# allow-query-on defines the server interface(s) from which queries
# are accepted and can be useful where a server is multi-homed,
# perhaps in conjunction with a view clause. Defaults to
# allow-query-on {any;};) meaning that queries are accepted on any
# server interface.
#
# NOTE:
# - The statements may be used in a zone, view or a global options
# clause.
{% if zone.allow_query_on is defined and zone.allow_query_on | length > 0 %}
allow-query {
{% for entry in zone.allow_query_on %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-query-on {};
{% endif %}
# allow-transfer defines a match list e.g. IP address(es) that are
# allowed to transfer (copy) the zone information from the server
# (master or slave for the zone). The default behavior is to allow
# zone transfers to any host. While on its face this may seem an
# excessively friendly default, DNS data is essentially public (that's
# why its there) and the bad guys can get all of it anyway. However if
# the thought of anyone being able to transfer your precious zone file
# is repugnant, or (and this is far more significant) you are
# concerned about possible DoS attack initiated by XFER requests, then
# use the following policy.
#
# NOTE:
# - This statement may be used in a zone, view or global options clause.
{% if zone.allow_transfer is defined and zone.allow_transfer | length > 0 %}
allow-transfer {
{% for entry in zone.allow_transfer %}
key {{ entry }};
{% endfor %}
};
{% else %}
# allow-transfer {};
{% endif %}
# allow-update defines an address_match_list of hosts that are allowed
# to submit dynamic updates for master zones, and thus this statement
# enables Dynamic DNS. The default in BIND 9 is to disallow updates
# from all hosts, that is, DDNS is disabled by default. This statement
# is mutually exclusive with update-policy and applies to master zones
# only. The example shows DDNS for three zones: the first disables
# DDNS explicitly, the second uses an IP-based list, and the third
# references a key clause. The allow-update in the first zone clause
# could have been omitted since it is the default behavior. Many
# people like to be cautious in case the default mode changes.
#
# NOTE:
# - This statement may be used in a zone, view or an options clause.
{% if zone.allow_update is defined and zone.allow_update | length > 0 %}
allow-update {
{% for entry in zone.allow_update %}
key {{ entry }};
{% endfor %}
};
{% else %}
# allow-update {};
{% endif %}
# allow-update-forwarding defines a match list, for instance,
# IP address(es) that are allowed to submit dynamic updates to
# a 'slave' sever for onward transmission to a 'master'.
#
# NOTE:
# - This statement may be used in zone, view or an options clause.
{% if zone.allow_update_forwarding is defined and zone.allow_update_forwarding | length > 0 %}
allow-update-forwarding {
{% for entry in zone.allow_update_forwarding %}
{{ entry }};
{% endfor %}
};
{% else %}
# allow-update-forwarding {};
{% endif %}
# Defines the file used by the zone in quoted string format, for
# instance, "slave/example.com" - or whatever convention you use. The
# file entry is mandatory for master and hint and optional - but
# highly recommended - for slave and not required for forward zones.
# The file may be an absolute path or relative to directory.
#
# NOTE:
# - If a type Slave has a file statement then any zone transfer
# will cause it to update this file. If the slave is reloaded then
# it will read this file and immediately start answering queries for
# the domain. If no file is specified it will immediately try to
# contact the Master and initiate a zone transfer. For obvious
# reasons the Slave cannot to zone queries until this zone transfer
# is complete. If the Master is not available or the Slave fails to
# contact the Master, ffor whatever reason, the zone may be left with
# no effective Authoritative Name Servers.
file "/etc/named/{{ zone.file }}";
# master servers
# https://bind9.readthedocs.io/en/latest/manpages.html?highlight=masters#masters
{% if zone.masters is defined and zone.masters | length > 0 %}
masters {
{% for master in zone.masters %}
{{ master.ip }} key {{ master.tsigkey}};
{% endfor %}
};
{% else %}
# masters {};
{% endif %}
# notify behavior is applicable to both master zones (with
# 'type master;') and slave zones (with 'type slave;') and if
# set to 'yes' (the default) then, when a zone is loaded or
# changed, for example, after a zone transfer, NOTIFY messages
# are sent to the name servers defined in the NS records for
# the zone (except itself and the 'Primary Master' name server
# defined in the SOA record) and to any IPs listed in any
# also-notify statement.
#
# If set to 'no' NOTIFY messages are not sent.
# If set to 'explicit' NOTIFY is only sent to those IP(s) listed
# in an also-notify statement.
#
# NOTE:
# - This statement may be specified in zone, view clauses or in a
# global options clause.
notify yes;
# Zones configured for dynamic DNS may use this option to set the
# update method to be used for the zone serial number in the SOA
# record.
#
# With the default setting of serial-update-method increment;, the
# SOA serial number is incremented by one each time the zone is
# updated.
#
# When set to serial-update-method unixtime;, the SOA serial number
# is set to the number of seconds since the Unix epoch, unless the
# serial number is already greater than or equal to that value, in
# which case it is simply incremented by one.
#
# When set to serial-update-method date;, the new SOA serial number
# is the current date in the form “YYYYMMDD”, followed by two
# zeroes, unless the existing serial number is already greater than
# or equal to that value, in which case it is incremented by one.
{% if zone.serial_update_method is defined %}
serial-update-method {{ zone.serial_update_method }};
{% else %}
# serial-update-method [date | increment | unixtime ];
{% endif %}
type {{ zone.type }};
};
{% endfor %}
};
{% endfor %}

13
vars/Archlinux.yml Normal file
View File

@ -0,0 +1,13 @@
---
bind_main_config: /etc/named.conf
bind_config_directory: /etc/named
bind_log_directory: /var/log/named
bind_package_names:
- bind
bind_service_name: named
bind_unix_user: named
bind_unix_group: named

13
vars/Debian.yml Normal file
View File

@ -0,0 +1,13 @@
---
bind_main_config: /etc/named.conf
bind_config_directory: /etc/named
bind_log_directory: /var/log/named
bind_package_names:
- bind9
bind_service_name: named
bind_unix_user: bind
bind_unix_group: bind

14
vars/RedHat.yml Normal file
View File

@ -0,0 +1,14 @@
---
bind_main_config: /etc/named.conf
bind_config_directory: /etc/named
bind_log_directory: /var/log/named
bind_package_names:
- bind
- bind-utils # for dig and tsig-keygen and so on
bind_service_name: named
bind_unix_user: named
bind_unix_group: named