It is the 26th of July 2017

How to setup a Debian Wheezy mail and DNS server using SaltStack - Bind9

In the last chapter I have setup an exim + dovecot mail server using salt. The current directory structure is:

  • /path/to/master.prograssing.com
    • ./pillar/top.sls
    • ./pillar/common/init.sls
    • ./pillar/ssh/init.sls
    • ./pillar/mail/init.sls
    • ./salt/common
      • ./init.sls
      • ./bash.bashrc
      • ./bash_aliases
      • ./iptables.rules
      • ./vagrant_iptables.rules
    • ./salt/mail
      • ./init.sls
      • ./.forward
      • ./mailname
      • ./spamassassin
      • ./dovecot/conf.d/10-mail.conf
      • ./exim4
        • ./update-exim4.conf.conf
        • ./virtual/prograssing.com
        • ./conf.d
          • ./acl/40_exim4-config_check_data-deny-virus.patch
          • ./main/01_exim4-config_listmacrosdefs
          • ./main/03_exim4-config_tlsoptions
          • ./router/350_exim4-config_vdom_aliases
    • ./salt/ssh
      • ./init.sls
      • ./sshd_config
      • ./ssh_config
      • ./vagrant_sshd_config
      • ./motd
      • ./issue.net
    • ./salt/top.sls
    • ./Vagrantfile (optional)
    • ./vagrantconfig.yaml (optional)

DNS Server setup using bind9

I decided to setup bind9 inside a chroot jail as outlined on tldp. For zone configuration I will use the Salt builtin jinja template system.

./salt/dns/init.sls:

dns-pkgs:
  pkg.installed:
    - pkgs:
      - bind9
      - dnsutils

/chroot/bind/etc/bind:
  file.directory:
    - user: root
    - group: root
    - makedirs: True
    - require:
      - pkg: dns-pkgs

bind:
  user.present:
    - require:
      - file: /chroot/bind/etc/bind

/etc/default/bind9:
  file.managed:
    - source: salt://dns/default/bind9

cp -aR /etc/bind /chroot/bind/etc:
  cmd.run:
    - require: 
      - pkg: dns-pkgs
      - file: /chroot/bind/etc/bind

/chroot/bind/log:
  file.directory:
    - user: root
    - group: bind
    - mode: 775
    - makedirs: true
    - require:
      - cmd: cp -aR /etc/bind /chroot/bind/etc

/chroot/bind/dev:
  file.directory:
    - user: root
    - group: bind
    - makedirs: true
    - require:
      - cmd: cp -aR /etc/bind /chroot/bind/etc

/chroot/bind/var/cache/bind:
  file.directory:
    - user: root
    - group: bind
    - mode: 775
    - makedirs: true
    - require:
      - cmd: cp -aR /etc/bind /chroot/bind/etc


mknod dev/null c 1 3 && mknod dev/zero c 1 5 && mknod dev/random c 1 8:
  cmd.run:
    - cwd: /chroot/bind
    - unless: test -e dev/null
    - require:
      - file: /chroot/bind/dev

/chroot/bind/etc/bind/named.conf.options:
  file.managed:
    - user: root
    - group: bind
    - mode: 640
    - source: salt://dns/chroot/bind/etc/bind/named.conf.options
    - require:
      - cmd: cp -aR /etc/bind /chroot/bind/etc

named.conf:
  file.managed:
    - name: /chroot/bind/etc/bind/named.conf
    - user: root
    - group: bind
    - mode: 640
    - source: salt://dns/chroot/bind/etc/bind/named.conf
    - require:
      - cmd: cp -aR /etc/bind /chroot/bind/etc

{% for domain, serial in pillar.get('domains', {}).items() %}
append-{{ domain }}:
  file.append:
    - name: /chroot/bind/etc/bind/named.conf
    - template: jinja
    - text: 'include "/etc/bind/named.conf.{{ domain }}";'
    - unless: grep "named.conf.{{ domain }}" /chroot/bind/etc/bind/named.conf
    - require:
      - file: named.conf

