Add DNSSEC signing, key backups and Porkbun support

Zones get a DNSSEC setting: named signs them with BIND's default (or a
custom) dnssec-policy and inline signing, with keys in a per-view key
directory. Jarl shows the keys, the DS record and when it is safe to
publish it, checks the parent's DS records (check-ds, which also tells
named), and refuses steps that would break a signed domain: switching
straight to unsigned, finishing a turn-off too early, deleting or moving
a signed zone, TTLs above max-zone-ttl. Turning off goes through the
insecure policy; wipe starts over once the parent has no DS.

Backups store the DNSSEC keys and restore puts them back for named; the
backup unit gets CAP_DAC_READ_SEARCH to read them. Jarl raises a zone's
serial above named's whenever it writes an older one (after a restore).
The serials check compares the signed serial.

With a Porkbun API key in jarl.yaml, the registrar's name servers, glue
records and DS records can be shown and changed, each change checked
first (dry run, force to override).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-08 21:19:04 +00:00
1 parent 293e6ddd33
commit 5630e7a848
72 files changed
+5760 -153

No files matched your search

+32 -1
View File
@@ -135,7 +135,7 @@ to stderr with `-o json` or `-o yaml`, so stdout holds just the documents.
|------|---------|
| 0 | Success |
| 1 | Other error (bad arguments, connection failure, ...) |
| 2 | A check found problems (`zone serials`, `zone delegation`); its report was printed |
| 2 | A check found problems (`zone serials`, `zone delegation`, `zone dnssec check-ds`, `zone registrar status`), or a step can't be taken yet (`zone dnssec disable` before turning off has finished); the report was printed |
| 3 | Not authenticated, or not allowed (token lacks the permission) |
| 4 | Not found |
| 5 | Conflict: concurrent change, object in use, drift |
@@ -196,6 +196,37 @@ zone's delegation and glue against the zone, and calls a zone that isn't
delegated (an internal-only zone) a note, not a problem. Both only run when
you run them; see [operations.md](operations.md#checking-name-servers-and-the-delegation).
### DNSSEC and the registrar
```sh
jarl zone dnssec status adbraun.lol --view external # keys, DS record, what's next
jarl zone dnssec enable adbraun.lol --view external [--policy NAME]
jarl zone dnssec check-ds adbraun.lol --view external # has the parent got the DS? tells named
jarl zone dnssec disable adbraun.lol --view external # step 1: insecure; run again to finish
jarl zone dnssec wipe adbraun.lol --view external [--force] # off at once, keys deleted
jarl zone registrar status adbraun.lol --view external # Porkbun: NS, glue, DS vs the zone
jarl zone registrar sync-glue adbraun.lol --view external [--dry-run]
jarl zone registrar set-ns adbraun.lol --view external [NS...] [--dry-run]
jarl zone registrar publish-ds adbraun.lol --view external [--key TAG]
jarl zone registrar remove-ds adbraun.lol 51126 --view external
```
[dnssec.md](dnssec.md) explains the steps. `enable` is safe at any time:
validation only starts once the zone's DS record is at the parent, and
`status` says when to publish it. `disable` never makes a zone unsigned
while the parent may still have its DS: its first run switches to BIND's
insecure policy, and it finishes (exit 0) only when named is done (exit 2
before). `wipe` switches off at once and deletes the keys, and refuses
while the parent zone has a DS record for the zone; `--force` wipes when the
parent can't be checked.
The `registrar` commands need a Porkbun API key in jarl.yaml and an
administrator. Each change checks first that it won't break the domain and
is refused otherwise: `--dry-run` shows the checks, `--force` skips them.
(Here `--force` means that; elsewhere it overwrites files changed outside
Jarl.)
## Records
```sh