Skip to content

DNS Operations

dr-provision provides a simple DNS query server. Most records are supported and can be returned by the server.

Endpoint Startup Configuration

Whether the DNS server is enabled and what ports it will listen on are controlled by the following startup options:

  1. --disable-dns to disable basic DNS functionality.
  2. --dns-port to change the DNS port from the default of 53 to something else. This is both TCP and UDP.

If none of these options are present, then we default to DNS being enabled on the standard port. The DNS server listens on all interfaces, and that behaviour cannot be modified at the present time.

Warning

Some services will conflict with DNS. Common sevices that must be disabled when running DRP DNS server

  • dnsmasq
  • bind

Runtime Configuration

By default, (without any Zones or Reservations defined) the DNS server will respond with negative matches.

Zones

A Zone defines a set of information that can be returned to DNS queries.

This includes dynamic records built from templatized rendering strings from Machine objects.

Reservations

A Reservation defines a one-to-one mapping between a specific network interface to be configured and the IP addressing information that should be applied to that interface.

If the reservation and its optional subnet contain an address, hostname, and a domainname, an A and PTR record will be created with in a zone that matches the Origin for the system.

Common Use Cases

This section provides real-world examples for typical DNS configurations.

Use Case 1: Basic Machine DNS

Map all machines to a domain with automatic DNS records.

Scenario: You want all machines managed by DRP to automatically get DNS entries like machine1.lab.local, machine2.lab.local.

Setup:

Bash
# Create zone for your domain
drpcli zones create - <<EOF
Name: lab-local
Origin: "lab.local."
Priority: 100
Records:
- Name: "eval:{{.Machine.Name}}"
  Type: A
  Value:
  - "{{.Machine.Address}}"
  TTL: 300
EOF

# Create forwarding zone for everything else
drpcli zones create - <<EOF
Name: root
Origin: "."
Priority: 10000
Forwarders:
- 8.8.8.8
- 8.8.4.4
EOF

Result: Any machine with an FQDN name matching the zone origin will automatically get an A record. For example, a machine named node1.lab.local with address 192.168.1.10 will resolve to 192.168.1.10.

Dynamic DNS Record Patterns

