mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-11-02 08:59:57 -06:00
Automated with Cursor+Claude Related: https://issues.redhat.com/browse/IDM-2894 Signed-off-by: PRANAV THUBE <pthube@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Antonio Torres <antorres@redhat.com>
373 lines
14 KiB
Python
373 lines
14 KiB
Python
#
|
|
# Copyright (C) 2024 FreeIPA Contributors see COPYING for license
|
|
#
|
|
"""This covers tests for DNS over TLS related feature"""
|
|
|
|
from __future__ import absolute_import
|
|
import pytest
|
|
import textwrap
|
|
import os
|
|
from ipatests.test_integration.test_caless import ExternalCA
|
|
from cryptography.hazmat.primitives import serialization
|
|
from ipatests.pytest_ipa.integration import tasks
|
|
from ipatests.test_integration.base import IntegrationTest
|
|
from ipatests.test_integration.test_dns import TestDNS
|
|
from ipatests.pytest_ipa.integration.firewall import Firewall
|
|
from ipaplatform.osinfo import osinfo
|
|
from ipaplatform.paths import paths
|
|
|
|
|
|
def verify_queries_encrypted(master, replicas, clients,
|
|
forwarder="1.1.1.1#853",
|
|
dns_hostname="freeipa.org"):
|
|
"""
|
|
Helper function to verify that queries are encrypted and
|
|
routed to the specified forwarder.
|
|
"""
|
|
unbound_log_cfg = textwrap.dedent("""
|
|
server:
|
|
verbosity: 3
|
|
log-queries: yes
|
|
cache-min-ttl: 0
|
|
cache-max-ttl: 0
|
|
""")
|
|
|
|
for server in [master] + replicas:
|
|
server.put_file_contents(
|
|
os.path.join(paths.UNBOUND_CONFIG_DIR, "log.conf"),
|
|
unbound_log_cfg,
|
|
)
|
|
server.run_command(["systemctl", "restart", "unbound"])
|
|
server.run_command(
|
|
["journalctl", "--flush", "--rotate", "--vacuum-time=1s"]
|
|
)
|
|
server.run_command(["dig", dns_hostname])
|
|
log_output = server.run_command(
|
|
["journalctl", "-u", "unbound", "--grep", forwarder]
|
|
)
|
|
assert forwarder in log_output.stdout_text, (
|
|
f"Forwarder {forwarder} not found in logs on "
|
|
f"{server.hostname}"
|
|
)
|
|
server.run_command(
|
|
["journalctl", "--flush", "--rotate", "--vacuum-time=1s"]
|
|
)
|
|
|
|
for client in clients:
|
|
client.run_command(["dig", dns_hostname])
|
|
log_output = master.run_command(
|
|
["journalctl", "-u", "unbound", "--grep", forwarder]
|
|
)
|
|
|
|
assert forwarder in log_output.stdout_text, (
|
|
f"Forwarder {forwarder} not found in logs on master for "
|
|
f"client {client.hostname}"
|
|
)
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
osinfo.id == 'fedora' and osinfo.version_number == (41,),
|
|
reason='Encrypted DNS not supported in fedora 41')
|
|
class TestDNSOverTLS(IntegrationTest):
|
|
"""Tests for DNS over TLS feature."""
|
|
|
|
topology = 'line'
|
|
num_replicas = 1
|
|
num_clients = 1
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
Firewall(cls.master).enable_service("dns-over-tls")
|
|
Firewall(cls.replicas[0]).enable_service("dns-over-tls")
|
|
tasks.install_packages(cls.master, ['*ipa-server-encrypted-dns'])
|
|
tasks.install_packages(cls.replicas[0], ['*ipa-server-encrypted-dns'])
|
|
tasks.install_packages(cls.clients[0], ['*ipa-client-encrypted-dns'])
|
|
|
|
def test_install_dnsovertls_invalid_ca(self):
|
|
"""
|
|
This test checks that the installers throws an error
|
|
when invalid cert is specified.
|
|
"""
|
|
bad_ca_cnf = textwrap.dedent("""
|
|
[ req ]
|
|
x509_extensions = v3_ca
|
|
[ v3_ca ]
|
|
basicConstraints = critical,CA:false
|
|
""")
|
|
self.master.put_file_contents("/bad_ca.cnf", bad_ca_cnf)
|
|
self.master.run_command(["openssl", "req", "-newkey", "rsa:2048",
|
|
"-nodes", "-keyout",
|
|
"/etc/pki/tls/certs/privkey-invalid.pem",
|
|
"-x509", "-days", "36500", "-out",
|
|
"/etc/pki/tls/certs/certificate-invalid.pem",
|
|
"-subj",
|
|
("/C=ES/ST=Andalucia/L=Sevilla/O=CompanyName/"
|
|
"OU=IT/CN=www.example.com/"
|
|
"emailAddress=email@example.com"),
|
|
"-config", "/bad_ca.cnf"])
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "1.1.1.1#cloudflare-dns.com",
|
|
"--dns-over-tls-cert",
|
|
"/etc/pki/tls/certs/certificate-invalid.pem",
|
|
"--dns-over-tls-key",
|
|
"/etc/pki/tls/certs/privkey-invalid.pem"
|
|
]
|
|
res = tasks.install_master(self.master, extra_args=args,
|
|
raiseonerr=False)
|
|
assert "Not a valid CA certificate: " in res.stderr_text
|
|
tasks.uninstall_master(self.master)
|
|
|
|
def test_install_dnsovertls_without_setup_dns_master(self):
|
|
"""
|
|
This test installs an IPA server using the --dns-over-tls option
|
|
without using setup-dns option, and captures warnings that appear.
|
|
"""
|
|
self.master.run_command(["ipa-server-install", "--uninstall", "-U"])
|
|
args = [
|
|
"--dns-over-tls",
|
|
]
|
|
res = tasks.install_master(
|
|
self.master, extra_args=args, setup_dns=False)
|
|
assert ("Warning: --dns-over-tls option specified without "
|
|
"--setup-dns, ignoring") in res.stdout_text
|
|
tasks.uninstall_master(self.master)
|
|
|
|
def test_install_dnsovertls_with_invalid_ipaddress_master(self):
|
|
"""
|
|
This test installs an IPA server using the --dns-over-tls
|
|
option with an invalid IP address.
|
|
"""
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "198.168.0.0.1#example-dns.test",
|
|
]
|
|
res = tasks.install_master(self.master, extra_args=args,
|
|
raiseonerr=False)
|
|
assert ("--dot-forwarder invalid: DoT forwarder must be in "
|
|
"the format of '1.2.3.4#dns.example.test'") in res.stderr_text
|
|
tasks.uninstall_master(self.master)
|
|
|
|
def test_validate_DoT_options_master(self):
|
|
"""
|
|
Tests that DoT options are displayed correctly on master.
|
|
"""
|
|
cmdout = self.master.run_command(
|
|
['ipa-server-install', '--help'])
|
|
assert '''--dot-forwarder=DOT_FORWARDERS
|
|
Add a DNS over TLS forwarder. This option can be used
|
|
multiple times''' in cmdout.stdout_text # noqa: E501
|
|
assert '''--dns-over-tls-cert=DNS_OVER_TLS_CERT
|
|
Certificate to use for DNS over TLS. If empty, a new
|
|
certificate will be requested from IPA CA''' in cmdout.stdout_text # noqa: E501
|
|
assert '''--dns-over-tls-key=DNS_OVER_TLS_KEY
|
|
Key for certificate specified in --dns-over-tls-cert''' in cmdout.stdout_text # noqa: E501
|
|
assert '''--dns-over-tls Configure DNS over TLS''' in cmdout.stdout_text # noqa: E501
|
|
|
|
def test_validate_DoT_options_replica(self):
|
|
"""
|
|
Tests that DoT options are displayed correctly on replica.
|
|
"""
|
|
cmdout = self.replicas[0].run_command(
|
|
['ipa-server-install', '--help'])
|
|
assert '''--dot-forwarder=DOT_FORWARDERS
|
|
Add a DNS over TLS forwarder. This option can be used
|
|
multiple times''' in cmdout.stdout_text
|
|
assert '''--dns-over-tls-cert=DNS_OVER_TLS_CERT
|
|
Certificate to use for DNS over TLS. If empty, a new
|
|
certificate will be requested from IPA CA''' in cmdout.stdout_text # noqa: E501
|
|
assert '''--dns-over-tls-key=DNS_OVER_TLS_KEY
|
|
Key for certificate specified in --dns-over-tls-cert''' in cmdout.stdout_text # noqa: E501
|
|
assert '''--dns-over-tls Configure DNS over TLS''' in cmdout.stdout_text # noqa: E501
|
|
|
|
def test_validate_DoT_options_client(self):
|
|
"""
|
|
Tests that DoT options are displayed correctly on client.
|
|
"""
|
|
cmdout = self.clients[0].run_command(
|
|
['ipa-client-install', '--help'])
|
|
assert '''--dns-over-tls Configure DNS over TLS''' in cmdout.stdout_text # noqa: E501
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
osinfo.id == 'fedora' and osinfo.version_number < (42,),
|
|
reason='Encrypted DNS not supported in Fedora < 42')
|
|
class TestDNSOverTLS_RelaxedPolicy(IntegrationTest):
|
|
"""Tests for DNS over TLS feature."""
|
|
|
|
topology = 'line'
|
|
num_replicas = 1
|
|
num_clients = 1
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
Firewall(cls.master).enable_service("dns-over-tls")
|
|
Firewall(cls.replicas[0]).enable_service("dns-over-tls")
|
|
tasks.install_packages(cls.master, ['*ipa-server-encrypted-dns'])
|
|
tasks.install_packages(cls.replicas[0], ['*ipa-server-encrypted-dns'])
|
|
tasks.install_packages(cls.clients[0], ['*ipa-client-encrypted-dns'])
|
|
|
|
def test_dot_relaxed_dns_policy_with_IPA_CA(self):
|
|
"""
|
|
This test installs IPA server, replica, and client with
|
|
--no-dnssec-validation option, relaxed DNS policy, and
|
|
with IPA CA, ensuring all queries are encrypted.
|
|
"""
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "1.1.1.1#cloudflare-dns.com",
|
|
"--no-dnssec-validation",
|
|
"--dns-policy", "relaxed"
|
|
]
|
|
tasks.install_master(self.master, extra_args=args)
|
|
|
|
self.clients[0].put_file_contents(
|
|
paths.RESOLV_CONF,
|
|
"nameserver %s" % self.master.ip
|
|
)
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--no-dnssec-validation"
|
|
]
|
|
tasks.install_client(
|
|
self.master,
|
|
self.clients[0],
|
|
nameservers=None,
|
|
extra_args=args
|
|
)
|
|
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "1.1.1.1#cloudflare-dns.com",
|
|
"--no-dnssec-validation",
|
|
"--dns-policy", "relaxed"
|
|
]
|
|
tasks.install_replica(
|
|
self.master,
|
|
self.replicas[0],
|
|
setup_dns=True,
|
|
extra_args=args
|
|
)
|
|
verify_queries_encrypted(
|
|
self.master,
|
|
[self.replicas[0]],
|
|
[self.clients[0]]
|
|
)
|
|
|
|
def test_uninstall_all(self):
|
|
"""
|
|
This test ensures that all hosts can be uninstalled correctly.
|
|
"""
|
|
tasks.uninstall_client(self.clients[0])
|
|
tasks.uninstall_replica(self.master, self.replicas[0])
|
|
tasks.uninstall_master(self.master)
|
|
|
|
def test_dot_relaxed_dns_policy_with_external_ca(self):
|
|
"""
|
|
This test installs IPA server, replica, and client with
|
|
--no-dnssec-validation option, relaxed DNS policy, and
|
|
with external CA, ensuring all queries are encrypted.
|
|
"""
|
|
# Install Master with external CA
|
|
# Create external CA cert + key.
|
|
external_ca = ExternalCA(days=36500)
|
|
cert_pem = external_ca.create_ca()
|
|
key_pem = external_ca.ca_key.private_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
encryption_algorithm=serialization.NoEncryption(),
|
|
)
|
|
cert_dest = "/etc/pki/tls/certs/certificate.pem"
|
|
key_dest = "/etc/pki/tls/certs/privkey.pem"
|
|
|
|
self.master.put_file_contents(cert_dest, cert_pem)
|
|
self.master.put_file_contents(key_dest, key_pem)
|
|
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "1.1.1.1#cloudflare-dns.com",
|
|
"--dns-over-tls-cert", cert_dest,
|
|
"--dns-over-tls-key", key_dest,
|
|
"--no-dnssec-validation",
|
|
"--dns-policy", "relaxed"
|
|
]
|
|
tasks.install_master(self.master, extra_args=args)
|
|
|
|
# Install Client with external CA
|
|
self.clients[0].put_file_contents(
|
|
paths.RESOLV_CONF,
|
|
"nameserver %s" % self.master.ip
|
|
)
|
|
dest_file = "/etc/pki/ca-trust/source/anchors/certificate.pem"
|
|
data = self.master.get_file_contents(cert_dest)
|
|
self.clients[0].transport.put_file_contents(dest_file, data)
|
|
self.clients[0].run_command(["update-ca-trust", "extract"])
|
|
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--no-dnssec-validation"
|
|
]
|
|
tasks.install_client(
|
|
self.master,
|
|
self.clients[0],
|
|
nameservers=None,
|
|
extra_args=args
|
|
)
|
|
|
|
# Install Replica with external CA
|
|
dest_file = "/etc/pki/ca-trust/source/anchors/certificate.pem"
|
|
data = self.master.get_file_contents(cert_dest)
|
|
self.clients[0].transport.put_file_contents(dest_file, data)
|
|
|
|
self.replicas[0].run_command(["update-ca-trust", "extract"])
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "1.1.1.1#cloudflare-dns.com",
|
|
"--no-dnssec-validation",
|
|
"--dns-policy", "relaxed"
|
|
]
|
|
tasks.install_replica(
|
|
self.master,
|
|
self.replicas[0],
|
|
setup_dns=True,
|
|
extra_args=args
|
|
)
|
|
|
|
verify_queries_encrypted(
|
|
self.master,
|
|
[self.replicas[0]],
|
|
[self.clients[0]]
|
|
)
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
osinfo.id == 'fedora' and osinfo.version_number == (41,),
|
|
reason='Encrypted DNS not supported in fedora 41')
|
|
class TestDNS_DoT(TestDNS):
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
tasks.install_packages(cls.master, ['*ipa-server-encrypted-dns'])
|
|
args = [
|
|
"--dns-over-tls",
|
|
"--dot-forwarder", "1.1.1.1#cloudflare-dns.com"
|
|
]
|
|
tasks.install_master(cls.master, extra_args=args)
|
|
|
|
def test_check_dot_forwarder_added_in_ipa_conf(self):
|
|
"""
|
|
This test checks that forwarders is listed in
|
|
dnsserver-show command and also the dot forwarder is
|
|
added to unbound and included in
|
|
/etc/unbound/conf.d/zzz-ipa.conf
|
|
"""
|
|
msg = 'Forwarders: 127.0.0.55'
|
|
cmd1 = self.master.run_command(
|
|
["ipa", "dnsserver-show", self.master.hostname]
|
|
)
|
|
assert msg in cmd1.stdout_text
|
|
contents = self.master.get_file_contents(
|
|
paths.UNBOUND_CONF, encoding='utf-8'
|
|
)
|
|
assert 'forward-addr: 1.1.1.1#cloudflare-dns.com' in contents
|