ML
    • Recent
    • Categories
    • Tags
    • Popular
    • Users
    • Groups
    • Register
    • Login

    Set up Bind server with Ansible

    IT Discussion
    bind ansible centos 7 linux devops
    2
    6
    17.5k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • stacksofplatesS
      stacksofplates
      last edited by stacksofplates

      Here is a role to configure and build Bind on CentOS 7. When I clone a machine, I grab the new MAC and add the reservation before I spin it up. Then in the inventory file, Ansible connects based on IP address and have a variable set up for the host name I want for the machine.

      Here's the machine in our inventory

      10.1.30.11   host_name=ns1.pa.jhbcomputers.com
      

      Here's the role structure:

      .
      ├── defaults
      │   └── main.yml
      ├── handlers
      │   └── main.yml
      ├── meta
      │   └── main.yml
      ├── README.md
      ├── tasks
      │   └── main.yml
      ├── templates
      │   ├── db.forward.j2
      │   ├── db.reverse.j2
      │   ├── named.conf.j2
      │   └── named.conf.local.j2
      ├── tests
      │   ├── inventory
      │   └── test.yml
      └── vars
          └── main.yml
      

      Here's our main tasks.yml file:

      ---
      # tasks file for Bind setup
      - name: Install bind
        yum:
          pkg: bind
          state: installed
      
      - name: Set hostname
        hostname:
          name: {{ host_name }}
      
      - name: Set hostname fact
        set_fact:
          ansible_fqdn: {{ host_name }}
      
      - name: Copy named conf file
        template:
          src: named.conf.j2
          dest: /etc/named.conf
          owner: root
          group: named
          mode: 0660
        notify: restart named
      
      - name: Make named directory
        file:
          path: /etc/named
          state: directory
          owner: root
          group: named
          mode: 0750
      
      - name: Copy named conf local file
        template:
          src: named.conf.local.j2
          dest: /etc/named/named.conf.local
          owner: root
          group: named
          mode: 0640
        notify: restart named
      
      
      - name: Make zones Directory
        file:
          path: /etc/named/zones
          state: directory
          owner: root
          group: named
          mode: 0750
      
      - name: Copy forward file
        template:
          src: db.forward.j2
          dest: /etc/named/zones/db.{{ domain }}
          owner: root
          group: named
          mode: 0640
        notify: restart named
      
      
      - name: Copy reverse file
        template:
          src: db.reverse.j2
          dest: /etc/named/zones/db.{{ rev_domain }}
          owner: root
          group: named
          mode: 0640
        notify: restart named
      
      - name: Open firewall port
        firewalld:
          service: dns
          permanent: true
          state: enabled
          immediate: yes
      

      db.forward.j2:

      $TTL 604800	; 1 week
      {{ domain }}	IN SOA	{{ ansible_fqdn }}. admin.{{ domain }}. (
      				8          ; serial
      				604800     ; refresh (1 week)
      				86400      ; retry (1 day)
      				2419200    ; expire (4 weeks)
      				604800     ; minimum (1 week)
      				)
      			NS	{{ ansible_fqdn }}.
      $ORIGIN {{ domain }}.
      $TTL 300	; 5 minutes
      $TTL 604800	; 1 week
      erl	 A 10.1.30.1
      ansible  A 10.1.30.5
      ns1      A 10.1.30.11
      

      db.reverse.j2:

      $ORIGIN .
      $TTL 604800	; 1 week
      {{ rev_domain }}	IN SOA	{{ ansible_fqdn }}. admin.{{ domain }}. (
      				7          ; serial
      				604800     ; refresh (1 week)
      				86400      ; retry (1 day)
      				2419200    ; expire (4 weeks)
      				604800     ; minimum (1 week)
      				)
      			NS	{{ ansible_fqdn }}.
      $ORIGIN {{ rev_domain }}.
      $TTL 604800	; 1 week
      1     PTR erl.30.1.10.in-addr.arpa.
      5     PTR ansible.30.1.10.in-addr.arpa.
      11    PTR ns1.30.1.10.in-addr.arpa.
      

      named.conf.j2:

      //
      // named.conf
      //
      // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
      
      
      // server as a caching only nameserver (as a localhost DNS resolver only).
      //
      // See /usr/share/doc/bind*/sample/ for example named configuration files.
      //
      
      include "/etc/rndc.key";
      
      
      options {
      	listen-on port 53 { 127.0.0.1; {{ ansible_eth0.ipv4.address }}; };
      #	listen-on-v6 port 53 { ::1; };
      	directory 	"/var/named";
      	dump-file 	"/var/named/data/cache_dump.db";
      	statistics-file "/var/named/data/named_stats.txt";
      	memstatistics-file "/var/named/data/named_mem_stats.txt";
      	allow-query     { any; };
      
      	/*
      	 - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
      	 - If you are building a RECURSIVE (caching) DNS server, you need to enable
      	   recursion.
      	 - If your recursive DNS server has a public IP address, you MUST enable access
      	   control to limit queries to your legitimate users. Failing to do so will
      	   cause your server to become part of large scale DNS amplification
      	   attacks. Implementing BCP38 within your network would greatly
      	   reduce such attack surface
      	*/
      	recursion yes;
      
      	dnssec-enable yes;
      	dnssec-validation yes;
      
              forwarders {
                     8.8.8.8;
              };
      
      	/* Path to ISC DLV key */
      	bindkeys-file "/etc/named.iscdlv.key";
      
      	managed-keys-directory "/var/named/dynamic";
      
      	pid-file "/run/named/named.pid";
      	session-keyfile "/run/named/session.key";
      };
      
      logging {
              channel default_debug {
                      file "data/named.run";
                      severity dynamic;
              };
      };
      
      zone "." IN {
      	type hint;
      	file "named.ca";
      };
      
      include "/etc/named/named.conf.local";
      

      named.conf.local.j2:

      zone "{{ domain }}" IN {
          type master;
          file "/etc/named/zones/db.{{ domain }}";
          allow-update { key rndc-key; };
      };
      
      zone "{{ rev_domain }}" IN {
          type master;
          file "/etc/named/zones/db.{{ rev_domain }}";
          allow-update {key rndc-key; };
      };
      
      controls {
           inet 127.0.0.1 port 953
               allow { 127.0.0.1; } keys { "rndc-key"; };
      };
      

      Here's the single simple handler main.yml:

      ---
      # handlers file for Bind setup
      - name: restart named
        service:
          name: named
          state: restarted
      

      And the vars main.yml file:

      ---
      # vars file for Bind setup
      domain: pa.jhbcomputers.com
      
      rev_domain: 30.1.10.in-addr.arpa
      

      Then you can call the role from your playbook:

      ---
      - name: Set up Bind
        hosts: 10.1.30.11
        gather_facts: true
        user: jhooks
        become: true
      
        roles:
          - bind
      
      1 Reply Last reply Reply Quote 2
      • stacksofplatesS
        stacksofplates
        last edited by

        For this to be truly modular, I would have to make variables for all of the options in each template file, but since this is pretty much just for me I didn't worry about it.

        1 Reply Last reply Reply Quote 0
        • stacksofplatesS
          stacksofplates
          last edited by

          I may also set up a yaml dictionary for the actual DNS entries. This way everything is in one place vs editing different files.

          1 Reply Last reply Reply Quote 0
          • stacksofplatesS
            stacksofplates
            last edited by stacksofplates

            So if you would want to use a YAML dictionary for your records here's a sample that goes in vars.yml:

            records:
              ns1:
                forward: 10.1.30.11
                type: A
                last: 11
                rev: 30.1.10.in-addr.arpa.
              ansible:
                forward: 10.1.30.5
                type: A
                last: 5
                rev: 30.1.10.in-addr.arpa.
            

            Then in your templates you would have this:

            reverse:

            $ORIGIN .
            $TTL 604800	; 1 week
            {{ rev_domain }}	IN SOA	{{ ansible_fqdn }}. admin.{{ domain }}. (
            				7          ; serial
            				604800     ; refresh (1 week)
            				86400      ; retry (1 day)
            				2419200    ; expire (4 weeks)
            				604800     ; minimum (1 week)
            				)
            			NS	{{ ansible_fqdn }}.
            $ORIGIN {{ rev_domain }}.
            $TTL 604800	; 1 week
            {% for key, value in records.iteritems() %}
            {{ value.last }}   PTR   {{ value.rev }}
            {% endfor %}
            

            forward:

            $ORIGIN .
            $TTL 604800	; 1 week
            {{ domain }}	IN SOA	{{ ansible_fqdn }}. admin.{{ domain }}. (
            				8          ; serial
            				604800     ; refresh (1 week)
            				86400      ; retry (1 day)
            				2419200    ; expire (4 weeks)
            				604800     ; minimum (1 week)
            				)
            			NS	{{ ansible_fqdn }}.
            $ORIGIN {{ domain }}.
            $TTL 300	; 5 minutes
            $TTL 604800	; 1 week
            
            {% for key, value in records.iteritems() %}
            {{ key }}   {{ value.type }}   {{ value.forward }}
            {% endfor %}
            

            And then the tasks would look like this:

            - name: Copy forward file
              template:
                src: db.forward.j2
                dest: /etc/named/zones/db.{{ domain }}
                owner: root
                group: named
                mode: 0640
              with_dict: "{{ records }}"
              notify: restart named
            
            
            - name: Copy reverse file
              template:
                src: db.reverse.j2
                dest: /etc/named/zones/db.{{ rev_domain }}
                owner: root
                group: named
                mode: 0640
              with_dict: "{{ records }}"
              notify: restart named
            
            1 Reply Last reply Reply Quote 2
            • scottalanmillerS
              scottalanmiller
              last edited by

              Nice, moving DNS to a YAML file and making it platform agnostic is awesome.

              1 Reply Last reply Reply Quote 2
              • stacksofplatesS
                stacksofplates
                last edited by stacksofplates

                So I also realized that if you have even a small number of records, a dictionary will become super long. So you can compact the dictionary like this:

                records:
                  ns1: {forward: 10.1.30.11, type: A, last: 11, rev: 30.1.10.in-addr.arpa.}
                  ansible: {forward: 10.1.30.5, type: A, last: 5, rev: 30.1.10.in-addr.arpa.}
                

                So while the other way may be easier to read, this saves a TON of space.

                1 Reply Last reply Reply Quote 1
                • 1 / 1
                • First post
                  Last post