new file: .github/workflows/python-publish.yml new file: .gitignore new file: LICENSE modified: README.md modified: certbot_dns_netbox/dns_netbox.py modified: pyproject.toml
4.2 KiB
Certbot DNS Netbox
Certbot DNS-01 authenticator plugin that updates the challenge TXT records in
NetBox DNS (the netbox-dns
NetBox plugin) via the bundled nbapi.py API helper.
DISCLAIMER: THIS PROJECT IS VIBE CODED USING AN LLM.
How it works
For every domain in the certificate request certbot asks this plugin to set an
_acme-challenge.<domain> TXT record. The plugin works exclusively through
the netbox-dns record API endpoint — the zone endpoint is never queried,
and the plugin never creates or deletes records:
- looks up the existing TXT records for the FQDN (records can be filtered by
fqdn,zoneandviewby name), - writes each challenge token into one of the pre-provisioned records, claiming one record per token,
- leaves the records in place after validation so they can be updated again on the next renewal.
Provisioning
The challenge TXT records must be created beforehand in netbox-dns, in the
view configured via search_view (certbot_dns_netbox/dns_netbox.py,
default: global). Each challenge token needs its own record:
| Certificate request | TXT records needed |
|---|---|
-d example.com or -d '*.example.com' |
1 |
-d example.com -d '*.example.com' (apex + wildcard) |
2 |
All records for a challenge share the same name (e.g. name
_acme-challenge.unifi in zone ewcs.ch); netbox-dns allows multiple TXT
records with different values for the same name. If a certificate request
needs more records than exist, certbot aborts with an error. Renewals simply
rewrite the values, so the records never need to be touched again.
Connection settings are taken from the environment, exactly as nbapi.py
expects them:
| Variable | Purpose |
|---|---|
NETBOX_URL |
Base URL of the NetBox instance |
NETBOX_BEARER |
NetBox API token (Authorization: Bearer) |
NETBOX_TOKEN |
NetBox API token (Authorization: Token) |
DEBUG |
Optional: verbose nbapi.py logging |
One of NETBOX_BEARER / NETBOX_TOKEN is required. The token's user needs
NetBox object permissions to view and change netbox-dns records only — no
zone or view permissions are required.
Installation
Install into the same Python environment as certbot:
pip install ./certbot-dns-netbox
Usage
export NETBOX_URL=https://netbox.example.com
export NETBOX_BEARER=<token>
certbot certonly \
--authenticator dns-netbox \
--dns-netbox-propagation-seconds 60 \
-d example.com -d '*.example.com'
Options
| Option | Default | Description |
|---|---|---|
--dns-netbox-propagation-seconds |
30 |
Seconds to wait for DNS propagation |
--dns-netbox-ttl |
keep current | TTL of the challenge TXT record (s) |
--dns-netbox-insecure |
off | Skip TLS verification towards NetBox |
The netbox-dns view to search is configured in code: search_view at the top
of certbot_dns_netbox/dns_netbox.py.
Renewal configuration
certbot stores the authenticator in the renewal configuration, so renewals need no extra flags:
# /etc/letsencrypt/renewal/example.com.conf
[renewalparams]
authenticator = dns-netbox
dns_netbox_ttl = 120
When certbot runs unattended (cron or systemd timer), make sure the NETBOX_*
environment variables are set, e.g. via a systemd EnvironmentFile= or a
wrapper script.
Verification
certbot plugins --init dns-netbox # plugin is discovered and loads
certbot certonly --dry-run \
--authenticator dns-netbox \
-d sub.example.com # end-to-end against the staging ACME API
Watch the _acme-challenge TXT records in the global view: their values
change to the challenge tokens during the run and remain in place afterwards.
The next renewal updates the same records again.