From feac3e94fc114c8862ca65b357ca48fdd81199a8 Mon Sep 17 00:00:00 2001 From: Tomas Krizek Date: Tue, 12 Mar 2019 18:47:35 +0100 Subject: [PATCH] modules/ta_update: move RFC5011 to a separate module --- .luacheckrc | 1 + daemon/lua/meson.build | 6 - daemon/lua/sandbox.lua | 1 + daemon/lua/trust_anchors.lua.in | 254 ++---------------- modules/meson.build | 4 + modules/ta_update/ta_update.lua | 248 +++++++++++++++++ .../ta_update.test.integr}/deckard.yaml | 2 +- .../ta_update.test.integr}/kresd_config.j2 | 0 .../rfc5011_unsupported_key_rollover.rpl | 0 9 files changed, 271 insertions(+), 245 deletions(-) create mode 100644 modules/ta_update/ta_update.lua rename {daemon/lua/trust_anchors.test.integr => modules/ta_update/ta_update.test.integr}/deckard.yaml (72%) rename {daemon/lua/trust_anchors.test.integr => modules/ta_update/ta_update.test.integr}/kresd_config.j2 (100%) rename {daemon/lua/trust_anchors.test.integr => modules/ta_update/ta_update.test.integr}/rfc5011_unsupported_key_rollover.rpl (100%) diff --git a/.luacheckrc b/.luacheckrc index 1729bd4b5..47608f478 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -14,6 +14,7 @@ new_read_globals = { 'cache', 'modules', 'trust_anchors', + 'ta_update', 'worker', 'event', '_hint_root_file', diff --git a/daemon/lua/meson.build b/daemon/lua/meson.build index e6e4eb963..d11bf7731 100644 --- a/daemon/lua/meson.build +++ b/daemon/lua/meson.build @@ -5,12 +5,6 @@ config_tests += [ ['ta_bootstrap', files('trust_anchors.test/bootstrap.test.lua')], ] -integr_tests += [ - # NOTE: ta_rfc5011 may fail due to race condition; to ensure it passes, deckard should - # introduce a timeout - ['ta_rfc5011', join_paths(meson.current_source_dir(), 'trust_anchors.test.integr')], -] - ta_config = configuration_data() ta_config.set('keyfile_default', keyfile_default) ta_config.set('etc_dir', etc_dir) diff --git a/daemon/lua/sandbox.lua b/daemon/lua/sandbox.lua index 017e3a399..79ebc4a61 100644 --- a/daemon/lua/sandbox.lua +++ b/daemon/lua/sandbox.lua @@ -316,6 +316,7 @@ end -- Load embedded modules trust_anchors = require('trust_anchors') +modules.load('ta_update') modules.load('ta_signal_query') modules.load('policy') modules.load('priming') diff --git a/daemon/lua/trust_anchors.lua.in b/daemon/lua/trust_anchors.lua.in index 472241015..a9eb1b3af 100644 --- a/daemon/lua/trust_anchors.lua.in +++ b/daemon/lua/trust_anchors.lua.in @@ -5,6 +5,12 @@ local C = ffi.C local trust_anchors -- the public pseudo-module, exported as global variable +-- RFC5011 state table +local key_state = { + Start = 'Start', AddPend = 'AddPend', Valid = 'Valid', + Missing = 'Missing', Revoked = 'Revoked', Removed = 'Removed' +} + -- Fetch over HTTPS with peert cert checked local function https_fetch(url, ca) local ssl_ok, https = pcall(require, 'ssl.https') @@ -152,179 +158,6 @@ local function bootstrap(url, ca) return rrset, msg end --- RFC5011 state table -local key_state = { - Start = 'Start', AddPend = 'AddPend', Valid = 'Valid', - Missing = 'Missing', Revoked = 'Revoked', Removed = 'Removed' -} - --- Find key in current keyset -local function ta_find(keyset, rr) - local rr_tag = C.kr_dnssec_key_tag(rr.type, rr.rdata, #rr.rdata) - assert(rr_tag >= 0 and rr_tag <= 65535, string.format('invalid RR: %s: %s', - kres.rr2str(rr), ffi.string(C.knot_strerror(rr_tag)))) - for i, ta in ipairs(keyset) do - -- Match key owner and content - local ta_tag = C.kr_dnssec_key_tag(ta.type, ta.rdata, #ta.rdata) - assert(ta_tag >= 0 and ta_tag <= 65535, string.format('invalid RR: %s: %s', - kres.rr2str(ta), ffi.string(C.knot_strerror(ta_tag)))) - if ta.owner == rr.owner then - if ta.type == rr.type then - if rr.type == kres.type.DNSKEY then - if C.kr_dnssec_key_match(ta.rdata, #ta.rdata, rr.rdata, #rr.rdata) == 0 then - return ta - end - elseif rr.type == kres.type.DS and ta.rdata == rr.rdata then - return ta - end - -- DNSKEY superseding DS, inexact match - elseif rr.type == kres.type.DNSKEY and ta.type == kres.type.DS then - if ta.key_tag == rr_tag then - keyset[i] = rr -- Replace current DS - rr.state = ta.state - rr.key_tag = ta.key_tag - return rr - end - -- DS key matching DNSKEY, inexact match - elseif rr.type == kres.type.DS and ta.type == kres.type.DNSKEY then - if rr_tag == ta_tag then - return ta - end - end - end - end - return nil -end - --- Evaluate TA status of a RR according to RFC5011. The time is in seconds. -local function ta_present(keyset, rr, hold_down_time, force_valid) - if rr.type == kres.type.DNSKEY and not C.kr_dnssec_key_ksk(rr.rdata) then - return false -- Ignore - end - -- Attempt to extract key_tag - local key_tag = C.kr_dnssec_key_tag(rr.type, rr.rdata, #rr.rdata) - if key_tag < 0 or key_tag > 65535 then - warn(string.format('[ ta ] ignoring invalid or unsupported RR: %s: %s', - kres.rr2str(rr), ffi.string(C.knot_strerror(key_tag)))) - return false - end - -- Find the key in current key set and check its status - local now = os.time() - local key_revoked = (rr.type == kres.type.DNSKEY) and C.kr_dnssec_key_revoked(rr.rdata) - local ta = ta_find(keyset, rr) - if ta then - -- Key reappears (KeyPres) - if ta.state == key_state.Missing then - ta.state = key_state.Valid - ta.timer = nil - end - -- Key is revoked (RevBit) - if ta.state == key_state.Valid or ta.state == key_state.Missing then - if key_revoked then - ta.state = key_state.Revoked - ta.timer = now + hold_down_time - end - end - -- Remove hold-down timer expires (RemTime) - if ta.state == key_state.Revoked and os.difftime(ta.timer, now) <= 0 then - ta.state = key_state.Removed - ta.timer = nil - end - -- Add hold-down timer expires (AddTime) - if ta.state == key_state.AddPend and os.difftime(ta.timer, now) <= 0 then - ta.state = key_state.Valid - ta.timer = nil - end - if rr.state ~= key_state.Valid or verbose() then - log('[ ta ] key: ' .. key_tag .. ' state: '..ta.state) - end - return true - elseif not key_revoked then -- First time seen (NewKey) - rr.key_tag = key_tag - if force_valid then - rr.state = key_state.Valid - else - rr.state = key_state.AddPend - rr.timer = now + hold_down_time - end - if rr.state ~= key_state.Valid or verbose() then - log('[ ta ] key: ' .. key_tag .. ' state: '..rr.state) - end - table.insert(keyset, rr) - return true - end - return false -end - --- TA is missing in the new key set. The time is in seconds. -local function ta_missing(ta, hold_down_time) - -- Key is removed (KeyRem) - local keep_ta = true - local key_tag = C.kr_dnssec_key_tag(ta.type, ta.rdata, #ta.rdata) - assert(key_tag >= 0 and key_tag <= 65535, string.format('invalid RR: %s: %s', - kres.rr2str(ta), ffi.string(C.knot_strerror(key_tag)))) - if ta.state == key_state.Valid then - ta.state = key_state.Missing - ta.timer = os.time() + hold_down_time - - -- Remove key that is missing for too long - elseif ta.state == key_state.Missing and os.difftime(ta.timer, os.time()) <= 0 then - ta.state = key_state.Removed - log('[ ta ] key: '..key_tag..' removed because missing for too long') - keep_ta = false - - -- Purge pending key - elseif ta.state == key_state.AddPend then - log('[ ta ] key: '..key_tag..' purging') - keep_ta = false - end - log('[ ta ] key: '..key_tag..' state: '..ta.state) - return keep_ta -end - -local active_refresh, update -- forwards - --- Plan an event for refreshing the root DNSKEYs and re-scheduling itself -local function refresh_plan(keyset, delay, is_initial) - local owner_str = kres.dname2str(keyset.owner) -- maybe fix converting back and forth? - keyset.refresh_ev = event.after(delay, function () - resolve(owner_str, kres.type.DNSKEY, kres.class.IN, 'NO_CACHE', - function (pkt) - -- Schedule itself with updated timeout - local delay_new = active_refresh(keyset, kres.pkt_t(pkt), is_initial) - delay_new = keyset.refresh_time or trust_anchors.refresh_time or delay_new - log('[ ta ] next refresh for ' .. owner_str .. ' in ' - .. delay_new/hour .. ' hours') - refresh_plan(keyset, delay_new) - end) - end) -end - --- Refresh the DNSKEYs from the packet, and return time to the next check. -active_refresh = function (keyset, pkt, is_initial) - local retry = true - if pkt:rcode() == kres.rcode.NOERROR then - local records = pkt:section(kres.section.ANSWER) - local new_keys = {} - for _, rr in ipairs(records) do - if rr.type == kres.type.DNSKEY then - table.insert(new_keys, rr) - end - end - update(keyset, new_keys, is_initial) - retry = false - else - warn('[ ta ] active refresh failed for ' .. kres.dname2str(keyset.owner) - .. ' with rcode: ' .. pkt:rcode()) - end - -- Calculate refresh/retry timer (RFC 5011, 2.3) - local min_ttl = retry and day or 15 * day - for _, rr in ipairs(keyset) do -- 10 or 50% of the original TTL - min_ttl = math.min(min_ttl, (retry and 100 or 500) * rr.ttl) - end - return math.max(hour, min_ttl) -end - -- Update ta.comment and return decorated line representing the RR -- This is meant to be in zone-file format. local function ta_rr_str(ta) @@ -465,68 +298,15 @@ local function keyset_publish(keyset) return count > 0 and not has_error end - --- Update existing keyset; return true if successful. --- Param `is_initial` (bool): force .NewKey states to .Valid, i.e. init empty keyset. -update = function (keyset, new_keys, is_initial) - if not new_keys then return false end - - -- Filter TAs to be purged from the keyset (KeyRem), in three steps - -- 1: copy TAs to be kept to `keepset` - local hold_down = (keyset.hold_down_time or trust_anchors.hold_down_time) / 1000 - local keepset = {} - local keep_removed = keyset.keep_removed or trust_anchors.keep_removed - for _, ta in ipairs(keyset) do - local keep = true - if not ta_find(new_keys, ta) then - -- Ad-hoc: RFC 5011 doesn't mention removing a Missing key. - -- Let's do it after a very long period has elapsed. - keep = ta_missing(ta, hold_down * 4) - end - -- Purge removed keys - if ta.state == key_state.Removed then - if keep_removed > 0 then - keep_removed = keep_removed - 1 - else - keep = false - end - end - if keep then - table.insert(keepset, ta) - end - end - -- 2: remove all TAs - other settings etc. will remain in the keyset - for i, _ in ipairs(keyset) do - keyset[i] = nil - end - -- 3: move TAs to be kept into the keyset (same indices) - for k, ta in pairs(keepset) do - keyset[k] = ta - end - - -- Evaluate new TAs - for _, rr in ipairs(new_keys) do - if (rr.type == kres.type.DNSKEY or rr.type == kres.type.DS) and rr.rdata ~= nil then - ta_present(keyset, rr, hold_down, is_initial) - end - end - - -- Store the keyset - keyset_write(keyset) - - -- Start using the new TAs. - if not keyset_publish(keyset) then - -- TODO: try to rebootstrap if for root? - return false - elseif verbose() then - log('[ ta ] refreshed trust anchors for domain ' .. kres.dname2str(keyset.owner) .. ' are:\n' - .. trust_anchors.summary(keyset.owner)) - end - - return true +local refresh_plan = function(keyset, delay, is_initial) + event.after(0, function() + if ta_update ~= nil then + ta_update.refresh_plan(keyset, delay, is_initial) + end + end) end -local add_file = function (path, unmanaged) +local function add_file(path, unmanaged) if not unmanaged then if not io.open(path .. '.lock', 'w') then error("[ ta ] ERROR: write access needed to keyfile dir '"..path.."'") @@ -613,16 +393,11 @@ trust_anchors = { -- - owner - that dname (for simplicity) -- - [optional] filename in which to persist the state, -- implying unmanaged TA if nil - -- - [optional] overrides for global defaults of - -- hold_down_time, refresh_time, keep_removed -- The RR tables also contain some additional TA-specific fields. keysets = {}, -- Documented properties: insecure = {}, - hold_down_time = 30 * day, - refresh_time = nil, - keep_removed = 0, bootstrap_url = 'https://data.iana.org/root-anchors/root-anchors.xml', bootstrap_ca = '@etc_dir@/icann-ca.pem', @@ -633,6 +408,9 @@ trust_anchors = { add_file = add_file, config = add_file, + keyset_write = keyset_write, + keyset_publish = keyset_publish, + -- Add DS/DNSKEY record(s) (unmanaged) add = function (keystr) local keyset, err = keyset_read(nil, keystr) diff --git a/modules/meson.build b/modules/meson.build index 0c3d7fb0d..dcadcbd82 100644 --- a/modules/meson.build +++ b/modules/meson.build @@ -14,6 +14,7 @@ lua_mod_src = [ # add lua modules without separate meson.build files('serve_stale/serve_stale.lua'), files('ta_sentinel/ta_sentinel.lua'), files('ta_signal_query/ta_signal_query.lua'), + files('ta_update/ta_update.lua'), files('workarounds/workarounds.lua'), ] @@ -28,6 +29,9 @@ integr_tests += [ ['bogus_log', join_paths(meson.current_source_dir(), 'bogus_log', 'test.integr')], ['rebinding', join_paths(meson.current_source_dir(), 'rebinding', 'test.integr')], ['serve_stale', join_paths(meson.current_source_dir(), 'serve_stale', 'test.integr')], + # NOTE: ta_update may pass in cases when it should fail due to race conditions + # To ensure reliability, deckard should introduce a time wait + ['ta_update', join_paths(meson.current_source_dir(), 'ta_update', 'ta_update.test.integr')], ] diff --git a/modules/ta_update/ta_update.lua b/modules/ta_update/ta_update.lua new file mode 100644 index 000000000..c683bbf9a --- /dev/null +++ b/modules/ta_update/ta_update.lua @@ -0,0 +1,248 @@ +-- Module interface +local ffi = require('ffi') +local kres = require('kres') +local C = ffi.C + +local ta_update = {} + +-- RFC5011 state table +local key_state = { + Start = 'Start', AddPend = 'AddPend', Valid = 'Valid', + Missing = 'Missing', Revoked = 'Revoked', Removed = 'Removed' +} + +-- Find key in current keyset +local function ta_find(keyset, rr) + local rr_tag = C.kr_dnssec_key_tag(rr.type, rr.rdata, #rr.rdata) + assert(rr_tag >= 0 and rr_tag <= 65535, string.format('invalid RR: %s: %s', + kres.rr2str(rr), ffi.string(C.knot_strerror(rr_tag)))) + for i, ta in ipairs(keyset) do + -- Match key owner and content + local ta_tag = C.kr_dnssec_key_tag(ta.type, ta.rdata, #ta.rdata) + assert(ta_tag >= 0 and ta_tag <= 65535, string.format('invalid RR: %s: %s', + kres.rr2str(ta), ffi.string(C.knot_strerror(ta_tag)))) + if ta.owner == rr.owner then + if ta.type == rr.type then + if rr.type == kres.type.DNSKEY then + if C.kr_dnssec_key_match(ta.rdata, #ta.rdata, rr.rdata, #rr.rdata) == 0 then + return ta + end + elseif rr.type == kres.type.DS and ta.rdata == rr.rdata then + return ta + end + -- DNSKEY superseding DS, inexact match + elseif rr.type == kres.type.DNSKEY and ta.type == kres.type.DS then + if ta.key_tag == rr_tag then + keyset[i] = rr -- Replace current DS + rr.state = ta.state + rr.key_tag = ta.key_tag + return rr + end + -- DS key matching DNSKEY, inexact match + elseif rr.type == kres.type.DS and ta.type == kres.type.DNSKEY then + if rr_tag == ta_tag then + return ta + end + end + end + end + return nil +end + +-- Evaluate TA status of a RR according to RFC5011. The time is in seconds. +local function ta_present(keyset, rr, hold_down_time, force_valid) +if rr.type == kres.type.DNSKEY and not C.kr_dnssec_key_ksk(rr.rdata) then + return false -- Ignore +end +-- Attempt to extract key_tag +local key_tag = C.kr_dnssec_key_tag(rr.type, rr.rdata, #rr.rdata) +if key_tag < 0 or key_tag > 65535 then + warn(string.format('[ ta_update ] ignoring invalid or unsupported RR: %s: %s', + kres.rr2str(rr), ffi.string(C.knot_strerror(key_tag)))) + return false +end +-- Find the key in current key set and check its status +local now = os.time() +local key_revoked = (rr.type == kres.type.DNSKEY) and C.kr_dnssec_key_revoked(rr.rdata) +local ta = ta_find(keyset, rr) +if ta then + -- Key reappears (KeyPres) + if ta.state == key_state.Missing then + ta.state = key_state.Valid + ta.timer = nil + end + -- Key is revoked (RevBit) + if ta.state == key_state.Valid or ta.state == key_state.Missing then + if key_revoked then + ta.state = key_state.Revoked + ta.timer = now + hold_down_time + end + end + -- Remove hold-down timer expires (RemTime) + if ta.state == key_state.Revoked and os.difftime(ta.timer, now) <= 0 then + ta.state = key_state.Removed + ta.timer = nil + end + -- Add hold-down timer expires (AddTime) + if ta.state == key_state.AddPend and os.difftime(ta.timer, now) <= 0 then + ta.state = key_state.Valid + ta.timer = nil + end + if rr.state ~= key_state.Valid or verbose() then + log('[ ta_update ] key: ' .. key_tag .. ' state: '..ta.state) + end + return true +elseif not key_revoked then -- First time seen (NewKey) + rr.key_tag = key_tag + if force_valid then + rr.state = key_state.Valid + else + rr.state = key_state.AddPend + rr.timer = now + hold_down_time + end + if rr.state ~= key_state.Valid or verbose() then + log('[ ta_update ] key: ' .. key_tag .. ' state: '..rr.state) + end + table.insert(keyset, rr) + return true + end + return false +end + +-- TA is missing in the new key set. The time is in seconds. +local function ta_missing(ta, hold_down_time) + -- Key is removed (KeyRem) + local keep_ta = true + local key_tag = C.kr_dnssec_key_tag(ta.type, ta.rdata, #ta.rdata) + assert(key_tag >= 0 and key_tag <= 65535, string.format('invalid RR: %s: %s', + kres.rr2str(ta), ffi.string(C.knot_strerror(key_tag)))) + if ta.state == key_state.Valid then + ta.state = key_state.Missing + ta.timer = os.time() + hold_down_time + + -- Remove key that is missing for too long + elseif ta.state == key_state.Missing and os.difftime(ta.timer, os.time()) <= 0 then + ta.state = key_state.Removed + log('[ ta_update ] key: '..key_tag..' removed because missing for too long') + keep_ta = false + + -- Purge pending key + elseif ta.state == key_state.AddPend then + log('[ ta_update ] key: '..key_tag..' purging') + keep_ta = false + end + log('[ ta_update ] key: '..key_tag..' state: '..ta.state) + return keep_ta +end + +-- Update existing keyset; return true if successful. +-- Param `is_initial` (bool): force .NewKey states to .Valid, i.e. init empty keyset. +local function update(keyset, new_keys, is_initial) + if not new_keys then return false end + + -- Filter TAs to be purged from the keyset (KeyRem), in three steps + -- 1: copy TAs to be kept to `keepset` + local hold_down = (keyset.hold_down_time or ta_update.hold_down_time) / 1000 + local keepset = {} + local keep_removed = keyset.keep_removed or ta_update.keep_removed + for _, ta in ipairs(keyset) do + local keep = true + if not ta_find(new_keys, ta) then + -- Ad-hoc: RFC 5011 doesn't mention removing a Missing key. + -- Let's do it after a very long period has elapsed. + keep = ta_missing(ta, hold_down * 4) + end + -- Purge removed keys + if ta.state == key_state.Removed then + if keep_removed > 0 then + keep_removed = keep_removed - 1 + else + keep = false + end + end + if keep then + table.insert(keepset, ta) + end + end + -- 2: remove all TAs - other settings etc. will remain in the keyset + for i, _ in ipairs(keyset) do + keyset[i] = nil + end + -- 3: move TAs to be kept into the keyset (same indices) + for k, ta in pairs(keepset) do + keyset[k] = ta + end + + -- Evaluate new TAs + for _, rr in ipairs(new_keys) do + if (rr.type == kres.type.DNSKEY or rr.type == kres.type.DS) and rr.rdata ~= nil then + ta_present(keyset, rr, hold_down, is_initial) + end + end + + -- Store the keyset + trust_anchors.keyset_write(keyset) + + -- Start using the new TAs. + if not trust_anchors.keyset_publish(keyset) then + -- TODO: try to rebootstrap if for root? + return false + elseif verbose() then + log('[ ta_update ] refreshed trust anchors for domain ' .. kres.dname2str(keyset.owner) .. ' are:\n' + .. trust_anchors.summary(keyset.owner)) + end + + return true +end + +-- Refresh the DNSKEYs from the packet, and return time to the next check. +local function active_refresh(keyset, pkt, is_initial) + local retry = true + if pkt:rcode() == kres.rcode.NOERROR then + local records = pkt:section(kres.section.ANSWER) + local new_keys = {} + for _, rr in ipairs(records) do + if rr.type == kres.type.DNSKEY then + table.insert(new_keys, rr) + end + end + update(keyset, new_keys, is_initial) + retry = false + else + warn('[ ta_update ] active refresh failed for ' .. kres.dname2str(keyset.owner) + .. ' with rcode: ' .. pkt:rcode()) + end + -- Calculate refresh/retry timer (RFC 5011, 2.3) + local min_ttl = retry and day or 15 * day + for _, rr in ipairs(keyset) do -- 10 or 50% of the original TTL + min_ttl = math.min(min_ttl, (retry and 100 or 500) * rr.ttl) + end + return math.max(hour, min_ttl) +end + +-- Plan an event for refreshing the root DNSKEYs and re-scheduling itself +local function refresh_plan(keyset, delay, is_initial) + local owner_str = kres.dname2str(keyset.owner) -- maybe fix converting back and forth? + keyset.refresh_ev = event.after(delay, function () + resolve(owner_str, kres.type.DNSKEY, kres.class.IN, 'NO_CACHE', + function (pkt) + -- Schedule itself with updated timeout + local delay_new = active_refresh(keyset, kres.pkt_t(pkt), is_initial) + delay_new = keyset.refresh_time or ta_update.refresh_time or delay_new + log('[ ta_update ] next refresh for ' .. owner_str .. ' in ' + .. delay_new/hour .. ' hours') + refresh_plan(keyset, delay_new) + end) + end) +end + +ta_update = { + -- - [optional] overrides for global defaults of + -- hold_down_time, refresh_time, keep_removed + hold_down_time = 30 * day, + refresh_time = nil, + keep_removed = 0, + refresh_plan = refresh_plan, +} + +return ta_update diff --git a/daemon/lua/trust_anchors.test.integr/deckard.yaml b/modules/ta_update/ta_update.test.integr/deckard.yaml similarity index 72% rename from daemon/lua/trust_anchors.test.integr/deckard.yaml rename to modules/ta_update/ta_update.test.integr/deckard.yaml index 4b71a6ba3..6906eeb1b 100644 --- a/daemon/lua/trust_anchors.test.integr/deckard.yaml +++ b/modules/ta_update/ta_update.test.integr/deckard.yaml @@ -5,7 +5,7 @@ programs: - -f - "1" templates: - - daemon/lua/trust_anchors.test.integr/kresd_config.j2 + - modules/ta_update/ta_update.test.integr/kresd_config.j2 - tests/integration/hints_zone.j2 configs: - config diff --git a/daemon/lua/trust_anchors.test.integr/kresd_config.j2 b/modules/ta_update/ta_update.test.integr/kresd_config.j2 similarity index 100% rename from daemon/lua/trust_anchors.test.integr/kresd_config.j2 rename to modules/ta_update/ta_update.test.integr/kresd_config.j2 diff --git a/daemon/lua/trust_anchors.test.integr/rfc5011_unsupported_key_rollover.rpl b/modules/ta_update/ta_update.test.integr/rfc5011_unsupported_key_rollover.rpl similarity index 100% rename from daemon/lua/trust_anchors.test.integr/rfc5011_unsupported_key_rollover.rpl rename to modules/ta_update/ta_update.test.integr/rfc5011_unsupported_key_rollover.rpl -- 2.47.2