---
title:  "Host je eigen DNS server in je labo"
excerpt: "Een labo is heel leuk maar het wordt nog veel leuker als je lokaal een eigen DNS server hebt."
date:   "2023-10-18T12:00:00.000Z"
author: Eli Winderickx
hero_image: /Bind_Cover.png
category: Bind,DNS,Linux
---
## Waarom willen we een eigen DNS server?
Het is heel leuk als we onze eigen Gitlab server of Zabbix opzetten. Maar als alleenstaande installaties hebben we er niet zo veel aan. We kunnen wel in alle servers de `hosts` bestanden gaan aanpassen tot een paar servers. Daarna wordt het eigenlijk niet meer beheerbaar. Iedere server moet een entry krijgen en moet up to date gehouden worden. 

De DNS server kan ons niet alleen helpen om het beheer van die IP-adressen te centraliseren. Daarnaast is het ook fijn om met hostnamen te kunnen werken. Die onthouden toch iets beter dan een reeks IP-adressen.

Een populaire keuze in de Linux wereld voor DNS is BIND. 

## Installatie
We hebben twee onderdelen nodig om deze service op te zetten:

```bash
sudo dnf install bind bind-utils -y
```

Dit installeert de `named` service. Configuratie kan gemaakt worden in `/etc/named.conf`. Daar gaan we nu de configuratie doorvoeren.

## Configuratie
Eerst moeten we instellen via welke weg we configuratie beschikbaar willen stellen. De poort staat vaak al goed. Daarnaast moeten we het IP-adres van de server nog toevoegen alsook wie verzoeken mag sturen. Hier heeft mijn server het IP-adres `192.168.124.115`. Andere servers in mijn labo bevinden zich in hetzelfde subnet dus die mogen verzoeken sturen; `192.168.124.0/24`

```
...
listen-on port 53 { 127.0.0.1; 192.168.124.115; };
...
allow-query { localhost; 192.168.124.0/24; }
```

Onderaan dat bestand kunnen we dan aangeven welke zones we gaan aanbieden. Doe dat net boven de `include` regel. Per zone kan je een domein configureren. Hier gaan we twee entries voorzien. De eerste is voor het forward domain zone en de tweede is voor de reverse DNS.

Onthou goed wat je onder `file` noteert. Dat worden de namen van de bestanden voor de volgende stap.

```
...
zone "winderickx.me" IN {
type master;
file "forward.winderickx.me";
allow-update { none; };
};

zone "124.168.192.in-addr.arpa" IN {
type master;
file "reverse.winderickx.me";
allow-update { none; };
};
include "/etc/named.rfc1912.zones";
...
```

Nu deze configuratie klaar staat, kunnen we de effectieve data invullen in de bestanden die we in de vorige stap hebben ingegeven. Deze bestanden staan standaard in `/var/named` map.

> Domeinnamen in DNS eindigen altijd met een . om duidelijk het TLD (Top Level Domain) aan te geven.

`forward.winderickx.me`
```
$TTL 86400
@   IN  SOA     dns.winderickx.me. root.winderickx.me. (
        2011071001  ;Serial
        3600        ;Refresh
        1800        ;Retry
        604800      ;Expire
        86400       ;Minimum TTL
)
@       IN  NS          dns.winderickx.me.
@       IN  A           192.168.124.99
dns           IN  A   192.168.124.115
<servers>          IN  A   <IP-adressen>
```

`reverse.winderickx.me`
```
$TTL 86400
@   IN  SOA     dns.winderickx.me. root.winderickx.me. (
        2011071001  ;Serial
        3600        ;Refresh
        1800        ;Retry
        604800      ;Expire
        86400       ;Minimum TTL
)
@       IN  NS          dns.winderickx.me.
@       IN  PTR         winderickx.me.
dns           IN  A   192.168.1.115
115     IN  PTR         dns.winderickx.me.
<laatste octet van IP>     IN  PTR         <Servers>.
```

Zorg er voor dat de named groep rechten heeft op het bestand.

```bash
sudo chgrp named -R /var/named
```

> Vergeet niet de firewall aan te passen!

```bash
sudo firewall-cmd --add-service=dns --permanent
sudo firewall-cmd --reload
```

Controleer nu de configuratie.
```bash
sudo named-checkconf /etc/named.conf
sudo named-checkzone /var/named/forward.winderickx.me
sudo named-checkzone /var/named/reverse.winderickx.me
```

Als daar geen fouten uitkomen, kan je nu de service starten.

```bash
sudo systemctl restart named
```

