modified: README.md

modified:   certbot_dns_netbox/dns_netbox.py
This commit is contained in:
Sven Luthi committed 2026-10-27 11:59:33 +01:00
1 parent 93248447b2
commit da48d8ef90
2 files changed
+131 -20

No files matched your search

+130 -19
View File
@@ -20,23 +20,6 @@ and the plugin **never creates or deletes records**:
3. leaves the records in place after validation so they can be updated again 3. leaves the records in place after validation so they can be updated again
on the next renewal. 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` Connection settings are taken from the environment, exactly as `nbapi.py`
expects them: expects them:
@@ -51,12 +34,140 @@ 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 NetBox object permissions to view and change netbox-dns records only — no
zone or view permissions are required. zone or view permissions are required.
## Tutorial: end-to-end setup
This walkthrough sets up certificates for `example.com`, including the
wildcard, from scratch. Adapt domains, names and paths to your environment.
### 1. Create the DNS zone
Create the `example.com` zone in netbox-dns, in the view the plugin searches
(`search_view` in `certbot_dns_netbox/dns_netbox.py`, default: `_default_`), and
note the numeric **zone ID** of the new zone — it is shown in the web UI URL
and can be looked up with:
```
GET /api/plugins/netbox-dns/zones/?name=example.com
```
### 2. Create a NetBox permission
In the NetBox admin interface, create a permission named
`ACME Client - Zone example.com`:
* **Object type**: `DNS › record` only
* **Actions**: view and change — nothing else. The plugin never creates or
deletes records, and it does not need zone or view permissions.
* **Constraint**:
```json
{"name": "_acme-challenge", "type": "TXT", "zone_id": 0000}
```
`0000` is the zone ID from step 1. The constraint limits the token to TXT
records named `_acme-challenge` in exactly that zone. Note that certificates
for sub-domains (`-d sub.example.com`) use a record named
`_acme-challenge.sub`; in that case, relax the constraint to
`"name__startswith": "_acme-challenge"` instead of the exact `name`.
### 3. Create a service user
* Create a user group, e.g. `ACME Clients`, and assign the permission from
step 2 to the **group** — any service user added to the group later
inherits it.
* Create a user, e.g. `certbot`, without a usable login, and make it a member
of the group.
### 4. Pre-provision the TXT records
The plugin only updates records, so they must exist before the first run.
Create `_acme-challenge` TXT records in the `example.com` zone — one per
challenge token:
| 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 (`_acme-challenge`, relative
to the zone); netbox-dns allows multiple TXT records with different values
for the same name. Initial values are placeholders and get rewritten by the
plugin. If a certificate request needs more records than exist, certbot
aborts with `Not enough TXT records ...` — add another record and rerun.
### 5. Create an API token and environment file
On the `certbot` user, create an API token (leave write enabled) and expose
it to whatever runs certbot — a cronjob in most cases — via environment
variables. Keep them in a root-readable-only file, e.g.
`/etc/default/certbot-netbox`:
```sh
NETBOX_URL=https://netbox.example.com
NETBOX_TOKEN=<token> # or: NETBOX_BEARER=<token>
```
```
chmod 600 /etc/default/certbot-netbox
```
### 6. Install certbot and the plugin in a dedicated venv
Do not install certbot from the system package manager — certbot and the
plugin live together in a dedicated venv:
```sh
python3 -m venv /opt/certbot-netbox
/opt/certbot-netbox/bin/pip install certbot certbot-dns-netbox
```
### 7. Test
```sh
/opt/certbot-netbox/bin/certbot certonly \
--authenticator dns-netbox \
-d example.com -d '*.example.com'
```
The first ever certbot run asks for an ACME account e-mail and the terms of
service. During the run the plugin writes the challenge tokens into the
`_acme-challenge` TXT records; the records remain in place afterwards. Tip:
append `--dry-run` for a first try to validate the setup against the staging
ACME API without touching rate limits.
### 8. Automate renewal
Create a wrapper that loads the environment and runs certbot from the venv,
e.g. `/usr/local/bin/certbot-netbox-renew`:
```sh
#!/bin/sh
set -a
. /etc/default/certbot-netbox
set +a
exec /opt/certbot-netbox/bin/certbot renew --quiet
```
```
chmod +x /usr/local/bin/certbot-netbox-renew
```
And a cron entry, e.g. `/etc/cron.d/certbot-netbox`:
```
0 3 * * * root /usr/local/bin/certbot-netbox-renew >> /var/log/certbot-netbox-renew.log 2>&1
```
`certbot renew` reads the renewal configuration written by step 7, so no
authenticator flags are needed here. Add a `--deploy-hook` (e.g. restarting
the web server) if services need to pick up the renewed certificate.
## Installation ## Installation
Install into the same Python environment as certbot: Install into the same Python environment as certbot:
``` ```
pip install ./certbot-dns-netbox pip install certbot-dns-netbox
``` ```
## Usage ## Usage
@@ -107,6 +218,6 @@ certbot certonly --dry-run \
-d sub.example.com # end-to-end against the staging ACME API -d sub.example.com # end-to-end against the staging ACME API
``` ```
Watch the `_acme-challenge` TXT records in the `global` view: their values Watch the `_acme-challenge` TXT records in the `_default_` view: their values
change to the challenge tokens during the run and remain in place afterwards. change to the challenge tokens during the run and remain in place afterwards.
The next renewal updates the same records again. The next renewal updates the same records again.
+1 -1
View File
@@ -26,7 +26,7 @@ from certbot.plugins import dns_common
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# netbox-dns view that contains the zone with the challenge TXT record. # netbox-dns view that contains the zone with the challenge TXT record.
search_view = "global" search_view = "_default_"
class Authenticator(dns_common.DNSAuthenticator): class Authenticator(dns_common.DNSAuthenticator):