Using Machine.Name: eval:{{.Machine.Name}} only works if the machine's Name field already contains the full FQDN matching the zone origin.

  • If Name = minio1 and dns-domain = storage.localnothing renders (Name doesn't match zone origin)
  • If Name = minio1.storage.local and dns-domain = storage.localrenders (Name matches zone origin)
  • In both cases, the dns-domain parameter is not used - it depends entirely on what's in the Name field

Using ShortName + ParamExpand (Recommended): Build the FQDN dynamically from ShortName and parameter:

YAML
Records:
- Name: "eval:{{.Machine.ShortName}}.{{.ParamExpand \"dns-domain\"}}"
  Type: A
  Value:
  - "{{.Machine.Address}}"
This actually uses the dns-domain parameter value, so machines with short names like minio1 will correctly resolve as minio1.storage.local.

Advanced: Conditional DNS Records: Only create records for machines with a specific dns-domain:

YAML
Records:
- Name: "eval:{{if eq (.ParamExpand \"dns-domain\") \"storage.local\"}}{{.Machine.ShortName}}.{{.ParamExpand \"dns-domain\"}}{{else}}do-not-match.this.domain.{{end}}"
  Type: A
  Value:
  - "{{.Machine.Address}}"
This only creates matching DNS records for machines with dns-domain: "storage.local". Others get a non-matching domain to avoid polluting the zone.

Testing:

Bash
# View live DNS records
drpcli zones view lab-local

# Test resolution
nslookup node1.lab.local <drp-ip>

Use Case 2: Service Cluster DNS (MinIO Example)

Create DNS records for a distributed service cluster with multiple nodes.

Scenario: You have a MinIO S3 cluster with 4 nodes that need consistent DNS naming: minio1.storage.local, minio2.storage.local, etc.

Setup:

Create a profile for MinIO nodes:

Bash
# Create MinIO cluster profile with DNS domain
drpcli profiles create - <<EOF
Name: minio-cluster
Params:
  dns-domain: "storage.local"
EOF

Create the storage zone:

Bash
drpcli zones create - <<EOF
Name: storage-local
Origin: "storage.local."
Priority: 100
Records:
- Name: "eval:{{.Machine.ShortName}}.{{.ParamExpand \"dns-domain\"}}"
  Type: A
  Value:
  - "{{.Machine.Address}}"
  TTL: 300
- Name: "minio"
  Type: A
  Value:
  - "eval:{{.Machine.Address}}"
  TTL: 300
EOF

Apply profile to machines:

Bash
# Apply MinIO cluster profile with dns-domain parameter
drpcli machines update minio1 '{"Profiles": ["minio-cluster"]}'
drpcli machines update minio2 '{"Profiles": ["minio-cluster"]}'
drpcli machines update minio3 '{"Profiles": ["minio-cluster"]}'
drpcli machines update minio4 '{"Profiles": ["minio-cluster"]}'

Result: Each MinIO node gets its own DNS entry, and all nodes also respond to the shared minio.storage.local name for load balancing.

Testing:

Bash
# Test individual nodes
nslookup minio1.storage.local <drp-ip>
nslookup minio2.storage.local <drp-ip>

# Test shared name (returns all IPs)
nslookup minio.storage.local <drp-ip>

Use Case 3: Split DNS with External Forwarding

Handle internal zones while forwarding external queries.

Scenario: You want DRP to handle DNS for your lab environment (lab.internal) but forward all other queries to your corporate DNS servers.

Setup:

Bash
# Internal lab zone
drpcli zones create - <<EOF
Name: lab-internal
Origin: "lab.internal."
Priority: 50
Continue: false
Records:
- Name: "eval:{{.Machine.Name}}"
  Type: A
  Value:
  - "{{.Machine.Address}}"
  TTL: 300
- Name: "drp"
  Type: A
  Value:
  - "192.168.10.10"
  TTL: 3600
EOF

# Corporate domain forwarding
drpcli zones create - <<EOF
Name: corporate
Origin: "corp.example.com."
Priority: 500
Continue: true
Forwarders:
- 10.0.0.53
EOF

# Catch-all forwarding for internet
drpcli zones create - <<EOF
Name: root
Origin: "."
Priority: 10000
Forwarders:
- 8.8.8.8
- 1.1.1.1
EOF

Result: Queries for *.lab.internal are answered by DRP, *.corp.example.com queries are forwarded to 10.0.0.53, and all other queries go to public DNS.

Use Case 4: Static Service Records

Create static DNS entries for services and infrastructure.

Scenario: You need static DNS records for services like load balancers, storage arrays, and infrastructure.

Setup:

Bash
drpcli zones create - <<EOF
Name: services
Origin: "services.local."
Priority: 100
Records:
- Name: "lb"
  Type: A
  Value:
  - "192.168.1.100"
  TTL: 3600
- Name: "storage"
  Type: A
  Value:
  - "192.168.1.200"
  TTL: 3600
- Name: "api"
  Type: CNAME
  Value:
  - "lb.services.local."
  TTL: 3600
- Name: "www"
  Type: CNAME
  Value:
  - "lb.services.local."
  TTL: 3600
EOF

Result: Static DNS entries for services that don't change frequently.

Use Case 5: Multi-Zone Setup with Templates

Create zones from templates in a content bundle.

Scenario: You want to package DNS configuration in a content bundle for repeatable deployments.

Setup:

Create zone files in your content bundle:

content/zones/internal.yaml:

YAML
Name: "internal"
Origin: "internal.local."
Priority: 100
Records:
- Name: "eval:{{.Machine.Name}}"
  Type: A
  Value:
  - "{{.Machine.Address}}"
  TTL: 300

content/zones/forwarding.yaml:

YAML
Name: "root"
Origin: "."
Priority: 10000
Forwarders:
- 8.8.8.8

Template String Quoting

When creating multiple zones in a bundle, double-quote template strings to avoid import issues:

YAML
Name: "eval:{{.Machine.ShortName}}"  # Correct
Name: eval:{{.Machine.ShortName}}    # May fail during import

Import:

Bash
drpcli contents bundle content.yaml
drpcli contents upload content.yaml

Example Configuration

The following Zone will act as a forwarding name server for all queries that aren't matched by other zones. This is a common final zone in the configuration.

YAML
Name: root
Origin: "."
Priority: 10000
Forwarders:
 - 8.8.8.8

The following Zone will service the example.com domain (as declared in the Origin field). It will also be authoritative and can be used in delegation.

YAML
Continue: false
Name: example.com
Origin: example.com.
Priority: 0
Records:
- Name: .
  TTL: 86400
  Type: SOA
  Value:
  - dns1.example.com.
  - hostmaster.example.com.
  - "762016905"
  - "21600"
  - "3600"
  - "604800"
  - "86400"
- Name: .
  TTL: 86400
  Type: NS
  Value:
  - dns1.example.com.
- Name: .
  TTL: 86400
  Type: NS
  Value:
  - dns2.example.com.
- Name: .
  TTL: 86400
  Type: MX
  Value:
  - "10"
  - mail.example.com.
- Name: .
  TTL: 86400
  Type: MX
  Value:
  - "20"
  - mail2.example.com.
- Name: dns1
  TTL: 86400
  Type: A
  Value:
  - 10.0.1.1
- Name: dns2
  TTL: 86400
  Type: A
  Value:
  - 10.0.1.2
- Name: server1
  TTL: 86400
  Type: A
  Value:
  - 10.0.1.5
- Name: server2
  TTL: 86400
  Type: A
  Value:
  - 10.0.1.6
- Name: ftp
  TTL: 86400
  Type: A
  Value:
  - 10.0.1.3
- Name: ftp
  TTL: 86400
  Type: A
  Value:
  - 10.0.1.4
- Name: mail
  TTL: 86400
  Type: CNAME
  Value:
  - server1.example.com.
- Name: mail2
  TTL: 86400
  Type: CNAME
  Value:
  - server2.example.com.
- Name: www
  TTL: 86400
  Type: CNAME
  Value:
  - server1.example.com.
TTL: 3600

Import Configuration

The drpcli command can also be used to import RFC-compliant zone files. For example, existing BIND or other server files can be imported as zones into the DRP server. This is a create operation. If you wish to make changes to the zone through the file, you will need to destroy the DRP zone and reimport the file.

The Name of the Zone will be based upon the $Origin part of the file.

Bash
drpcli zones import my-zone.txt

Example file

Text Only
$ORIGIN example.com.
$TTL 86400
@       IN      SOA     dns1.example.com.       hostmaster.example.com. (
                        2001062501 ; serial
                        21600      ; refresh after 6 hours
                        3600       ; retry after 1 hour
                        604800     ; expire after 1 week
                        86400 )    ; minimum TTL of 1 day


        IN      NS      dns1.example.com.
        IN      NS      dns2.example.com.


        IN      MX      10      mail.example.com.
        IN      MX      20      mail2.example.com.


dns1    IN      A       10.0.1.1
dns2    IN      A       10.0.1.2


server1 IN      A       10.0.1.5
server2 IN      A       10.0.1.6


ftp     IN      A       10.0.1.3
        IN      A       10.0.1.4

mail    IN      CNAME   server1
mail2   IN      CNAME   server2


www     IN      CNAME   server1

CLI Operations

The drpcli can be used to create, update, and delete zones. Additionally, there are helpers to add and remove records.

CRUD Operations

Using the yaml files above, a zone can be created by:

Bash
drpcli zones create root.yaml

or updated by:

Bash
drpcli zones update root root.yaml

or destroyed by:

Bash
drpcli zones destroy root

or viewed by:

Bash
drpcli zones show root --format=yaml

or view the live records (including dynamic records and reservation records) by:

Bash
drpcli zones view root --format=yaml

The output looks like:

YAML
Data:
  .:
    MX:
    - Data:
      - "10"
      - mail.example.com.
      TTL: 86400
      Uuid: zones:example.com
    - Data:
      - "20"
      - mail2.example.com.
      TTL: 86400
      Uuid: zones:example.com
    NS:
    - Data:
      - dns1.example.com.
      TTL: 86400
      Uuid: zones:example.com
    - Data:
      - dns2.example.com.
      TTL: 86400
      Uuid: zones:example.com
    SOA:
    - Data:
      - dns1.example.com.
      - hostmaster.example.com.
      - "762259547"
      - "21600"
      - "3600"
      - "604800"
      - "86400"
      TTL: 86400
      Uuid: zones:example.com
  1.1.1.1:
    PTR:
    - Data:
      - New Record.example.com.
      TTL: 3600
      Uuid: zones:example.com
  3.3.3.3:
    PTR:
    - Data:
      - fred.example.com.
      TTL: 300
      Uuid: machines:34553cb1-7425-465a-a3a9-fb67458506bf
  4.4.4.4:
    PTR:
    - Data:
      - jane.example.com.
      TTL: 3600
      Uuid: reservations:04040404
  10.0.1.1:
    PTR:
    - Data:
      - dns1.example.com.
      TTL: 86400
      Uuid: zones:example.com
  10.0.1.2:
    PTR:
    - Data:
      - dns2.example.com.
      TTL: 86400
      Uuid: zones:example.com
  10.0.1.3:
    PTR:
    - Data:
      - ftp.example.com.
      TTL: 86400
      Uuid: zones:example.com
  10.0.1.4:
    PTR:
    - Data:
      - ftp.example.com.
      TTL: 86400
      Uuid: zones:example.com
  10.0.1.5:
    PTR:
    - Data:
      - server1.example.com.
      TTL: 86400
      Uuid: zones:example.com
  10.0.1.6:
    PTR:
    - Data:
      - server2.example.com.
      TTL: 86400
      Uuid: zones:example.com
  New Record:
    A:
    - Data:
      - 1.1.1.1
      TTL: 3600
      Uuid: zones:example.com
  dns1:
    A:
    - Data:
      - 10.0.1.1
      TTL: 86400
      Uuid: zones:example.com
  dns2:
    A:
    - Data:
      - 10.0.1.2
      TTL: 86400
      Uuid: zones:example.com
  fred:
    A:
    - Data:
      - 3.3.3.3
      TTL: 300
      Uuid: machines:34553cb1-7425-465a-a3a9-fb67458506bf
  ftp:
    A:
    - Data:
      - 10.0.1.3
      TTL: 86400
      Uuid: zones:example.com
    - Data:
      - 10.0.1.4
      TTL: 86400
      Uuid: zones:example.com
  jane:
    A:
    - Data:
      - 4.4.4.4
      TTL: 3600
      Uuid: reservations:04040404
  mail:
    CNAME:
    - Data:
      - server1.example.com.
      TTL: 86400
      Uuid: zones:example.com
  mail2:
    CNAME:
    - Data:
      - server2.example.com.
      TTL: 86400
      Uuid: zones:example.com
  server1:
    A:
    - Data:
      - 10.0.1.5
      TTL: 86400
      Uuid: zones:example.com
  server2:
    A:
    - Data:
      - 10.0.1.6
      TTL: 86400
      Uuid: zones:example.com
  www:
    CNAME:
    - Data:
      - server1.example.com.
      TTL: 86400
      Uuid: zones:example.com

The returned object a map with a single key, Data. The object in the Data key is another map whose keys are the values that are to be looked up. The . key is the same as the Origin of the zone. Special IP address entries are used as short-hand for the PTR zones for reverse lookups.

Under each lookup zey is a map of record types (e.g. A or AAAA). The object in that section is a list of values for a single record. DNS can return multiple values for a single lookup. This list provides all return values for that name and type pair. The Data field is a list of strings that will be converted into the record type when being sent to the requester. Additionally, a TTL field defines the actual type for that specific value. The Uuid field defines where that record comes from. The value is read as <type>:<id>. Static records have the value, zones:<zone name>. Machine records have the value, machines:<uuid> and the Reservation records have the value, reservations:<ip address in hex>

Records

Once a zone is added, records can be added by:

Bash
# Adds an A/PTR record for greg.example.com to 3.3.3.3
drpcli zones records add example.com A greg 3.3.3.3

Additionally, the ttl for the record can be provided by adding the --ttl flag.

Bash
# Adds an A/PTR record for greg.example.com to 3.3.3.3
drpcli zones records add example.com A greg 3.3.3.3 --ttl 3600

Or adding a dynamic record for machines that have Name fields that fall in the example.com domain.

Bash
# Adds an A/PTR record for all the Machines that match *.example.com in the Name field
drpcli zones records add example.com A "eval:{{.Machine.Name}}" "{{.Machine.Address}}"

This record is special and will generate a live entry for each machine that has a name that ends in example.com using the Machine's Address field.

Records can be removed by:

Bash
# Adds an A/PTR record for greg.example.com to 3.3.3.3
drpcli zones records remove example.com A greg 3.3.3.3

You can also get the formats and fields of the allowed record types by:

Bash
drpcli zones records types

This will produce something like this:

YAML
A:
  Key: 1
  Max: 1
  Min: 1
  Records:
  - Name: A
    Subtype: a
    Type: net.IP
AAAA:
  Key: 28
  Max: 1
  Min: 1
  Records:
  - Name: AAAA
    Subtype: aaaa
    Type: net.IP
AFSDB:
  Key: 18
  Max: 2
  Min: 2
  Records:
  - Name: Subtype
    Subtype: ""
    Type: uint16
  - Name: Hostname
    Subtype: domain-name
    Type: string
...

The map is string record type (e.g. A) and the object defines the format.

The object has the fields:

  • Key - the 16-bit integer type of the record
  • Max - the maximum number of fields for this record (-1 means unlimited)
  • Min - the minimum number of fields for this record (-1 means no minimum)
  • Records - A list of the required fields for this record.
    • Name - the name of the field
    • Type - the type of the field
    • Subtype - helper to clarify additional properties of the type. (e.g. domain-name for a string type)