2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 10:10:06 +00:00

Test manual-mode with KSK rollover

Similar to previous commit.

Parametrize each test case and in case of manual-mode, execute
additional checks. First a keymgr run should not change the existing
key state (with exceptions of timing events such as moving from
RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate
messages must be logged.

After enforcing the next step with 'rndc dnssec -step', the key state
should be the same as if the step were to be taken automatically.
This commit is contained in:
Matthijs Mekking 2025-07-24 12:05:06 +02:00
parent e35e103d7f
commit 6904e43510

View File

@ -13,7 +13,10 @@
from datetime import timedelta
import pytest
import isctest
from isctest.util import param
from rollover.common import (
pytestmark,
alg,
@ -30,7 +33,7 @@ from rollover.common import (
CDSS = ["CDS (SHA-256)"]
POLICY = "ksk-doubleksk-autosign"
POLICY = "ksk-doubleksk"
OFFSETS = {}
OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds())
OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds())
@ -45,11 +48,22 @@ OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KSK_CONFIG["purge-keys"].total_sec
OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_seconds())
def test_ksk_doubleksk_step1(alg, size, ns3):
zone = "step1.ksk-doubleksk.autosign"
@pytest.mark.parametrize(
"tld",
[
param("autosign"),
param("manual"),
],
)
def test_ksk_doubleksk_step1(tld, alg, size, ns3):
zone = f"step1.ksk-doubleksk.{tld}"
policy = f"{POLICY}-{tld}"
isctest.kasp.wait_keymgr_done(ns3, zone)
# manual-mode: Nothing changing in the zone, no 'dnssec -step' required.
# Note that the key was already generated during setup.
step = {
# Introduce the first key. This will immediately be active.
"zone": zone,
@ -63,14 +77,46 @@ def test_ksk_doubleksk_step1(alg, size, ns3):
# already passed).
"nextev": KSK_LIFETIME - KSK_IPUB - timedelta(days=7),
}
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step)
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
def test_ksk_doubleksk_step2(alg, size, ns3):
zone = "step2.ksk-doubleksk.autosign"
@pytest.mark.parametrize(
"tld",
[
param("autosign"),
param("manual"),
],
)
def test_ksk_doubleksk_step2(tld, alg, size, ns3):
zone = f"step2.ksk-doubleksk.{tld}"
policy = f"{POLICY}-{tld}"
isctest.kasp.wait_keymgr_done(ns3, zone)
if tld == "manual":
# Same as step 1.
step = {
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}",
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
],
"manual-mode": True,
"nextev": None,
}
keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
# Check logs.
tag = keys[1].key.tag
msg = f"keymgr-manual-mode: block KSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})"
ns3.log.expect(msg)
# Force step.
with ns3.watch_log_from_here() as watcher:
ns3.rndc(f"dnssec -step {zone}")
watcher.wait_for_line(f"keymgr: {zone} done")
step = {
# Successor KSK is prepublished (and signs DNSKEY RRset).
# KSK1 goal: omnipresent -> hidden
@ -88,14 +134,60 @@ def test_ksk_doubleksk_step2(alg, size, ns3):
# Next key event is when the successor KSK becomes OMNIPRESENT.
"nextev": KSK_IPUB,
}
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step)
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
def test_ksk_doubleksk_step3(alg, size, ns3):
zone = "step3.ksk-doubleksk.autosign"
@pytest.mark.parametrize(
"tld",
[
param("autosign"),
param("manual"),
],
)
def test_ksk_doubleksk_step3(tld, alg, size, ns3):
zone = f"step3.ksk-doubleksk.{tld}"
policy = f"{POLICY}-{tld}"
isctest.kasp.wait_keymgr_done(ns3, zone)
if tld == "manual":
# Same as step 2, but DNSKEY has become OMNIPRESENT.
step = {
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}",
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}",
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step3-s']}",
],
"keyrelationships": [1, 2],
"manual-mode": True,
"nextev": None,
}
keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
# Check logs.
tag = keys[2].key.tag
msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED"
ns3.log.expect(msg)
# Force step.
with ns3.watch_log_from_here() as watcher:
ns3.rndc(f"dnssec -step {zone}")
watcher.wait_for_line(f"keymgr: {zone} done")
# Check logs.
tag = keys[1].key.tag
msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE"
if msg in ns3.log:
# Force step.
isctest.log.debug(
f"keymgr-manual-mode blocking transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again"
)
with ns3.watch_log_from_here() as watcher:
ns3.rndc(f"dnssec -step {zone}")
watcher.wait_for_line(f"keymgr: {zone} done")
step = {
# The successor DNSKEY RRset has become omnipresent. The
# predecessor DS can be withdrawn and the successor DS can be
@ -118,14 +210,50 @@ def test_ksk_doubleksk_step3(alg, size, ns3):
# successor DS. This is the the retire interval.
"nextev": KSK_IRET,
}
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step)
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
def test_ksk_doubleksk_step4(alg, size, ns3):
zone = "step4.ksk-doubleksk.autosign"
@pytest.mark.parametrize(
"tld",
[
param("autosign"),
param("manual"),
],
)
def test_ksk_doubleksk_step4(tld, alg, size, ns3):
zone = f"step4.ksk-doubleksk.{tld}"
policy = f"{POLICY}-{tld}"
isctest.kasp.wait_keymgr_done(ns3, zone)
if tld == "manual":
# Same as step 3, but DS has become HIDDEN/OMNIPRESENT.
step = {
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}",
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step4-p']}",
f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}",
],
"keyrelationships": [1, 2],
"manual-mode": True,
"nextev": None,
}
keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
# Check logs.
tag = keys[1].key.tag
msg1 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE"
msg2 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE"
ns3.log.expect(msg1)
ns3.log.expect(msg2)
# Force step.
with ns3.watch_log_from_here() as watcher:
ns3.rndc(f"dnssec -step {zone}")
watcher.wait_for_line(f"keymgr: {zone} done")
step = {
# The predecessor DNSKEY may be removed, the successor DS is
# omnipresent.
@ -145,14 +273,24 @@ def test_ksk_doubleksk_step4(alg, size, ns3):
# This is the DNSKEY TTL plus zone propagation delay.
"nextev": KSK_KEYTTLPROP,
}
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step)
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
def test_ksk_doubleksk_step5(alg, size, ns3):
zone = "step5.ksk-doubleksk.autosign"
@pytest.mark.parametrize(
"tld",
[
param("autosign"),
param("manual"),
],
)
def test_ksk_doubleksk_step5(tld, alg, size, ns3):
zone = f"step5.ksk-doubleksk.{tld}"
policy = f"{POLICY}-{tld}"
isctest.kasp.wait_keymgr_done(ns3, zone)
# manual-mode: Nothing changing in the zone, no 'dnssec -step' required.
step = {
# The predecessor DNSKEY is long enough removed from the zone it
# has become hidden.
@ -170,14 +308,24 @@ def test_ksk_doubleksk_step5(alg, size, ns3):
# This is the KSK lifetime minus Ipub minus Iret minus time elapsed.
"nextev": KSK_LIFETIME - KSK_IPUB - KSK_IRET - KSK_KEYTTLPROP,
}
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step)
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)
def test_ksk_doubleksk_step6(alg, size, ns3):
zone = "step6.ksk-doubleksk.autosign"
@pytest.mark.parametrize(
"tld",
[
param("autosign"),
param("manual"),
],
)
def test_ksk_doubleksk_step6(tld, alg, size, ns3):
zone = f"step6.ksk-doubleksk.{tld}"
policy = f"{POLICY}-{tld}"
isctest.kasp.wait_keymgr_done(ns3, zone)
# manual-mode: Nothing changing in the zone, no 'dnssec -step' required.
step = {
# Predecessor KSK is now purged.
"zone": zone,
@ -188,4 +336,4 @@ def test_ksk_doubleksk_step6(alg, size, ns3):
],
"nextev": None,
}
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step)
isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step)