mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 01:31:48 -04:00
Test migration to dnssec-policy, retire old keys
Migrating from 'auto-dnssec maintain;' to dnssec-policy did not work properly, mainly because the legacy keys were initialized badly. Earlier commit deals with migration where existing keys match the policy. This commit deals with migration where existing keys do not match the policy. In that case, named must not immediately delete the existing keys, but gracefully roll to the dnssec-policy. However, named did remove the existing keys immediately. This is because the legacy key states were initialized badly. Because those keys had their states initialized to HIDDEN or RUMOURED, the keymgr decides that they can be removed (because only when the key has its states in OMNIPRESENT it can be used safely). The original thought to initialize key states to HIDDEN (and RUMOURED to deal with existing keys) was to ensure that those keys will go through the required propagation time before the keymgr decides they can be used safely. However, those keys are already in the zone for a long time and making the key states represent otherwise is dangerous: keys may be pulled out of the zone while in fact they are required to establish the chain of trust. Fix initializing key states for existing keys by looking more closely at the time metadata. Add TTL and propagation delays to the time metadata and see if the DNSSEC records have been propagated. Initialize the state to OMNIPRESENT if so, otherwise initialize to RUMOURED. If the time metadata is in the future, or does not exist, keep initializing the state to HIDDEN. The added test makes sure that new keys matching the policy are introduced, but existing keys are kept in the zone until the new keys have been propagated.
This commit is contained in:
parent
a224754d59
commit
7f43520893
6 changed files with 187 additions and 8 deletions
|
|
@ -36,7 +36,7 @@ controls {
|
|||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/* This is a zone that migrates to dnssec-policy. */
|
||||
/* These are zones that migrate to dnssec-policy. */
|
||||
zone "migrate.kasp" {
|
||||
type master;
|
||||
file "migrate.kasp.db";
|
||||
|
|
@ -46,6 +46,15 @@ zone "migrate.kasp" {
|
|||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
zone "migrate-nomatch.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
/* These are alorithm rollover test zones. */
|
||||
zone "step1.algorithm-roll.kasp" {
|
||||
type master;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ controls {
|
|||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/* This is a zone that migrates to dnssec-policy. */
|
||||
/* These are zones that migrate to dnssec-policy. */
|
||||
zone "migrate.kasp" {
|
||||
type master;
|
||||
file "migrate.kasp.db";
|
||||
|
|
@ -43,6 +43,13 @@ zone "migrate.kasp" {
|
|||
dnssec-policy "migrate";
|
||||
};
|
||||
|
||||
zone "migrate-nomatch.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate-nomatch";
|
||||
};
|
||||
|
||||
/*
|
||||
* Zones for testing KSK/ZSK algorithm roll.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -57,3 +57,21 @@ dnssec-policy "migrate" {
|
|||
zsk key-directory lifetime P60D algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "migrate-nomatch" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm rsasha1 2048;
|
||||
zsk key-directory lifetime P60D algorithm rsasha1 2048;
|
||||
};
|
||||
|
||||
// Together 12h
|
||||
zone-propagation-delay 3600;
|
||||
max-zone-ttl 11h;
|
||||
|
||||
// Together 24h
|
||||
parent-registration-delay 21h;
|
||||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,6 +51,22 @@ private_type_record $zone 5 "$KSK" >> "$infile"
|
|||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
|
||||
# time the existing keys do not match the policy.
|
||||
setup migrate-nomatch.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -b 1024 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
|
||||
Tkey="now-3900s" # DNSKEY TTL + propagation delay
|
||||
Tsig="now-12h" # Zone's maximum TTL + propagation delay
|
||||
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
#
|
||||
# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
|
||||
# algorithm rollover.
|
||||
|
|
|
|||
|
|
@ -2917,6 +2917,58 @@ dnssec_verify
|
|||
_migrate_ksk=$(key_get KEY1 ID)
|
||||
_migrate_zsk=$(key_get KEY2 ID)
|
||||
|
||||
#
|
||||
# Testing migration with unmatched existing keys.
|
||||
#
|
||||
set_zone "migrate-nomatch.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_nomatch() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keyalgorithm "KEY1" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DS" "omnipresent"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
|
||||
}
|
||||
init_migration_nomatch
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migratenomatch_ksk=$(key_get KEY1 ID)
|
||||
_migratenomatch_zsk=$(key_get KEY2 ID)
|
||||
|
||||
# Reconfig dnssec-policy (triggering algorithm roll and other dnssec-policy
|
||||
# changes).
|
||||
echo_i "reconfig dnssec-policy to trigger algorithm rollover"
|
||||
|
|
@ -2980,6 +3032,64 @@ ret=0
|
|||
[ $_migrate_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
# Test migration to dnssec-policy, existing keys do not match.
|
||||
set_zone "migrate-nomatch.kasp"
|
||||
set_policy "migrate-nomatch" "4" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# The legacy keys need to be retired, but otherwise stay present until the
|
||||
# new keys are omnipresent, and can be used to construct a chain of trust.
|
||||
init_migration_nomatch
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
set_keytime "KEY1" "RETIRED" "yes"
|
||||
set_keystate "KEY1" "GOAL" "hidden"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
set_keystate "KEY2" "GOAL" "hidden"
|
||||
|
||||
set_keyrole "KEY3" "ksk"
|
||||
set_keylifetime "KEY3" "0"
|
||||
set_keyalgorithm "KEY3" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY3" "yes"
|
||||
set_zonesigning "KEY3" "no"
|
||||
|
||||
set_keyrole "KEY4" "zsk"
|
||||
set_keylifetime "KEY4" "5184000"
|
||||
set_keyalgorithm "KEY4" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY4" "no"
|
||||
# This key is not active yet, first the DNSKEY needs to be omnipresent.
|
||||
set_zonesigning "KEY4" "no"
|
||||
|
||||
set_keytime "KEY3" "PUBLISHED" "yes"
|
||||
set_keytime "KEY3" "ACTIVE" "yes"
|
||||
set_keytime "KEY3" "RETIRED" "none"
|
||||
set_keystate "KEY3" "GOAL" "omnipresent"
|
||||
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY3" "STATE_DS" "hidden"
|
||||
|
||||
set_keytime "KEY4" "PUBLISHED" "yes"
|
||||
set_keytime "KEY4" "ACTIVE" "yes"
|
||||
set_keytime "KEY4" "RETIRED" "yes"
|
||||
set_keystate "KEY4" "GOAL" "omnipresent"
|
||||
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY4" "STATE_ZRRSIG" "hidden"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
|
||||
ret=0
|
||||
[ $_migratenomatch_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migratenomatch_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
#
|
||||
# Testing KSK/ZSK algorithm rollover.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1228,7 +1228,7 @@ transition:
|
|||
*
|
||||
*/
|
||||
static void
|
||||
keymgr_key_init(dns_dnsseckey_t *key, isc_stdtime_t now) {
|
||||
keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
|
||||
bool ksk, zsk;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t active = 0, pub = 0, syncpub = 0;
|
||||
|
|
@ -1254,15 +1254,34 @@ keymgr_key_init(dns_dnsseckey_t *key, isc_stdtime_t now) {
|
|||
/* Get time metadata. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
|
||||
if (active <= now && ret == ISC_R_SUCCESS) {
|
||||
dnskey_state = RUMOURED;
|
||||
dns_ttl_t key_ttl = dst_key_getttl(key->key);
|
||||
key_ttl += dns_kasp_zonepropagationdelay(kasp);
|
||||
if ((active + key_ttl) <= now) {
|
||||
dnskey_state = OMNIPRESENT;
|
||||
} else {
|
||||
dnskey_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
|
||||
if (pub <= now && ret == ISC_R_SUCCESS) {
|
||||
zrrsig_state = RUMOURED;
|
||||
dns_ttl_t zone_ttl = dns_kasp_zonemaxttl(kasp);
|
||||
zone_ttl += dns_kasp_zonepropagationdelay(kasp);
|
||||
if ((pub + zone_ttl) <= now) {
|
||||
zrrsig_state = OMNIPRESENT;
|
||||
} else {
|
||||
zrrsig_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_SYNCPUBLISH, &syncpub);
|
||||
if (syncpub <= now && ret == ISC_R_SUCCESS) {
|
||||
ds_state = RUMOURED;
|
||||
dns_ttl_t ds_ttl = dns_kasp_dsttl(kasp);
|
||||
ds_ttl += dns_kasp_parentregistrationdelay(kasp);
|
||||
ds_ttl += dns_kasp_parentpropagationdelay(kasp);
|
||||
if ((syncpub + ds_ttl) <= now) {
|
||||
ds_state = OMNIPRESENT;
|
||||
} else {
|
||||
ds_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set key states for all keys that do not have them. */
|
||||
|
|
@ -1342,7 +1361,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
{
|
||||
bool found_match = false;
|
||||
|
||||
keymgr_key_init(dkey, now);
|
||||
keymgr_key_init(dkey, kasp, now);
|
||||
|
||||
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
|
||||
kkey = ISC_LIST_NEXT(kkey, link))
|
||||
|
|
@ -1511,7 +1530,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
|||
dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
|
||||
dst_key_settime(dst_key, DST_TIME_CREATED, now);
|
||||
RETERR(dns_dnsseckey_create(mctx, &dst_key, &newkey));
|
||||
keymgr_key_init(newkey, now);
|
||||
keymgr_key_init(newkey, kasp, now);
|
||||
} else {
|
||||
newkey = candidate;
|
||||
dst_key_setnum(newkey->key, DST_NUM_LIFETIME, lifetime);
|
||||
|
|
|
|||
Loading…
Reference in a new issue