rollover-going-insecure: From setup.sh to pytest bootstrap

Symlink ns1 and ns2 to rollover/ns1 and rollover/ns2.
Symlink ns3/template.db.j2.manual to rollover/ns3/template.db.j2.manual.

Since the bootstrapping is done before the templates are rendered
automatically, replace @DEFAULT_ALGORITHM@ in ns3/kasp.conf.j2 to
ecdsa256 and rename to ns3/kasp.conf.

Now we have to fake different lifetimes, so adjust fake_lifetime
to update a single key.

Note that we have changed the setup slightly: We also sign the
step2 zones, but with post validation disabled. This is more
accurate because we need to test that the public keys and signatures
are being removed from the zone.

(cherry picked from commit cc4244f384)
This commit is contained in:
Matthijs Mekking 2025-11-28 10:43:42 +01:00
parent 5c499eb2c5
commit 40330867b1
10 changed files with 130 additions and 84 deletions

View file

@ -0,0 +1 @@
../rollover/ns1

View file

@ -0,0 +1 @@
../rollover/ns2

View file

@ -15,7 +15,7 @@ dnssec-policy "unsigning" {
dnskey-ttl 7200;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
ksk key-directory lifetime unlimited algorithm ecdsa256;
zsk key-directory lifetime P60D algorithm ecdsa256;
};
};

View file

@ -1 +0,0 @@
../../rollover/ns3/template.db.in

View file

@ -0,0 +1 @@
../../rollover/ns3/template.db.j2.manual

View file

@ -0,0 +1 @@
../../_common/trusted.conf.j2

View file

@ -1,71 +0,0 @@
#!/bin/sh -e
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. ../conf.sh
cd "ns3"
setup() {
zone="$1"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
}
# Make lines shorter by storing key states in environment variables.
H="HIDDEN"
R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
# The child zones (step1, step2) beneath these zones represent the various
# steps of unsigning a zone.
for zn in going-insecure.kasp going-insecure-dynamic.kasp; do
# Step 1:
# Set up a zone with dnssec-policy that is going insecure.
setup step1.$zn
echo "$zone" >>zones
T="now-10d"
S="now-12955mi"
keytimes="-P $T -A $T"
cdstimes="-P sync $S"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $cdstimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2)
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# Set up a zone with dnssec-policy that is going insecure. Don't add
# this zone to the zones file, because this zone is no longer expected
# to be fully signed.
setup step2.$zn
# The DS was withdrawn from the parent zone 26 hours ago.
D="now-26h"
keytimes="-P $T -A $T -I $D -D now"
cdstimes="-P sync $S -D sync $D"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $cdstimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $T -r $O $T -d $U $D -D ds $D "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK}.state"
echo "Lifetime: 5184000" >>"${ZSK}.state"
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
done

View file