/chroot/bind/etc/bind/named.conf.{{ domain }}:
  file.managed:
    - user: root
    - group: bind
    - mode: 640
    - template: jinja
    - context: 
      domain: {{ domain }}
    - source: salt://dns/named.conf.tmpl
    - require:
      - file: append-{{ domain }}

/chroot/bind/var/cache/bind/{{ domain }}:
  file.managed:
    - user: root
    - group: bind
    - mode: 640
    - template: jinja
    - context: 
      domain: {{ domain }}
      serial: {{ serial }}
      wan_ip: {{ grains['ip_interfaces'][pillar['wan_interface']][-1] }}
    - source: salt://dns/zone.tmpl
{% endfor %}

################
# reverse dns

append-reversedns:
  file.append:
    - name: /chroot/bind/etc/bind/named.conf
    - template: jinja
    - text: 'include "/etc/bind/named.conf.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[2] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[1] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[0] }}.in-addr.arpa";'
    - unless: grep "named.conf.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[2] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[1] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[0] }}.in-addr.arpa" /chroot/bind/etc/bind/named.conf
    - require:
      - file: named.conf

/chroot/bind/etc/bind/named.conf.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[2] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[1] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[0] }}.in-addr.arpa:
  file.managed:
    - user: root
    - group: bind
    - mode: 640
    - template: jinja
    - context: 
      domain: "{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[2] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[1] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[0] }}.in-addr.arpa"
    - source: salt://dns/named.conf.tmpl
    - require:
      - file: append-reversedns

/chroot/bind/var/cache/bind/{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[2] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[1] }}.{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[0] }}.in-addr.arpa:
  file.managed:
    - user: root
    - group: bind
    - mode: 640
    - template: jinja
    - context: 
      domains: {{ pillar.get('domains', {}).keys() }}
      domain: "{{ grains['ip_interfaces'][pillar['wan_interface']][-1].split('.')[-1] }}"
      serial: 123
      wan_ip: {{ grains['ip_interfaces'][pillar['wan_interface']][-1] }}
    - source: salt://dns/reverse_zone.tmpl

bind9:
  service.running:
    - require:
      - pkg: dns-pkgs
      - file:  append-reversedns
      - file: /etc/default/bind9

Configuration files

./salt/dns/chroot/bind/etc/bind/named.conf:

...
acl common-allow-transfer {
    <allow transfer subnet>;
};

./salt/dns/default/bind9:

...
OPTIONS="-u bind -t /chroot/bind"
...

Pillar Files

./pillar/dns/init.sls:

domains:
    prograssing.com: 4711

Jinja Templates

./salt/dns/named_conf.tmpl:

zone "{{ domain }}" {
        type master;
        file "{{ domain }}";
        allow-transfer {
                common-allow-transfer;
        };
};

./salt/dns/zone.tmpl:

$TTL    <#>

@       IN      SOA     {{ grains['id'] }}. root.{{ grains['id'] }}. (
                        {{ serial }} ; Serial
                        <#>   ; Refresh
                        <#>    ; Retry
                        <#>  ; Expire
                        <#> ) ; Minimum

{{ domain }}.                IN NS   {{ grains['id'] }}.
{{ domain }}.                IN NS   <primary ns>.
ns.{{ domain }}.             IN A    {{ wan_ip }}
{{ domain }}.                IN A    {{ wan_ip }}
mail.{{ domain }}.           IN A    {{ wan_ip }}
*.{{ domain }}.              IN CNAME        {{ domain }}.
{{ domain }}.                IN MX  10 mail.{{ domain }}.
{{ domain }}.                IN TXT  "v=spf1 +a +mx -all"

./salt/dns/reverse_zone.tmpl:

$TTL    <#>

@       IN      SOA     {{ grains['id'] }}. root.{{ grains['id'] }}. (
                        {{ serial }} ; Serial
                        <#>   ; Refresh
                        <#>    ; Retry
                        <#>  ; Expire
                        <#> ) ; Minimum

                 IN NS   {{ grains['id'] }}.
{{ domain }}               IN PTR  {{ grains['id'] }}.
{% for domainptr in domains %}{{ domain }}              IN PTR  {{ domainptr }}.
{% endfor %}

In the last chapter I will deploy the entire configuration to a live system.

Featured Apps

Free Money