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:
1 parent
293e6ddd33
commit
5630e7a848
72 files changed
+5760
-153
No files matched your search
+46
-10
@@ -223,6 +223,18 @@ func (t *Tools) ReloadZone(ctx context.Context, zone, view string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// CheckDS tells named that the parent zone has published (or withdrawn)
|
||||
// the DS record for key tag of a zone it signs (rndc dnssec -checkds).
|
||||
func (t *Tools) CheckDS(ctx context.Context, zone, view string, tag uint16, alg uint8, published bool) (string, error) {
|
||||
which := "withdrawn"
|
||||
if published {
|
||||
which = "published"
|
||||
}
|
||||
z := zoneArgs("", zone, view)[1:]
|
||||
args := append([]string{"dnssec", "-checkds", "-key", strconv.Itoa(int(tag)), "-alg", strconv.Itoa(int(alg)), which}, z...)
|
||||
return t.RNDCRun(ctx, args...)
|
||||
}
|
||||
|
||||
func zoneArgs(cmd, zone, view string) []string {
|
||||
z := strings.TrimSuffix(zone, ".")
|
||||
if z == "" {
|
||||
@@ -236,16 +248,32 @@ func zoneArgs(cmd, zone, view string) []string {
|
||||
|
||||
// ZoneStatus is the result of rndc zonestatus.
|
||||
type ZoneStatus struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Files string `json:"files"`
|
||||
Serial uint32 `json:"serial"`
|
||||
HasSerial bool `json:"-"`
|
||||
Nodes int `json:"nodes"`
|
||||
LastLoaded string `json:"last_loaded"`
|
||||
Secure bool `json:"secure"`
|
||||
Dynamic bool `json:"dynamic"`
|
||||
Raw string `json:"raw"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Files string `json:"files"`
|
||||
// Serial is the serial of the zone file named loaded. For a zone
|
||||
// named signs (inline signing) that is the unsigned zone Jarl wrote;
|
||||
// the signed zone that named serves has its own serial, SignedSerial.
|
||||
Serial uint32 `json:"serial"`
|
||||
HasSerial bool `json:"-"`
|
||||
SignedSerial uint32 `json:"signed_serial,omitempty"`
|
||||
HasSignedSerial bool `json:"-"`
|
||||
Nodes int `json:"nodes"`
|
||||
LastLoaded string `json:"last_loaded"`
|
||||
Secure bool `json:"secure"`
|
||||
InlineSigning bool `json:"inline_signing"`
|
||||
NextKeyEvent string `json:"next_key_event,omitempty"`
|
||||
Dynamic bool `json:"dynamic"`
|
||||
Raw string `json:"raw"`
|
||||
}
|
||||
|
||||
// ServedSerial is the serial named answers queries with: the signed
|
||||
// zone's for a zone it signs, otherwise the loaded one.
|
||||
func (zs *ZoneStatus) ServedSerial() (uint32, bool) {
|
||||
if zs.HasSignedSerial {
|
||||
return zs.SignedSerial, true
|
||||
}
|
||||
return zs.Serial, zs.HasSerial
|
||||
}
|
||||
|
||||
// ZoneStatus returns named's view of a zone.
|
||||
@@ -277,6 +305,14 @@ func ParseZoneStatus(out string) *ZoneStatus {
|
||||
if n, err := strconv.ParseUint(v, 10, 32); err == nil {
|
||||
zs.Serial, zs.HasSerial = uint32(n), true
|
||||
}
|
||||
case "signed serial":
|
||||
if n, err := strconv.ParseUint(v, 10, 32); err == nil {
|
||||
zs.SignedSerial, zs.HasSignedSerial = uint32(n), true
|
||||
}
|
||||
case "inline signing":
|
||||
zs.InlineSigning = v == "yes"
|
||||
case "next key event":
|
||||
zs.NextKeyEvent = v
|
||||
case "nodes":
|
||||
zs.Nodes, _ = strconv.Atoi(v)
|
||||
case "last loaded":
|
||||
|
||||
Reference in new issue
Block a user