Skip to main content

Simplifying DNS Zone Management

Project description

DNScode

Simplifying DNS Zone management


About

DNScode is a project to help simplify DNS zone management, when using plain text files with servers like BIND and NSD. It provides a framework for programmatically generating zone files with Python, allowing for more flexibility, compared to other DNS as code solutions.

Why

I created this project to help me simplify my personal DNS records for my domains. What started out as a way to simply create a list of subdomains to point to a single host, turned into a flexible library for DNS zone generation. While still meeting my goal of a simple list to update, I am also able to use it for LetsEncrypt DNS challenges using my own self hosted DNS, without being forced to use BIND and rfc2136. And if I do decide to setup DNSSEC at some later point, I can build automation into my existing DNS tooling, simplifying management and reducing the likely hood of mistakes. All without loosing any flexibility.

Features

  • Support for most major record types.
  • Support for custom records.
  • Multiple zones in one file.
  • Dynamic and static records.
  • Simple and intuitive.

Installation

# Create working directory
mkdir dnsproject
cd dnsproject

# Create virtual envrionment (optional, but highly recomended)
python3 -m venv .venv
source .venv/bin/activate

# Install the dnscode package
pip install dnscode

Usage

Import the dnscode package into a python script, create a zone object, then add records into the zone. Records can be added either via helper functions in the dnscode.Zone class, or by manually creating record objects and adding them through dnscode.Zone.add(). Both methods are shown in the example below.

Once the zone is setup, you can save it as a text file using dnscode.Zone.save_file(). Currently, it also outputs to to STDOUT. See https://code.minecraftchest1.us/minecraftchest1/dnscode/issues/5 for details.

API docs at https://dnscode.minecraftchest1.us/classdnscode_1_1dnscode_1_1Zone

import dnscode

zone = dnscode.Zone(origin='example.com')				# Create zone object
zone.new_SOA(mname='ns1.minecraftchest1.us.',			# Create SOA
	rname='admin.minecraftchest1.us.',
	refresh=onemonth, retry=oneday, ttl=oneday)
zone.new_A(name='myhost', ttl=3600, host='0.0.0.0')		#New A record
zone.new_AAAA(name='myhost', ttl-3600, hosts='::1')

more_hosts = [
	'host1',
	'host2',
	'host3',
]

zone.new_A(name=more_hosts, ttl=60, host='0.0.0.0')
zone.new_AAAA(name=more_hosts, ttl=60, host='::!')

# More helper functions in the docs

cname = dnscode.CNAME(name='mycname', ttl=60, host='example.com')
# More record objects in the docs.
zone.add(cname)

zone.save_file('example.zone')

Certbot integration

Certbot supports validation using external scripts. Here is a quick example on how to configure your project and certbot for DNS validation.

Create the following scripts. These are the hooks that certbot will call to perform DNS validation.

/path/to/validation.sh

#!/bin/bash

# Certbot only returns the domain to be validated. We must add the prefix manually.
NEW_DOMAIN="_acme-challenge.${CERTBOT_DOMAIN}."

# Call your script with the record to add.
/path/to/project/.venv/bin/python3 /path/to/project/zone.py ${NEW_DOMAIN} TXT "${CERTBOT_VALIDATION}"
echo 'Propagation delay'
# Not optional, but encouraged. Exact time depends on your DNS setup.
sleep 15

/path/to/cleanup.sh

#!/bin/bash
# No cleanup required. The zone we added during validation will get removed next time the script is run.
# You could run it here if you want.
echo 'Nothing to do.'

Add the following somewhere to your script.

# Add record from command line args.
#
# NOTE: This implementation only allows for passing at most one record at a time.
#
# NOTE: This provides no validation or sanitation. More checks should be added if
#       you can't guarantee the validity of the provided arguments.

if len(sys.argv) >= 4:						# Check that enough args were provided
    r = dnscode.Record()
    r.name  = sys.argv[1]
    r.rtype = sys.argv[2]
    if sys.argv[2] == 'TXT':				# Add quoted if the record type is TXT
        r.data  = f"\"{sys.argv[3]}\""
    else:
        r.data  = sys.argv[3]
    zone.add(r)

Tell certbot to use the above hooks for validation. For example:

/path/to/certbot certonly --manual --preferred-challenges=dns --manual-auth-hook /path/to/validation.sh --manual-cleanup-hook /path/to/cleanup.sh -d 'example.com' --cert-name 'example-cert'

One drawback with this implementation is that only one domain can be validated at one. Further work is required for multi domain certs.

Donte

If you find this project useful, feel free to leave me a tip with Ko-Fi.

<iframe id='kofiframe' src='https://ko-fi.com/minecraftchest1/?hidefeed=true&widget=true&embed=true&preview=true' style='border:none;width:100%;padding:4px;background:#f9f9f9;' height='712' title='minecraftchest1'></iframe>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dnscode-1.7.3.post1.tar.gz (6.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dnscode-1.7.3.post1-py3-none-any.whl (17.8 kB view details)

Uploaded Python 3

File details

Details for the file dnscode-1.7.3.post1.tar.gz.

File metadata

  • Download URL: dnscode-1.7.3.post1.tar.gz
  • Upload date:
  • Size: 6.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dnscode-1.7.3.post1.tar.gz
Algorithm Hash digest
SHA256 8f59238c794ad903b01b69cda627284105d525159687df4aa3d04bb39b9976c9
MD5 b6ea490d7847c9cbdb3242dffda9f5df
BLAKE2b-256 e56c0395c987ce8f1798a741197453b788e704b3eef24c4c3be0ce894858b682

See more details on using hashes here.

File details

Details for the file dnscode-1.7.3.post1-py3-none-any.whl.

File metadata

  • Download URL: dnscode-1.7.3.post1-py3-none-any.whl
  • Upload date:
  • Size: 17.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dnscode-1.7.3.post1-py3-none-any.whl
Algorithm Hash digest
SHA256 6e93d4f47fc59eb5ad13211edd3b3696010e8d89aaee16bbdab0a0da2bb16857
MD5 a74c6e25762153761d8782a9dd5c8cd4
BLAKE2b-256 f0fcb8450b3bb00b7c45597668e6234808f6dc60a280b5e32c6824f68f622afd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page