@ -22,6 +22,28 @@ from rollover.common import (
DURATION,
UNSIGNING_CONFIG,
)
from rollover.setup import (
configure_root,
configure_tld,
configure_going_insecure,
)
def bootstrap():
data = {
"tlds": [],
"trust_anchors": [],
}
tlds = []
tld_name = "kasp"
delegations = configure_going_insecure(tld_name, reconfig=False)
tld = configure_tld(tld_name, delegations)
tlds.append(tld)
data["tlds"].append(tld_name)
ta = configure_root(tlds)
data["trust_anchors"].append(ta)
return data
@pytest.mark.parametrize(

View file

@ -23,6 +23,28 @@ from rollover.common import (
DURATION,
UNSIGNING_CONFIG,
)
from rollover.setup import (
configure_root,
configure_tld,
configure_going_insecure,
)
def bootstrap():
data = {
"tlds": [],
"trust_anchors": [],
}
tlds = []
tld_name = "kasp"
delegations = configure_going_insecure(tld_name, reconfig=True)
tld = configure_tld(tld_name, delegations)
tlds.append(tld)
data["tlds"].append(tld_name)
ta = configure_root(tlds)
data["trust_anchors"].append(ta)
return data
@pytest.fixture(scope="module", autouse=True)

View file

@ -94,13 +94,12 @@ def configure_root(delegations: List[Zone]) -> TrustAnchor:
return ksk.into_ta("static-ds")
def fake_lifetime(keys: List[str]):
def fake_lifetime(key: str, lifetime: int):
"""
Fake lifetime of old algorithm keys.
Fake lifetime of key.
"""
for key in keys:
with open(f"ns3/{key}.state", "a") as statefile:
statefile.write("Lifetime: 0\n")
with open(f"ns3/{key}.state", "a", encoding="utf-8") as statefile:
statefile.write(f"Lifetime: {lifetime}\n")
def set_key_relationship(key1: str, key2: str):
@ -363,7 +362,8 @@ def configure_algo_ksk_zsk(tld: str, reconfig: bool = False) -> List[Zone]:
cwd="ns3",
)
# Signing.
fake_lifetime([ksk1_name, zsk1_name])
fake_lifetime(ksk1_name, 0)
fake_lifetime(zsk1_name, 0)
render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
# Step 3:
@ -404,7 +404,8 @@ def configure_algo_ksk_zsk(tld: str, reconfig: bool = False) -> List[Zone]:
cwd="ns3",
)
# Signing.
fake_lifetime([ksk1_name, zsk1_name])
fake_lifetime(ksk1_name, 0)
fake_lifetime(zsk1_name, 0)
render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
# Step 4:
@ -445,7 +446,8 @@ def configure_algo_ksk_zsk(tld: str, reconfig: bool = False) -> List[Zone]:
cwd="ns3",
)
# Signing.
fake_lifetime([ksk1_name, zsk1_name])
fake_lifetime(ksk1_name, 0)
fake_lifetime(zsk1_name, 0)
render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
# Step 5:
@ -486,7 +488,8 @@ def configure_algo_ksk_zsk(tld: str, reconfig: bool = False) -> List[Zone]:
cwd="ns3",
)
# Signing.
fake_lifetime([ksk1_name, zsk1_name])
fake_lifetime(ksk1_name, 0)
fake_lifetime(zsk1_name, 0)
render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
# Step 6:
@ -526,7 +529,8 @@ def configure_algo_ksk_zsk(tld: str, reconfig: bool = False) -> List[Zone]:
cwd="ns3",
)
# Signing.
fake_lifetime([ksk1_name, zsk1_name])
fake_lifetime(ksk1_name, 0)
fake_lifetime(zsk1_name, 0)
render_and_sign_zone(zonename, [ksk1_name, zsk1_name, ksk2_name, zsk2_name])
return zones
@ -1283,3 +1287,69 @@ def configure_enable_dnssec(tld: str, policy: str) -> List[Zone]:
render_and_sign_zone(zonename, [csk_name], extra_options="-z")
return zones
def configure_going_insecure(tld: str, reconfig: bool = False) -> List[Zone]:
zones = []
keygen = CmdHelper("KEYGEN", "-a ECDSA256 -L 7200")
settime = CmdHelper("SETTIME", "-s")
# The child zones (step1, step2) beneath these zones represent the various
# steps of unsigning a zone.
for zone in [f"going-insecure.{tld}", f"going-insecure-dynamic.{tld}"]:
# Set up a zone with dnssec-policy that is going insecure.
# Step 1:
zonename = f"step1.{zone}"
zones.append(Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3")))
isctest.log.info(f"setup {zonename}")
# Timing metadata.
TpubN = "now-10d"
TsbmN = "now-12955mi"
keytimes = f"-P {TpubN} -A {TpubN}"
cdstimes = f"-P sync {TsbmN}"
# Key generation.
ksk_name = keygen(f"-f KSK {keytimes} {cdstimes} {zonename}", cwd="ns3").strip()
zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").strip()
settime(
f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -d OMNIPRESENT {TpubN} {ksk_name}",
cwd="ns3",
)
settime(
f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}",
cwd="ns3",
)
# Signing.
render_and_sign_zone(zonename, [ksk_name, zsk_name])
if reconfig:
# Step 2:
zonename = f"step2.{zone}"
zones.append(
Zone(zonename, f"{zonename}.db", Nameserver("ns3", "10.53.0.3"))
)
isctest.log.info(f"setup {zonename}")
# The DS was withdrawn from the parent zone 26 hours ago.
TremN = "now-26h"
keytimes = f"-P {TpubN} -A {TpubN} -I {TremN} -D now"
cdstimes = f"-P sync {TsbmN} -D sync {TremN}"
# Key generation.
ksk_name = keygen(
f"-f KSK {keytimes} {cdstimes} {zonename}", cwd="ns3"
).strip()
zsk_name = keygen(f"{keytimes} {zonename}", cwd="ns3").strip()
settime(
f"-g HIDDEN -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} -d UNRETENTIVE {TremN} -D ds {TremN} {ksk_name}",
cwd="ns3",
)
settime(
f"-g HIDDEN -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}",
cwd="ns3",
)
# Fake lifetime of old algorithm keys.
fake_lifetime(ksk_name, 0)
fake_lifetime(zsk_name, 5184000)
# Signing.
render_and_sign_zone(zonename, [ksk_name, zsk_name], extra_options="-P")
return zones