## Client configuratie
We gaan er even van uit dat je gebruik maakt van `NetworkManager` voor jouw netwerk configuratie. Dit kan je dan gebruiken om jouw nieuwe DNS in te stellen op alle hosts.

> Hier gebruik ik de connectie `enp1s0` om de aanpassingen op uit te voeren. Om te weten te komen welke connectie voor jou actief staat, voer dan `ip -br a` uit.

```bash
sudo nmcli c m enp1s0 ipv4.dns "192.168.124.115"
sudo nmcli c m enp1s0 ipv4.ignore-auto-dns yes
sudo systemctl restart NetworkManager
```

Als dat goed gelukt is, ga je dit IP-adres terugvinden in `/etc/resolv.conf`. Dit is namelijk de plaats waar Linux de DNS server verwacht. Heb je dus geen `NetworkManager`, dan kan je ook hier manueel het IP-adres aanpassen. 

## En nu Ansible!
Omdat we productief lui zijn, doen we dit proces liefst zo automatisch mogelijk. Ik heb daarom dit hele proces ook in een Ansible playbook geschreven. Die kan je dus gewoon gebruiken. Mijn DNS server is een RHEL gebasseerde server. Als je een Debian gebasseerde server gebruikt, ga je mogelijk hinder ervaren. Je gaat nog steeds enkele bestanden moeten voorzien:
- named.conf
- Forward lookup bestand
- reverse lookup bestand
- resolv.conf 

Geef gerust een seintje via [LinkedIn](https://www.linkedin.com/in/eliwinderickx/) als je vast zit met deze bestanden.

```yml
---
- name: Install DNS server
  hosts: dns
  vars:
    packages:
      - bind
      - bind-utils
      - firewalld
  tasks:
    - name: Install the required software
      ansible.builtin.dnf:
        name: "{{ item }}"
        state: latest
      loop: "{{ packages }}"
        
    - name: Enable and start firewall service
      ansible.builtin.service:
        name: firewalld
        state: started
        enabled: true

    - name: Allow DNS traffic on firewall
      ansible.posix.firewalld:
        service: dns
        state: enabled
        permanent: true
        immediate: true

    - name: Configure the BIND service
      ansible.builtin.copy:
        src: named.conf
        dest: /etc/named.conf
        owner: root
        group: named
        mode: 0640
      notify: restart bind service

    - name: Prepare DNS zone files
      ansible.builtin.copy:
        src: "{{ item }}"
        dest: "/var/named/{{ item }}"
        owner: root
        group: named
        mode: 0644
      loop:
        - forward.winderickx.me
        - reverse.winderickx.me
      notify: restart bind service
  handlers:
    - name: restart bind service
      ansible.builtin.service:
        name: named
        state: restarted
- name: Configure DNS for hosts
  hosts: all
  vars: 
    dns4: 192.168.124.115
    conn_name: enp1s0
  tasks:
    - name: Configure the correct DNS for the server
      community.general.nmcli:
        conn_name: "{{ conn_name }}"
        type: ethernet
        dns4: "{{ dns4 }}"
        dns4_ignore_auto: true
        state: present
      when: ansible_facts['distribution'] != "Debian"
      notify: reload NetworkManager

    - name: Configure the correct DNS for debian
      ansible.builtin.template:
        src: resolv.conf.j2
        dest: /etc/resolv.conf
        owner: root
        group: root
        mode: 0644
      when: ansible_facts['distribution'] == "Debian"
  handlers:
    - name: reload NetworkManager
      ansible.builtin.service:
        name: NetworkManager
        state: restarted
```

## Bonus
Wil je wel Ansible gebruiken maar geen eigen DNS server? Dan heb je hier een andere playbook die de inventory van jouw Ansible gebruikt om `/etc/hosts` op te vullen. Dit is een heel pak simplistischer dan heel de opzet hierboven maar we moeten bij iedere aanpassing wel deze playbook uitvoeren op ALLE servers in onze inventory en die inventory wordt ineens de `Single Source of Truth`. Hou daar dus zeker rekening mee als je toch voor deze optie gaat!

`dns.yml`
```yml
- name: /etc/hosts is up to date
  hosts: all
  gather_facts: yes
  tasks:
    - name: Deploy /etc/hosts
      ansible.builtin.template:
        src: templates/hosts.j2
        dest: /etc/hosts
```

`hosts.j2`
```j2
{% for host in groups['all'] %}
{{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }} {{ hostvars[host]['ansible_facts']['fqdn'] }} {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}
```