Getting started

Default configuration

By default, the role configures dnsmasq to act as a caching and forwarding DNS server for the local machine. Additional configuration like support for Consul DNS service and LXC subdomain managed by the debops.lxc role is enabled when detected.

The initial configuration is designed with nested hierarchy of DNS servers in mind: by default answers about private IP addresses from external DNS servers are blocked to avoid rebinding, but the hosts' own domain, as well as its parent domain are exempt from this, as long as the parent domain has 3 or more levels. The filtering of PTR requests will be disabled when the upstream nameservers are located in a private IP address ranges, or local LXC configuration is detected, to allow revDNS requests to be resolved.

If the host has the br2 network interface, it is assumed to be a local private network, and DHCP/DNS/PXE services are configured for it. The role will automatically create relevant configuration based on the IP addresses defined on the interface, as well as publish a DNS domain based on the interface name; this can be controlled using the dnsmasq__interfaces configuration variables. The role will automatically configure support for iPXE service managed by debops.ipxe role to allow customized PXE boot menus.

Example inventory

Hosts added to the debops_service_dnsmasq inventory group will have the dnsmasq installed and configured.

[debops_service_dnsmasq]
hostname

Example playbook

If you are using this role without DebOps, here's an example Ansible playbook that uses the debops.dnsmasq role:

---

- name: Configure dnsmasq
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_dnsmasq' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  pre_tasks:

    - import_role:
        name: 'dnsmasq'
        tasks_from: 'main_env'
      tags: [ 'role::dnsmasq', 'role::ferm', 'role::tcpwrappers' ]

  roles:

    - role: resolvconf
      tags: [ 'role::resolvconf', 'skip::resolvconf' ]
      resolvconf__dependent_services:
        - 'dnsmasq'

    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm' ]
      ferm__dependent_rules:
        - '{{ dnsmasq__ferm__dependent_rules }}'

    - role: tcpwrappers
      tags: [ 'role::tcpwrappers', 'skip::tcpwrappers' ]
      tcpwrappers__dependent_allow:
        - '{{ dnsmasq__env_tcpwrappers__dependent_allow }}'

    - role: dnsmasq
      tags: [ 'role::dnsmasq', 'skip::dnsmasq' ]

If you are using this role without DebOps, here's an example Ansible playbook that uses debops.dnsmasq together with the debops.persistent_paths:

---

- name: Configure dnsmasq and ensure persistence
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_dnsmasq_persistent_paths' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  pre_tasks:

    - import_role:
        name: 'dnsmasq'
        tasks_from: 'main_env'
      tags: [ 'role::dnsmasq', 'role::ferm', 'role::tcpwrappers' ]

  roles:

    - role: resolvconf
      tags: [ 'role::resolvconf', 'skip::resolvconf' ]
      resolvconf__dependent_services:
        - 'dnsmasq'

    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm' ]
      ferm__dependent_rules:
        - '{{ dnsmasq__ferm__dependent_rules }}'

    - role: tcpwrappers
      tags: [ 'role::tcpwrappers', 'skip::tcpwrappers' ]
      tcpwrappers__dependent_allow:
        - '{{ dnsmasq__env_tcpwrappers__dependent_allow }}'

    - role: dnsmasq
      tags: [ 'role::dnsmasq', 'skip::dnsmasq' ]

    - role: persistent_paths
      tags: [ 'role::persistent_paths', 'skip::persistent_paths' ]
      persistent_paths__dependent_paths: '{{ dnsmasq__persistent_paths__dependent_paths }}'

If you are using this role without DebOps, here's an example Ansible playbook that uses debops.dnsmasq together with the debops-contrib.apparmor role:

---

## Basically the same playbook as the one in DebOps core with the difference
## that this playbook also uses the debops-contrib.apparmor role to configure
## AppArmor.

- name: Configure AppArmor for dnsmasq
  collections: [ 'debops.debops' ]
  hosts: [ 'debops_contrib_service_dnsmasq' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  pre_tasks:

    - import_role:
        name: 'dnsmasq'
        tasks_from: 'main_env'
      tags: [ 'role::dnsmasq', 'role::ferm', 'role::tcpwrappers' ]

  roles:

    - role: debops-contrib.apparmor
      tags: [ 'role::apparmor' ]
      apparmor__local_dependent_config: '{{ dnsmasq__apparmor__local_dependent_config }}'


- name: Configure dnsmasq
  collections: [ 'debops.debops' ]
  hosts: [ 'debops_contrib_service_dnsmasq' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  roles:

    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm' ]
      ferm__dependent_rules:
        - '{{ dnsmasq__ferm__dependent_rules }}'

    - role: dnsmasq
      tags: [ 'role::dnsmasq' ]

debops.persistent_paths support

In case the host in question happens to be a TemplateBasedVM on Qubes OS or another system where persistence is not the default, it should be absent in debops_service_dnsmasq and instead be added to the debops_service_dnsmasq_persistent_paths Ansible inventory group so that the changes can be made persistent:

[debops_service_dnsmasq_persistent_paths]
hostname

The dnsmasq__base_packages are expected to be present (typically installed in the TemplateVM).

Note that you will need to set core__unsafe_writes to True when you attempt to update the configuration on a system that uses bind mounts for persistence. You can set core__unsafe_writes directly in your inventory without the need to run the debops.core role for this special case. Refer to Templating or updating persistent files for details.

Other resources

List of other useful resources related to the debops.dnsmasq Ansible role: