The Corefile parser now fully populates typed fields on RFC2136 instead of just recognising directives. Validation happens at parse-time so configuration errors fail loud at CoreDNS startup rather than silent at request time. Added: - config.go: tsigKey type, TSIG algorithm allowlist (rejects HMAC-MD5 deliberately), base64 secret decoder with 8-byte minimum length check, canonical-key-name normalisation (lowercase + trailing dot). - plugin.go: RFC2136 struct now carries TSIGKeys map, TTL uint32, PersistPath string. DefaultTTL=60. - setup.go: parse() validates and stores tsig-key/ttl/persist directives. Duplicate key names rejected. Multiple TSIG keys allowed (for rotation). At-least-one-zone is enforced. - setup_test.go: 13 table-driven cases (5 happy + 8 error paths) using caddy.NewTestController. All pass. ServeDNS still passes through — UPDATE handling lands in Phase 1.4. Module path: git.supported.systems/rsp2k/coredns-rfc2136
77 lines
2.2 KiB
Markdown
77 lines
2.2 KiB
Markdown
# coredns-rfc2136
|
|
|
|
A [CoreDNS](https://coredns.io) plugin that accepts **RFC 2136 dynamic DNS
|
|
updates** (TSIG-authenticated), filling a gap in the official plugin set.
|
|
|
|
CoreDNS as-shipped has no plugin for accepting dynamic updates — its
|
|
plugin model treats authoritative data as read-only (loaded from `auto`,
|
|
`file`, `secondary`, etc.). This plugin adds the missing piece.
|
|
|
|
## Primary use case: self-hosted ACME DNS-01
|
|
|
|
The motivating problem: automate Let's Encrypt cert issuance for many
|
|
domains without depending on registrar APIs (Vultr/Route53/Cloudflare).
|
|
The architecture:
|
|
|
|
```
|
|
_acme-challenge.example.com CNAME <uuid>.auth.supported.systems
|
|
│
|
|
│ delegated NS to your CoreDNS host
|
|
▼
|
|
CoreDNS + rfc2136 plugin
|
|
│
|
|
│ accepts TSIG UPDATEs from Caddy
|
|
│ (caddy-dns/rfc2136) or any other
|
|
│ ACME client
|
|
▼
|
|
Let's Encrypt validates
|
|
```
|
|
|
|
One-time per protected domain: add a `CNAME` glue line in your static
|
|
zones. After that, all cert issuance + renewal happens via UPDATE
|
|
messages — zero static zone-file churn.
|
|
|
|
## Status
|
|
|
|
**Phase 1 (skeleton)**: compiles, registers with CoreDNS, parses the
|
|
Corefile directive. Does not yet handle UPDATE messages or serve any
|
|
records. ServeDNS is a pass-through. See `phases.md` for the roadmap.
|
|
|
|
## Configuration
|
|
|
|
```
|
|
rfc2136 <zone> [<zone>...] {
|
|
tsig-key <key-name> <algorithm> <base64-secret>
|
|
ttl <seconds>
|
|
persist <path>
|
|
}
|
|
```
|
|
|
|
Example:
|
|
|
|
```
|
|
.:53 auth.example.com {
|
|
rfc2136 auth.example.com {
|
|
tsig-key acme-key. hmac-sha256 BASE64SECRET==
|
|
ttl 60
|
|
}
|
|
errors
|
|
log
|
|
}
|
|
```
|
|
|
|
## Building
|
|
|
|
This plugin is consumed by a custom CoreDNS build via `plugin.cfg`:
|
|
|
|
```
|
|
# In CoreDNS source's plugin.cfg, BEFORE the `cache` plugin:
|
|
rfc2136:git.supported.systems/rsp2k/coredns-rfc2136
|
|
```
|
|
|
|
Then `go get git.supported.systems/rsp2k/coredns-rfc2136 && make`.
|
|
|
|
## License
|
|
|
|
MIT (TODO: add LICENSE file).
|