URL: https://github.com/freeipa/freeipa/pull/5780
Author: stanislavlevin
 Title: #5780: ipatests: dnssec: Add alternative approach for checking chain of 
trust
Action: opened

PR body:
"""
drill is currently broken on F34. Fortunately, there are another tools for 
checking DNSSEC trust. One of them is `delv`:
    
    delv is a tool for sending DNS queries and validating the results,
    using the same internal resolver and validator logic as named.
    
    delv sends to a specified name server all queries needed to fetch and
    validate the requested data; this includes the original requested query,
    subsequent queries to follow CNAME or DNAME chains, queries for DNSKEY,
    and DS records to establish a chain of trust for DNSSEC validation. It
    does not perform iterative resolution, but simulates the behavior of a
    name server configured for DNSSEC validating and forwarding.
    

- mark as XFAIL `test_chain_of_trust_drill` on F34
- conditionally skip `test_chain_of_trust_delv` (requires delv > 9.15.4 for 
`+yaml`)

Related: https://pagure.io/freeipa/issue/8793
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/5780/head:pr5780
git checkout pr5780
From 579269c90e60268ee08dabaf7d0f2e78fa87dc05 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Wed, 19 May 2021 00:51:36 +0300
Subject: [PATCH 1/2] ipatests: dnssec: Add alternative approach for checking
 chain of trust

drill is currently broken on F34. Fortunately, there are another
tools for checking DNSSEC trust. One of them is `delv`:

> delv is a tool for sending DNS queries and validating the results,
using the same internal resolver and validator logic as named.

delv sends to a specified name server all queries needed to fetch and
validate the requested data; this includes the original requested query,
subsequent queries to follow CNAME or DNAME chains, queries for DNSKEY,
and DS records to establish a chain of trust for DNSSEC validation. It
does not perform iterative resolution, but simulates the behavior of a
name server configured for DNSSEC validating and forwarding.

Related: https://pagure.io/freeipa/issue/8793
Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 ipatests/test_integration/test_dnssec.py | 115 ++++++++++++++++++++++-
 1 file changed, 110 insertions(+), 5 deletions(-)

diff --git a/ipatests/test_integration/test_dnssec.py b/ipatests/test_integration/test_dnssec.py
index bae16120a7a..4e02a9b27d4 100644
--- a/ipatests/test_integration/test_dnssec.py
+++ b/ipatests/test_integration/test_dnssec.py
@@ -4,17 +4,23 @@
 
 from __future__ import absolute_import
 
+import base64
 import logging
 import re
 import subprocess
 import time
+import textwrap
 
 import dns.dnssec
 import dns.name
+import pytest
+import yaml
 
 from ipatests.test_integration.base import IntegrationTest
 from ipatests.pytest_ipa.integration import tasks
 from ipatests.pytest_ipa.integration.firewall import Firewall
+from ipaplatform.tasks import tasks as platform_tasks
+from ipaplatform.osinfo import osinfo
 from ipaplatform.paths import paths
 from ipapython.dnsutil import DNSResolver
 
@@ -350,11 +356,7 @@ def test_sign_root_zone(self):
             self.replicas[0].ip, root_zone, timeout=300
         ), "Zone %s is not signed (replica)" % root_zone
 
-    def test_chain_of_trust(self):
-        """
-        Validate signed DNS records, using our own signed root zone
-        :return:
-        """
+    def test_delegation(self):
         dnszone_add_dnssec(self.master, example_test_zone)
 
         # delegation
@@ -419,6 +421,15 @@ def test_chain_of_trust(self):
             rtype="DS"
         ), "No DS record of '%s' returned from replica" % example_test_zone
 
+    @pytest.mark.xfail(
+        osinfo.id == "fedora" and osinfo.version_number == (34,),
+        reason="https://pagure.io/freeipa/issue/8793";,
+        strict=True,
+    )
+    def test_chain_of_trust_drill(self):
+        """
+        Validate signed DNS records, using our own signed root zone
+        """
         # extract DSKEY from root zone
         ans = resolve_with_dnssec(self.master.ip, root_zone,
                                   rtype="DNSKEY")
@@ -462,6 +473,100 @@ def test_chain_of_trust(self):
         self.master.run_command(args)
         self.replicas[0].run_command(args)
 
+    def test_chain_of_trust_delv(self):
+        """
+        Validate signed DNS records, using our own signed root zone
+        """
+        INITIAL_KEY_FMT = '%s initial-key %d %d %d "%s";'
+
+        # delv reports its version on stderr
+        delv_version = self.master.run_command(
+            ["delv", "-v"]
+        ).stderr_text.rstrip().replace("delv ", "")
+        assert delv_version
+
+        delv_version_parsed = platform_tasks.parse_ipa_version(delv_version)
+        if delv_version_parsed < platform_tasks.parse_ipa_version("9.16"):
+            pytest.skip(
+                f"Requires delv >= 9.16(+yaml), installed: '{delv_version}'"
+            )
+
+        # extract DSKEY from root zone
+        ans = resolve_with_dnssec(
+            self.master.ip, root_zone, rtype="DNSKEY"
+        )
+        dnskey_rrset = ans.response.get_rrset(
+            ans.response.answer,
+            dns.name.from_text(root_zone),
+            dns.rdataclass.IN,
+            dns.rdatatype.DNSKEY,
+        )
+        assert dnskey_rrset, "No DNSKEY records received"
+
+        # export trust keys for root zone
+        initial_keys = []
+        for key_rdata in dnskey_rrset:
+            if key_rdata.flags != 257:
+                continue  # it is not KSK
+
+            initial_keys.append(
+                INITIAL_KEY_FMT % (
+                    root_zone,
+                    key_rdata.flags,
+                    key_rdata.protocol,
+                    key_rdata.algorithm,
+                    base64.b64encode(key_rdata.key).decode("utf-8"),
+                )
+            )
+
+        assert initial_keys, "No KSK returned from the root zone"
+
+        trust_anchors = textwrap.dedent(
+            """\
+            trust-anchors {{
+            {initial_key}
+            }};
+            """
+        ).format(initial_key="\n".join(initial_keys))
+        logger.debug("Root zone trust-anchors: %s", trust_anchors)
+
+        # set trusted anchor for our root zone
+        for host in [self.master, self.replicas[0]]:
+            host.put_file_contents(paths.DNSSEC_TRUSTED_KEY, trust_anchors)
+
+        # verify signatures
+        args = [
+            "delv",
+            "+yaml",
+            "+nosplit",
+            "+vtrace",
+            "@localhost",
+            example_test_zone,
+            "-a",
+            paths.DNSSEC_TRUSTED_KEY,
+            "SOA",
+        ]
+
+        # delv puts trace info on stderr
+        for host in [self.master, self.replicas[0]]:
+            result = host.run_command(args)
+            yaml_data = yaml.safe_load(result.stdout_text)
+
+            query_name_abs = dns.name.from_text(example_test_zone)
+            root_zone_name = dns.name.from_text(root_zone)
+            query_name_rel = query_name_abs.relativize(
+                root_zone_name
+            ).to_text()
+            assert yaml_data["query_name"] == query_name_rel
+            assert yaml_data["status"] == "success"
+
+            assert len(yaml_data["records"]) == 1
+            fully_validated = yaml_data["records"][0]["fully_validated"]
+            fully_validated.sort()
+            assert len(fully_validated) == 2
+            assert f"{example_test_zone} 1 IN RRSIG SOA" in fully_validated[0]
+            assert f"{example_test_zone} 1 IN SOA" in fully_validated[1]
+
     def test_servers_use_localhost_as_dns(self):
         # check that localhost is set as DNS server
         for host in [self.master, self.replicas[0]]:

From 0014aa1e73c4d93e9aa833b9b686adbd2dd1dffc Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Wed, 19 May 2021 19:10:34 +0300
Subject: [PATCH 2/2] temp commit: Trigger DNSSEC tests on F33, F34

F32 is covered on Azure.

Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 .freeipa-pr-ci.yaml                        |  2 +-
 ipatests/prci_definitions/temp_commit.yaml | 44 +++++++++++++++++-----
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/.freeipa-pr-ci.yaml b/.freeipa-pr-ci.yaml
index abcf8c5b634..80656690080 120000
--- a/.freeipa-pr-ci.yaml
+++ b/.freeipa-pr-ci.yaml
@@ -1 +1 @@
-ipatests/prci_definitions/gating.yaml
\ No newline at end of file
+ipatests/prci_definitions/temp_commit.yaml
\ No newline at end of file
diff --git a/ipatests/prci_definitions/temp_commit.yaml b/ipatests/prci_definitions/temp_commit.yaml
index 26e4b0e58b9..606386b3e00 100644
--- a/ipatests/prci_definitions/temp_commit.yaml
+++ b/ipatests/prci_definitions/temp_commit.yaml
@@ -47,7 +47,7 @@ topologies:
     memory: 14500
 
 jobs:
-  fedora-latest/build:
+  fedora-f33/build:
     requires: []
     priority: 100
     job:
@@ -55,20 +55,46 @@ jobs:
       args:
         git_repo: '{git_repo}'
         git_refspec: '{git_refspec}'
-        template: &ci-master-latest
+        template: &ci-master-f33
           name: freeipa/ci-master-f33
           version: 0.0.8
         timeout: 1800
         topology: *build
 
-  fedora-latest/temp_commit:
-    requires: [fedora-latest/build]
-    priority: 50
+  fedora-f33/test_dnssec_TestInstallDNSSECFirst:
+    requires: [fedora-f33/build]
+    priority: 100
+    job:
+      class: RunPytest
+      args:
+        build_url: '{fedora-f33/build_url}'
+        test_suite: test_integration/test_dnssec.py::TestInstallDNSSECFirst
+        template: *ci-master-f33
+        timeout: 3600
+        topology: *master_1repl
+
+  fedora-f34/build:
+    requires: []
+    priority: 100
+    job:
+      class: Build
+      args:
+        git_repo: '{git_repo}'
+        git_refspec: '{git_refspec}'
+        template: &ci-master-f34
+          name: freeipa/ci-master-f34
+          version: 0.0.3
+        timeout: 1800
+        topology: *build
+
+  fedora-f34/test_dnssec_TestInstallDNSSECFirst:
+    requires: [fedora-f34/build]
+    priority: 100
     job:
       class: RunPytest
       args:
-        build_url: '{fedora-latest/build_url}'
-        test_suite: test_integration/test_REPLACEME.py
-        template: *ci-master-latest
+        build_url: '{fedora-f33/build_url}'
+        test_suite: test_integration/test_dnssec.py::TestInstallDNSSECFirst
+        template: *ci-master-f34
         timeout: 3600
-        topology: *master_1repl_1client
+        topology: *master_1repl
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to