diff --git a/README.rst b/README.rst index dc7c4ae..5e9043e 100644 --- a/README.rst +++ b/README.rst @@ -24,9 +24,39 @@ Install the bind package and start the bind service. --------------- Manage the bind configuration file. -Zone files are not generated by this state -rather than taken from `salt://zones`. -See `pillar.example` for how to overwrite +This state can generate some basic zone files if a `records` entry is found in the +`available_zones`' declaration for the zone (see `pillar.example` for how to write these) + +Example Pillar +============== + +.. code:: yaml + + bind: + configured_zones: + example.com: + type: master + notify: False + available_zones: + example.com: + file: example.com.txt + soa: + ns: ns1.example.com # Required + contact: hostmaster.example.com # Required + serial: 2017041001 # Required + records: # Records for the zone, grouped by type + A: + mx1: # A RR with multiple values can + - 1.2.3.228 # be written as an array + - 1.2.3.229 + cat: 2.3.4.188 + rat: 1.2.3.231 + live: 1.2.3.236 + +See *bind/pillar.example* for a more complete example. + +On the other hand, if no `records` entry exists, the zone file is not generated by this state +rather than taken from `salt://zones`. See `pillar.example` for how to overwrite this URL. Example Pillar diff --git a/bind/config.sls b/bind/config.sls index 78698e6..86f437e 100644 --- a/bind/config.sls +++ b/bind/config.sls @@ -134,12 +134,22 @@ bind_default_zones: {% for zone, zone_data in salt['pillar.get']('bind:configured_zones', {}).items() -%} {%- set file = salt['pillar.get']("bind:available_zones:" + zone + ":file", zone_data.get('file')) %} +{%- set zone_records = salt['pillar.get']('bind:available_zones:' + zone + ':records', {}) %} +{# If we define RRs in pillar, we use the internal template to generate the zone file + otherwise, we fallback to the old behaviour and use the declared file +#} +{%- set zone_source = 'salt://bind/files/zone.jinja' if zone_records != {} else 'salt://' ~ map.zones_source_dir ~ '/' ~ file %} {% if file and zone_data['type'] == "master" -%} zones-{{ zone }}: file.managed: - name: {{ map.named_directory }}/{{ file }} - - source: 'salt://{{ map.zones_source_dir }}/{{ file }}' + - source: {{ zone_source }} - template: jinja + {% if zone_records != {} %} + - context: + soa: {{ salt['pillar.get']("bind:available_zones:" + zone + ":soa") }} + records: {{ zone_records }} + {% endif %} - user: {{ salt['pillar.get']('bind:config:user', map.user) }} - group: {{ salt['pillar.get']('bind:config:group', map.group) }} - mode: {{ salt['pillar.get']('bind:config:mode', '644') }} @@ -163,12 +173,22 @@ signed-{{ zone }}: {%- for view, view_data in salt['pillar.get']('bind:configured_views', {}).items() %} {% for zone, zone_data in view_data.get('configured_zones', {}).items() -%} {%- set file = salt['pillar.get']("bind:available_zones:" + zone + ":file", zone_data.get('file')) %} -{% if file and zone_data['type'] == "master" -%} +{%- set zone_records = salt['pillar.get']('bind:available_zones:' + zone + ':records', {}) %} +{# If we define RRs in pillar, we use the internal template to generate the zone file + otherwise, we fallback to the old behaviour and use the declared file +#} +{%- set zone_source = 'salt://bind/zone.jinja' if zone_records != {} else 'salt://' ~ map.zones_source_dir ~ '/' ~ file %} +{% if file and zone_data['type'] == 'master' -%} zones-{{ view }}-{{ zone }}: file.managed: - name: {{ map.named_directory }}/{{ file }} - - source: 'salt://{{ map.zones_source_dir }}/{{ file }}' + - source: {{ zone_source }} - template: jinja + {% if zone_records != {} %} + - context: + soa: {{ salt['pillar.get']("bind:available_zones:" + zone + ":soa") }} + records: {{ zone_records }} + {% endif %} - user: {{ salt['pillar.get']('bind:config:user', map.user) }} - group: {{ salt['pillar.get']('bind:config:group', map.group) }} - mode: {{ salt['pillar.get']('bind:config:mode', '644') }} diff --git a/bind/map.jinja b/bind/map.jinja index 63252e6..0a7bf19 100644 --- a/bind/map.jinja +++ b/bind/map.jinja @@ -13,7 +13,7 @@ 'named_directory': '/var/cache/bind/zones', 'log_dir': '/var/log/bind9', 'log_mode': '644', - 'user': 'root', + 'user': 'bind', 'group': 'bind', 'mode': '644' }, diff --git a/pillar.example b/pillar.example index abe8d31..b1b9948 100644 --- a/pillar.example +++ b/pillar.example @@ -103,6 +103,44 @@ bind: - 127.0.0.0/8 # And the applicable IP addresses - 10.20.0.0/16 +### Define zone records in pillar ### +bind: + available_zones: + example.com: + file: example.com.txt + soa: # Declare the SOA RRs for the zone + ns: ns1.example.com # Required + contact: hostmaster.example.com # Required + serial: 2017041001 # Required + class: IN # Optional. Default: IN + refresh: 8600 # Optional. Default: 12h + retry: 900 # Optional. Default: 15m + expiry: 86000 # Optional. Default: 2w + nxdomain: 500 # Optional. Default: 1m + ttl: 8600 # Optional. Not set by default + records: # Records for the zone, grouped by type + A: + mx1: # A RR with multiple values can + - 1.2.3.228 # be written as an array + - 1.2.3.229 + cat: 2.3.4.188 + rat: 1.2.3.231 + live: 1.2.3.236 + NS: + '@': + - rat + - cat + CNAME: + ftp: cat.example.com. + www: cat.example.com. + mail: mx1.example.com. + smtp: mx1.example.com. + TXT: # Complex records can be expressed as strings + '@': + - '"some_value"' + - '"v=spf1 mx a ip4:1.2.3.4 ~all"' + _dmarc: '"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; fo=1:d:s; adkim=r; aspf=r; pct=100; ri=86400"' + ### Externally defined Zones ### bind: available_zones: