Add wait_for_keymgr_done() util function to tests

The kasp test cases assume that keymgr operations on the zone under test
have been completed before the test is executed. These are typically
quite fast, but the logs need to be explicitly checked for the messages,
otherwise there's a possibility of race conditions causing the
kasp/rollover tests to become unstable.

Call the wait function in all the kasp/rollover tests where it is
expected (which is generally in each test, unless we're dealing with
unsigned zones).
This commit is contained in:
Nicki Křížek 2025-07-08 13:46:01 +02:00
parent fe55342916
commit 467b826162
21 changed files with 325 additions and 56 deletions

View file

@ -9,6 +9,7 @@
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
from datetime import datetime, timedelta, timezone
from functools import total_ordering
import glob
import os
@ -18,10 +19,10 @@ import subprocess
import time
from typing import Dict, List, Optional, Tuple, Union
from datetime import datetime, timedelta, timezone
import dns
import dns.tsig
from isctest.instance import NamedInstance
import isctest.log
import isctest.query
import isctest.util
@ -1528,3 +1529,16 @@ def policy_to_properties(ttl, keys: List[str]) -> List[KeyProperties]:
proplist.append(keyprop)
return proplist
def wait_keymgr_done(server: NamedInstance, zone: str, reconfig: bool = False) -> None:
"""
Block and wait until the keymgr is done processing zone.
"""
messages = []
if reconfig:
messages.append("received control channel command 'reconfig'")
messages.append("apply_configuration")
messages.append(f"keymgr: {zone} done")
with server.watch_log_from_start() as watcher:
watcher.wait_for_sequence(messages)

View file

@ -642,6 +642,8 @@ def test_kasp_case(servers, ns3, params):
zone = params["zone"]
policy = params["policy"]
isctest.kasp.wait_keymgr_done(ns3, zone)
params["config"]["key-directory"] = params["config"]["key-directory"].replace(
"{keydir}", keydir
)
@ -753,6 +755,8 @@ def test_kasp_inherit_signed(zone, policy, server_id, alg, tsig_kind, servers):
else None
)
isctest.kasp.wait_keymgr_done(server, zone)
key1 = KeyProperties.default()
key1.metadata["Algorithm"] = alg.number
key1.metadata["Length"] = alg.bits
@ -779,6 +783,8 @@ def test_kasp_inherit_view(number, dynamic, inline_signing, txt_rdata, ns4):
view = f"example{number}"
tsig = f"{os.environ['DEFAULT_HMAC']}:keyforview{number}:{KASP_INHERIT_TSIG_SECRET[f'view{number}']}"
isctest.kasp.wait_keymgr_done(ns4, zone)
key1 = KeyProperties.default()
key1.metadata["Algorithm"] = ECDSAP384SHA384.number
key1.metadata["Length"] = ECDSAP384SHA384.bits
@ -828,6 +834,8 @@ def test_kasp_default(ns3):
zone = "default.kasp"
policy = "default"
isctest.kasp.wait_keymgr_done(ns3, zone)
# Key properties.
# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
keyprops = [
@ -904,6 +912,9 @@ def test_kasp_default(ns3):
# A zone that uses inline-signing.
isctest.log.info("check an inline-signed zone with the default policy is signed")
zone = "inline-signing.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
# Key properties.
key1 = KeyProperties.default()
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
@ -920,6 +931,9 @@ def test_kasp_dynamic(ns3):
isctest.log.info("check dynamic zone is updated and signed after update")
zone = "dynamic.kasp"
policy = "default"
isctest.kasp.wait_keymgr_done(ns3, zone)
# Key properties.
key1 = KeyProperties.default()
expected = [key1]
@ -982,6 +996,9 @@ def test_kasp_dynamic(ns3):
# Dynamic, and inline-signing.
zone = "dynamic-inline-signing.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
# Key properties.
key1 = KeyProperties.default()
expected = [key1]
@ -1016,6 +1033,9 @@ def test_kasp_dynamic(ns3):
# Dynamic, signed, and inline-signing.
isctest.log.info("check dynamic signed, and inline-signed zone")
zone = "dynamic-signed-inline-signing.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
# Key properties.
key1 = KeyProperties.default()
# The ns3/setup.sh script sets all states to omnipresent.
@ -1045,6 +1065,9 @@ def test_kasp_checkds(ns3):
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
]
isctest.kasp.wait_keymgr_done(ns3, zone)
expected = isctest.kasp.policy_to_properties(ttl=303, keys=policy_keys)
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
ksks = [k for k in keys if k.is_ksk()]
@ -1087,6 +1110,9 @@ def test_kasp_checkds_doubleksk(ns3):
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden",
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:rumoured",
]
isctest.kasp.wait_keymgr_done(ns3, zone)
expected = isctest.kasp.policy_to_properties(ttl=303, keys=policy_keys)
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
ksks = [k for k in keys if k.is_ksk()]
@ -1156,6 +1182,9 @@ def test_kasp_checkds_csk(ns3):
policy_keys = [
f"csk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
]
isctest.kasp.wait_keymgr_done(ns3, zone)
expected = isctest.kasp.policy_to_properties(ttl=303, keys=policy_keys)
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
isctest.kasp.check_dnssec_verify(ns3, zone)
@ -1186,7 +1215,10 @@ def test_kasp_special_characters(ns3):
# A zone with special characters.
isctest.log.info("check special characters")
zone = r'i-am.":\;?&[]\@!\$*+,|=\.\(\)special.kasp'
zone = r"i-am.\":\;?&[]\@!\$*+,|=\.\(\)special.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
# It is non-trivial to adapt the tests to deal with all possible different
# escaping characters, so we will just try to verify the zone.
isctest.kasp.check_dnssec_verify(ns3, zone)
@ -1197,6 +1229,9 @@ def test_kasp_insecure(ns3):
isctest.log.info("check insecure zones")
zone = "insecure.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
expected = []
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
isctest.kasp.check_keys(zone, keys, expected)
@ -1432,6 +1467,9 @@ def test_kasp_zsk_retired(ns3):
# zsk successor
f"zsk 31536000 {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:hidden",
]
isctest.kasp.wait_keymgr_done(ns3, zone)
expected = isctest.kasp.policy_to_properties(300, key_properties)
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
ksks = [k for k in keys if k.is_ksk()]
@ -1550,6 +1588,8 @@ def test_kasp_purge_keys(ns4):
f"{os.environ['DEFAULT_HMAC']}:keyforview2:{KASP_INHERIT_TSIG_SECRET['view2']}"
)
isctest.kasp.wait_keymgr_done(ns4, zone)
isctest.kasp.check_dnssec_verify(ns4, zone, tsig=tsig1)
isctest.kasp.check_dnssec_verify(ns4, zone, tsig=tsig2)

View file

@ -24,9 +24,12 @@ from common import (
def test_algoroll_csk_initial(ns6):
config = ALGOROLL_CONFIG
policy = "csk-algoroll"
zone = "step1.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone)
step = {
"zone": "step1.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}",

View file

@ -39,9 +39,11 @@ TIME_PASSED = 0 # set in reconfigure() fixture
@pytest.fixture(scope="module", autouse=True)
def reconfigure(ns6, templates):
global TIME_PASSED # pylint: disable=global-statement
start_time = KeyTimingMetadata.now()
isctest.kasp.wait_keymgr_done(ns6, "step1.csk-algorithm-roll.kasp")
templates.render("ns6/named.conf", {"csk_roll": True})
start_time = KeyTimingMetadata.now()
ns6.reconfigure()
# Calculate time passed to correctly check for next key events.
@ -49,8 +51,12 @@ def reconfigure(ns6, templates):
def test_algoroll_csk_reconfig_step1(ns6, alg, size):
zone = "step1.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step1.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The RSASHA keys are outroducing.
@ -65,8 +71,12 @@ def test_algoroll_csk_reconfig_step1(ns6, alg, size):
def test_algoroll_csk_reconfig_step2(ns6, alg, size):
zone = "step2.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step2.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The RSASHA keys are outroducing, but need to stay present
@ -88,8 +98,12 @@ def test_algoroll_csk_reconfig_step2(ns6, alg, size):
def test_algoroll_csk_reconfig_step3(ns6, alg, size):
zone = "step3.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step3.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The DS can be swapped.
@ -104,8 +118,12 @@ def test_algoroll_csk_reconfig_step3(ns6, alg, size):
def test_algoroll_csk_reconfig_step4(ns6, alg, size):
zone = "step4.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step4.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The old DS is HIDDEN, we can remove the old algorithm records.
@ -120,8 +138,12 @@ def test_algoroll_csk_reconfig_step4(ns6, alg, size):
def test_algoroll_csk_reconfig_step5(ns6, alg, size):
zone = "step5.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step5.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The DNSKEY becomes HIDDEN.
@ -140,8 +162,12 @@ def test_algoroll_csk_reconfig_step5(ns6, alg, size):
def test_algoroll_csk_reconfig_step6(ns6, alg, size):
zone = "step6.csk-algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step6.csk-algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The zone signatures are now HIDDEN.

View file

@ -24,9 +24,12 @@ from common import (
def test_algoroll_ksk_zsk_initial(ns6):
config = ALGOROLL_CONFIG
policy = "rsasha256"
zone = "step1.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone)
step = {
"zone": "step1.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"ksk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}",

View file

@ -39,9 +39,11 @@ TIME_PASSED = 0 # set in reconfigure() fixture
@pytest.fixture(scope="module", autouse=True)
def reconfigure(ns6, templates):
global TIME_PASSED # pylint: disable=global-statement
start_time = KeyTimingMetadata.now()
isctest.kasp.wait_keymgr_done(ns6, "step1.algorithm-roll.kasp")
templates.render("ns6/named.conf", {"alg_roll": True})
start_time = KeyTimingMetadata.now()
ns6.reconfigure()
# Calculate time passed to correctly check for next key events.
@ -49,8 +51,12 @@ def reconfigure(ns6, templates):
def test_algoroll_ksk_zsk_reconfig_step1(ns6, alg, size):
zone = "step1.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step1.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The RSASHA keys are outroducing.
@ -67,8 +73,12 @@ def test_algoroll_ksk_zsk_reconfig_step1(ns6, alg, size):
def test_algoroll_ksk_zsk_reconfig_step2(ns6, alg, size):
zone = "step2.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step2.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The RSASHA keys are outroducing, but need to stay present
@ -92,8 +102,12 @@ def test_algoroll_ksk_zsk_reconfig_step2(ns6, alg, size):
def test_algoroll_ksk_zsk_reconfig_step3(ns6, alg, size):
zone = "step3.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step3.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The DS can be swapped.
@ -110,8 +124,12 @@ def test_algoroll_ksk_zsk_reconfig_step3(ns6, alg, size):
def test_algoroll_ksk_zsk_reconfig_step4(ns6, alg, size):
zone = "step4.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step4.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The old DS is HIDDEN, we can remove the old algorithm records.
@ -128,8 +146,12 @@ def test_algoroll_ksk_zsk_reconfig_step4(ns6, alg, size):
def test_algoroll_ksk_zsk_reconfig_step5(ns6, alg, size):
zone = "step5.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step5.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The DNSKEY becomes HIDDEN.
@ -150,8 +172,12 @@ def test_algoroll_ksk_zsk_reconfig_step5(ns6, alg, size):
def test_algoroll_ksk_zsk_reconfig_step6(ns6, alg, size):
zone = "step6.algorithm-roll.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": "step6.algorithm-roll.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
# The zone signatures are now HIDDEN.

View file

@ -63,9 +63,13 @@ OFFSETS["step8-s"] = OFFSETS["step7-s"] - int(CONFIG["purge-keys"].total_seconds
def test_csk_roll1_step1(alg, size, ns3):
zone = "step1.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Introduce the first key. This will immediately be active.
"zone": "step1.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}",
@ -79,6 +83,10 @@ def test_csk_roll1_step1(alg, size, ns3):
def test_csk_roll1_step2(alg, size, ns3):
zone = "step2.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Successor CSK is prepublished (signs DNSKEY RRset, but not yet
# other RRsets).
@ -86,7 +94,7 @@ def test_csk_roll1_step2(alg, size, ns3):
# CSK2 goal: hidden -> omnipresent
# CSK2 dnskey: hidden -> rumoured
# CSK2 krrsig: hidden -> rumoured
"zone": "step2.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
@ -100,11 +108,15 @@ def test_csk_roll1_step2(alg, size, ns3):
def test_csk_roll1_step3(alg, size, ns3):
zone = "step3.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Successor CSK becomes omnipresent, meaning we can start signing
# the remainder of the zone with the successor CSK, and we can
# submit the DS.
"zone": "step3.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
# Predecessor CSK will be removed, so moving to UNRETENTIVE.
# CSK1 zrrsig: omnipresent -> unretentive
@ -134,8 +146,12 @@ def test_csk_roll1_step3(alg, size, ns3):
def test_csk_roll1_step4(alg, size, ns3):
zone = "step4.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step4.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor CSK is no longer signing the DNSKEY RRset.
# CSK1 krrsig: omnipresent -> unretentive
@ -157,8 +173,12 @@ def test_csk_roll1_step4(alg, size, ns3):
def test_csk_roll1_step5(alg, size, ns3):
zone = "step5.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step5.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor KRRSIG records are now all hidden.
# CSK1 krrsig: unretentive -> hidden
@ -176,8 +196,12 @@ def test_csk_roll1_step5(alg, size, ns3):
def test_csk_roll1_step6(alg, size, ns3):
zone = "step6.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step6.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor ZRRSIG records are now all hidden (so the DNSKEY
# can be removed).
@ -197,8 +221,12 @@ def test_csk_roll1_step6(alg, size, ns3):
def test_csk_roll1_step7(alg, size, ns3):
zone = "step7.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step7.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor CSK is now completely HIDDEN.
"keyprops": [
@ -215,8 +243,12 @@ def test_csk_roll1_step7(alg, size, ns3):
def test_csk_roll1_step8(alg, size, ns3):
zone = "step8.csk-roll1.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step8.csk-roll1.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step8-s']}",

View file

@ -66,9 +66,13 @@ OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(timedelta(days=90).total_seconds()
def test_csk_roll2_step1(alg, size, ns3):
zone = "step1.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Introduce the first key. This will immediately be active.
"zone": "step1.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}",
@ -82,6 +86,10 @@ def test_csk_roll2_step1(alg, size, ns3):
def test_csk_roll2_step2(alg, size, ns3):
zone = "step2.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Successor CSK is prepublished (signs DNSKEY RRset, but not yet
# other RRsets).
@ -89,7 +97,7 @@ def test_csk_roll2_step2(alg, size, ns3):
# CSK2 goal: hidden -> omnipresent
# CSK2 dnskey: hidden -> rumoured
# CSK2 krrsig: hidden -> rumoured
"zone": "step2.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
@ -103,11 +111,15 @@ def test_csk_roll2_step2(alg, size, ns3):
def test_csk_roll2_step3(alg, size, ns3):
zone = "step3.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Successor CSK becomes omnipresent, meaning we can start signing
# the remainder of the zone with the successor CSK, and we can
# submit the DS.
"zone": "step3.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
# Predecessor CSK will be removed, so moving to UNRETENTIVE.
# CSK1 zrrsig: omnipresent -> unretentive
@ -137,8 +149,12 @@ def test_csk_roll2_step3(alg, size, ns3):
def test_csk_roll2_step4(alg, size, ns3):
zone = "step4.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step4.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor ZRRSIG is HIDDEN. The successor ZRRSIG is
# OMNIPRESENT.
@ -162,8 +178,12 @@ def test_csk_roll2_step4(alg, size, ns3):
def test_csk_roll2_step5(alg, size, ns3):
zone = "step5.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step5.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor DNSKEY can be removed.
# CSK1 dnskey: omnipresent -> unretentive
@ -184,8 +204,12 @@ def test_csk_roll2_step5(alg, size, ns3):
def test_csk_roll2_step6(alg, size, ns3):
zone = "step6.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step6.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor CSK is now completely HIDDEN.
# CSK1 dnskey: unretentive -> hidden
@ -203,8 +227,12 @@ def test_csk_roll2_step6(alg, size, ns3):
def test_csk_roll2_step7(alg, size, ns3):
zone = "step7.csk-roll2.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step7.csk-roll2.autosign",
"zone": zone,
"cdss": CDSS,
# The predecessor CSK is now completely HIDDEN.
"keyprops": [

View file

@ -24,9 +24,12 @@ from common import (
def test_dynamic2inline(alg, size, ns6, templates):
config = DEFAULT_CONFIG
policy = "default"
zone = "dynamic2inline.kasp"
isctest.kasp.wait_keymgr_done(ns6, zone)
step = {
"zone": "dynamic2inline.kasp",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
@ -38,5 +41,6 @@ def test_dynamic2inline(alg, size, ns6, templates):
templates.render("ns6/named.conf", {"change_lifetime": True})
ns6.reconfigure()
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
isctest.kasp.check_rollover_step(ns6, config, policy, step)

View file

@ -45,8 +45,12 @@ OFFSETS["step4"] = -int(IPUBC.total_seconds() + IRETKSK.total_seconds())
def test_rollover_enable_dnssec_step1(alg, size, ns3):
zone = "step1.enable-dnssec.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step1.enable-dnssec.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"csk unlimited {alg} {size} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden offset:{OFFSETS['step1']}",
@ -59,8 +63,12 @@ def test_rollover_enable_dnssec_step1(alg, size, ns3):
def test_rollover_enable_dnssec_step2(alg, size, ns3):
zone = "step2.enable-dnssec.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step2.enable-dnssec.autosign",
"zone": zone,
"cdss": CDSS,
# The DNSKEY is omnipresent, but the zone signatures not yet.
# Thus, the DS remains hidden.
@ -77,8 +85,12 @@ def test_rollover_enable_dnssec_step2(alg, size, ns3):
def test_rollover_enable_dnssec_step3(alg, size, ns3):
zone = "step3.enable-dnssec.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step3.enable-dnssec.autosign",
"zone": zone,
"cdss": CDSS,
# All signatures should be omnipresent, so the DS can be submitted.
# zrrsig: rumoured -> omnipresent
@ -94,8 +106,12 @@ def test_rollover_enable_dnssec_step3(alg, size, ns3):
def test_rollover_enable_dnssec_step4(alg, size, ns3):
zone = "step4.enable-dnssec.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": "step4.enable-dnssec.autosign",
"zone": zone,
"cdss": CDSS,
# DS has been published long enough.
# ds: rumoured -> omnipresent

View file

@ -34,8 +34,12 @@ from common import (
def test_going_insecure_initial(zone, ns6, alg, size):
config = UNSIGNING_CONFIG
policy = "unsigning"
zone = f"step1.{zone}"
isctest.kasp.wait_keymgr_done(ns6, zone)
step = {
"zone": f"step1.{zone}",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"ksk 0 {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}",

View file

@ -41,11 +41,14 @@ def reconfigure_policy(ns6, templates):
def test_going_insecure_reconfig_step1(zone, alg, size, ns6):
config = DEFAULT_CONFIG
policy = "insecure"
zone = f"step1.{zone}"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
# Key goal states should be HIDDEN.
# The DS may be removed if we are going insecure.
step = {
"zone": f"step1.{zone}",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"ksk 0 {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{-DURATION['P10D']}",
@ -71,12 +74,15 @@ def test_going_insecure_reconfig_step1(zone, alg, size, ns6):
def test_going_insecure_reconfig_step2(zone, alg, size, ns6):
config = DEFAULT_CONFIG
policy = "insecure"
zone = f"step2.{zone}"
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
# The DS is long enough removed from the zone to be considered
# HIDDEN. This means the DNSKEY and the KSK signatures can be
# removed.
step = {
"zone": f"step2.{zone}",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"ksk 0 {alg} {size} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{-DURATION['P10D']}",

View file

@ -37,6 +37,8 @@ def test_rollover_ksk_three_is_a_crowd(alg, size, ns3):
"""Test #2375: Scheduled rollovers are happening faster than they can finish."""
zone = "three-is-a-crowd.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
"zone": zone,
"cdss": CDSS,

View file

@ -46,9 +46,13 @@ OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_sec
def test_ksk_doubleksk_step1(alg, size, ns3):
zone = "step1.ksk-doubleksk.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Introduce the first key. This will immediately be active.
"zone": "step1.ksk-doubleksk.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}",
@ -63,13 +67,17 @@ def test_ksk_doubleksk_step1(alg, size, ns3):
def test_ksk_doubleksk_step2(alg, size, ns3):
zone = "step2.ksk-doubleksk.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Successor KSK is prepublished (and signs DNSKEY RRset).
# KSK1 goal: omnipresent -> hidden
# KSK2 goal: hidden -> omnipresent
# KSK2 dnskey: hidden -> rumoured
# KSK2 krrsig: hidden -> rumoured
"zone": "step2.ksk-doubleksk.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}",
@ -84,6 +92,10 @@ def test_ksk_doubleksk_step2(alg, size, ns3):
def test_ksk_doubleksk_step3(alg, size, ns3):
zone = "step3.ksk-doubleksk.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# The successor DNSKEY RRset has become omnipresent. The
# predecessor DS can be withdrawn and the successor DS can be
@ -92,7 +104,7 @@ def test_ksk_doubleksk_step3(alg, size, ns3):
# KSK2 dnskey: rumoured -> omnipresent
# KSK2 krrsig: rumoured -> omnipresent
# KSK2 ds: hidden -> rumoured
"zone": "step3.ksk-doubleksk.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}",
@ -110,6 +122,10 @@ def test_ksk_doubleksk_step3(alg, size, ns3):
def test_ksk_doubleksk_step4(alg, size, ns3):
zone = "step4.ksk-doubleksk.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# The predecessor DNSKEY may be removed, the successor DS is
# omnipresent.
@ -117,7 +133,7 @@ def test_ksk_doubleksk_step4(alg, size, ns3):
# KSK1 krrsig: omnipresent -> unretentive
# KSK1 ds: unretentive -> hidden
# KSK2 ds: rumoured -> omnipresent
"zone": "step4.ksk-doubleksk.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}",
@ -133,12 +149,16 @@ def test_ksk_doubleksk_step4(alg, size, ns3):
def test_ksk_doubleksk_step5(alg, size, ns3):
zone = "step5.ksk-doubleksk.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# The predecessor DNSKEY is long enough removed from the zone it
# has become hidden.
# KSK1 dnskey: unretentive -> hidden
# KSK1 krrsig: unretentive -> hidden
"zone": "step5.ksk-doubleksk.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-p']}",
@ -154,9 +174,13 @@ def test_ksk_doubleksk_step5(alg, size, ns3):
def test_ksk_doubleksk_step6(alg, size, ns3):
zone = "step6.ksk-doubleksk.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Predecessor KSK is now purged.
"zone": "step6.ksk-doubleksk.autosign",
"zone": zone,
"cdss": CDSS,
"keyprops": [
f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-p']}",

View file

@ -37,6 +37,8 @@ from common import (
def test_lifetime_initial(zone, policy, lifetime, alg, size, ns6):
config = DEFAULT_CONFIG
isctest.kasp.wait_keymgr_done(ns6, zone)
step = {
"zone": zone,
"cdss": CDSS,

View file

@ -27,6 +27,11 @@ from common import (
@pytest.fixture(scope="module", autouse=True)
def reconfigure_policy(ns6, templates):
isctest.kasp.wait_keymgr_done(ns6, "shorter-lifetime")
isctest.kasp.wait_keymgr_done(ns6, "longer-lifetime")
isctest.kasp.wait_keymgr_done(ns6, "limit-lifetime")
isctest.kasp.wait_keymgr_done(ns6, "unlimit-lifetime")
templates.render("ns6/named.conf", {"change_lifetime": True})
ns6.reconfigure()
@ -47,6 +52,8 @@ def reconfigure_policy(ns6, templates):
def test_lifetime_reconfig(zone, policy, lifetime, alg, size, ns6):
config = DEFAULT_CONFIG
isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True)
step = {
"zone": zone,
"cdss": CDSS,

View file

@ -62,6 +62,8 @@ def test_rollover_multisigner(ns3, alg, size):
zone = "multisigner-model2.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
isctest.kasp.check_dnssec_verify(ns3, zone)
key_properties = [
@ -138,6 +140,8 @@ def test_rollover_multisigner(ns3, alg, size):
# keys in the desired key range.
zone = "single-to-multisigner.kasp"
isctest.kasp.wait_keymgr_done(ns3, zone)
isctest.kasp.check_dnssec_verify(ns3, zone)
key_properties = [

View file

@ -35,6 +35,8 @@ def test_straight2none_initial(zone, ns6, alg, size):
config = DEFAULT_CONFIG
policy = "default"
isctest.kasp.wait_keymgr_done(ns6, zone)
step = {
"zone": zone,
"cdss": CDSS,

View file

@ -26,6 +26,9 @@ from common import (
@pytest.fixture(scope="module", autouse=True)
def reconfigure_policy(ns6, templates):
isctest.kasp.wait_keymgr_done(ns6, "going-straight-to-none.kasp")
isctest.kasp.wait_keymgr_done(ns6, "going-straight-to-none-dynamic.kasp")
templates.render("ns6/named.conf", {"policy": "none"})
ns6.reconfigure()

View file

@ -55,9 +55,13 @@ OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(CONFIG["purge-keys"].total_seconds
def test_zsk_prepub_step1(alg, size, ns3):
zone = "step1.zsk-prepub.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# Introduce the first key. This will immediately be active.
"zone": "step1.zsk-prepub.autosign",
"zone": zone,
"keyprops": [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}",
f"zsk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}",
@ -71,12 +75,16 @@ def test_zsk_prepub_step1(alg, size, ns3):
def test_zsk_prepub_step2(alg, size, ns3):
zone = "step2.zsk-prepub.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# it is time to pre-publish the successor zsk.
# zsk1 goal: omnipresent -> hidden
# zsk2 goal: hidden -> omnipresent
# zsk2 dnskey: hidden -> rumoured
"zone": "step2.zsk-prepub.autosign",
"zone": zone,
"keyprops": [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}",
f"zsk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}",
@ -91,13 +99,17 @@ def test_zsk_prepub_step2(alg, size, ns3):
def test_zsk_prepub_step3(alg, size, ns3):
zone = "step3.zsk-prepub.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# predecessor zsk is no longer actively signing. successor zsk is
# now actively signing.
# zsk1 zrrsig: omnipresent -> unretentive
# zsk2 dnskey: rumoured -> omnipresent
# zsk2 zrrsig: hidden -> rumoured
"zone": "step3.zsk-prepub.autosign",
"zone": zone,
"keyprops": [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}",
f"zsk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent zrrsig:unretentive offset:{OFFSETS['step3-p']}",
@ -116,13 +128,17 @@ def test_zsk_prepub_step3(alg, size, ns3):
def test_zsk_prepub_step4(alg, size, ns3):
zone = "step4.zsk-prepub.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# predecessor zsk is no longer needed. all rrsets are signed with
# the successor zsk.
# zsk1 dnskey: omnipresent -> unretentive
# zsk1 zrrsig: unretentive -> hidden
# zsk2 zrrsig: rumoured -> omnipresent
"zone": "step4.zsk-prepub.autosign",
"zone": zone,
"keyprops": [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-p']}",
f"zsk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:unretentive zrrsig:hidden offset:{OFFSETS['step4-p']}",
@ -137,10 +153,14 @@ def test_zsk_prepub_step4(alg, size, ns3):
def test_zsk_prepub_step5(alg, size, ns3):
zone = "step5.zsk-prepub.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# predecessor zsk is now removed.
# zsk1 dnskey: unretentive -> hidden
"zone": "step5.zsk-prepub.autosign",
"zone": zone,
"keyprops": [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-p']}",
f"zsk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:hidden zrrsig:hidden offset:{OFFSETS['step5-p']}",
@ -156,9 +176,13 @@ def test_zsk_prepub_step5(alg, size, ns3):
def test_zsk_prepub_step6(alg, size, ns3):
zone = "step6.zsk-prepub.autosign"
isctest.kasp.wait_keymgr_done(ns3, zone)
step = {
# predecessor zsk is now purged.
"zone": "step6.zsk-prepub.autosign",
"zone": zone,
"keyprops": [
f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-p']}",
f"zsk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-s']}",

View file

@ -36,8 +36,7 @@ def test_rollover_manual(ns3):
size = os.environ["DEFAULT_BITS"]
zone = "manual-rollover.kasp"
with ns3.watch_log_from_start() as watcher:
watcher.wait_for_line(f"keymgr: {zone} done")
isctest.kasp.wait_keymgr_done(ns3, zone)
isctest.kasp.check_dnssec_verify(ns3, zone)