Allow hosts to read DNS records for IP SAN

For SAN IPAddress extension the cert plugin verifies that the IP address
matches the host entry. Certmonger uses the host principal to
authenticate and retrieve certificates. But the host principal did not
have permission to read DNS entries from LDAP.

Allow all hosts to read some entries from active DNS records.

Fixes: https://pagure.io/freeipa/issue/8098
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
Christian Heimes 2020-03-13 08:40:14 +01:00
parent 9c9c6a7063
commit 7a9ac1f586
3 changed files with 50 additions and 5 deletions

View File

@ -12,6 +12,7 @@ aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search
aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)
aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)
aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || urirecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)
aci: (targetattr = "aaaarecord || arecord || cnamerecord || idnsname || objectclass || ptrrecord")(targetfilter = "(&(objectclass=idnsrecord)(|(aaaarecord=*)(arecord=*)(cnamerecord=*)(ptrrecord=*)(idnsZoneActive=TRUE)))")(version 3.0; acl "Allow hosts to read DNS A/AAA/CNAME/PTR records"; allow (read,search,compare) userdn = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)
dn: cn=servers,cn=dns,$SUFFIX
changetype: add

View File

@ -5,7 +5,7 @@ addifexist: objectClass: idnsConfigObject
addifexist: aci:(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)
addifexist: aci:(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)
addifexist: aci:(targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || urirecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)
addifexist: aci:(targetattr = "aaaarecord || arecord || cnamerecord || idnsname || objectclass || ptrrecord")(targetfilter = "(&(objectclass=idnsrecord)(|(aaaarecord=*)(arecord=*)(cnamerecord=*)(ptrrecord=*)(idnsZoneActive=TRUE)))")(version 3.0; acl "Allow hosts to read DNS A/AAA/CNAME/PTR records"; allow (read,search,compare) userdn = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";)
# replace DNS tree deny rule with managedBy enhanced allow rule
dn: cn=dns, $SUFFIX

View File

@ -6,11 +6,13 @@
Module provides tests which testing ability of various certificate
related scenarios.
"""
from __future__ import absolute_import
import ipaddress
import re
from cryptography import x509
from cryptography.x509.oid import ExtensionOID
from cryptography.hazmat.backends import default_backend
from ipatests.pytest_ipa.integration import tasks
from ipatests.test_integration.base import IntegrationTest
@ -20,7 +22,11 @@ class TestInstallMasterClient(IntegrationTest):
@classmethod
def install(cls, mh):
tasks.install_master(cls.master)
tasks.install_master(cls.master, setup_dns=True)
# use master's DNS so nsupdate adds correct IP address for client
tasks.config_host_resolvconf_with_master_data(
cls.master, cls.clients[0]
)
tasks.install_client(cls.master, cls.clients[0])
def test_cacert_file_appear_with_option_F(self):
@ -46,3 +52,41 @@ class TestInstallMasterClient(IntegrationTest):
assert status == "MONITORING"
self.clients[0].run_command(['ls', '-l', '/etc/pki/tls/test.CA'])
def test_ipa_getcert_san_aci(self):
"""Test for DNS and IP SAN extensions + ACIs
"""
hostname = self.clients[0].hostname
certfile = '/etc/pki/tls/certs/test2.pem'
tasks.kinit_admin(self.master)
name, zone = hostname.split('.', 1)
self.master.run_command(['ipa', 'dnsrecord-show', zone, name])
tasks.kdestroy_all(self.master)
cmd_arg = [
'ipa-getcert', 'request', '-v', '-w',
'-f', certfile,
'-k', '/etc/pki/tls/private/test2.key',
'-K', f'test/{hostname}',
'-D', hostname,
'-A', self.clients[0].ip,
]
result = self.clients[0].run_command(cmd_arg)
request_id = re.findall(r'\d+', result.stdout_text)
# check if certificate is in MONITORING state
status = tasks.wait_for_request(self.clients[0], request_id[0], 50)
assert status == "MONITORING"
certdata = self.clients[0].get_file_contents(certfile)
cert = x509.load_pem_x509_certificate(
certdata, default_backend()
)
ext = cert.extensions.get_extension_for_oid(
ExtensionOID.SUBJECT_ALTERNATIVE_NAME
)
dnsnames = ext.value.get_values_for_type(x509.DNSName)
assert dnsnames == [self.clients[0].hostname]
ipaddrs = ext.value.get_values_for_type(x509.IPAddress)
assert ipaddrs == [ipaddress.ip_address(self.clients[0].ip)]