On 15.4.2013 21:16, Martin Kosek wrote:
Jan, can you please rebase the patch also for ipa-3-1? We will need to
fix this issue also for 3.1.

Yep.

--
Jan Cholasta
>From eb97cc1e5fa6b1d2953b78c72e601e17a87be208 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Mon, 15 Apr 2013 12:19:11 +0200
Subject: [PATCH 1/2] Use A/AAAA records instead of CNAME records in ipa-ca.

https://fedorahosted.org/freeipa/ticket/3547
---
 install/share/bind.zone.db.template |   2 +-
 install/tools/ipa-ca-install        |   2 +-
 install/tools/ipa-replica-manage    |   1 +
 install/tools/ipa-upgradeconfig     |  54 ++++++++-------
 ipaserver/install/bindinstance.py   | 130 +++++++++++++++++++++++++++++-------
 ipaserver/install/cainstance.py     |   6 +-
 6 files changed, 142 insertions(+), 53 deletions(-)

diff --git a/install/share/bind.zone.db.template b/install/share/bind.zone.db.template
index 5ee71d6..6795bb0 100644
--- a/install/share/bind.zone.db.template
+++ b/install/share/bind.zone.db.template
@@ -26,4 +26,4 @@ _kpasswd._udp		IN SRV 0 100 464	$HOST
 $OPTIONAL_NTP
 
 ; CNAME for IPA CA replicas (used for CRL, OCSP)
-$IPA_CA_CNAME		IN CNAME		$HOST
+$IPA_CA_RECORD
diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index f8f7e1d..2ebce60 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -85,7 +85,7 @@ def install_dns_records(config, options):
     try:
         api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
                                   bind_pw=config.dirman_password)
-        bind.add_ipa_ca_cname(config.host_name, config.domain_name)
+        bind.add_ipa_ca_dns_records(config.host_name, config.domain_name)
     finally:
         if api.Backend.ldap2.isconnected():
              api.Backend.ldap2.disconnect()
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index e78f9d2..a339a50 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -697,6 +697,7 @@ def del_master(realm, hostname, options):
                 api.Backend.ldap2.connect(ccache=ccache)
             bind = bindinstance.BindInstance()
             bind.remove_master_dns_records(hostname, realm, realm.lower())
+            bind.remove_ipa_ca_dns_records(hostname, realm.lower())
     except Exception, e:
         print "Failed to cleanup %s DNS entries: %s" % (hostname, convert_error(e))
         print "You may need to manually remove them from the tree"
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index f71d834..8bd7ff2 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -628,31 +628,35 @@ def migrate_crl_publish_dir(ca):
                      'request pki-ca restart')
     return True
 
-def add_server_cname_records():
-    root_logger.info('[Add missing server CNAME records]')
+def add_ca_dns_records():
+    root_logger.info('[Add missing CA DNS records]')
 
-    if not sysupgrade.get_upgrade_state('dns', 'ipa_ca_cname'):
-        try:
-            api.Backend.ldap2.connect(autobind=True)
-        except ipalib.errors.PublicError, e:
-            root_logger.error("Cannot connect to LDAP to add DNS records: %s", e)
-        else:
-            ret = api.Command['dns_is_enabled']()
-            if not ret['result']:
-                root_logger.info('DNS is not configured')
-                sysupgrade.set_upgrade_state('dns', 'ipa_ca_cname', True)
-                return
-
-            bind = bindinstance.BindInstance()
-            # DNS is enabled, so let bindinstance find out if CA is enabled
-            # and let it add the CNAME in that case
-            bind.add_ipa_ca_cname(api.env.host, api.env.domain, ca_configured=None)
-            sysupgrade.set_upgrade_state('dns', 'ipa_ca_cname', True)
-        finally:
-            if api.Backend.ldap2.isconnected():
-                 api.Backend.ldap2.disconnect()
-    else:
-        root_logger.info('IPA CA CNAME already processed')
+    if sysupgrade.get_upgrade_state('dns', 'ipa_ca_records'):
+        root_logger.info('IPA CA DNS records already processed')
+        return
+
+    try:
+        api.Backend.ldap2.connect(autobind=True)
+    except ipalib.errors.PublicError, e:
+        root_logger.error("Cannot connect to LDAP to add DNS records: %s", e)
+        return
+
+    ret = api.Command['dns_is_enabled']()
+    if not ret['result']:
+        root_logger.info('DNS is not configured')
+        sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True)
+        return
+
+    bind = bindinstance.BindInstance()
+
+    bind.convert_ipa_ca_cnames(api.env.domain)
+
+    # DNS is enabled, so let bindinstance find out if CA is enabled
+    # and let it add the record in that case
+    bind.add_ipa_ca_dns_records(api.env.host, api.env.domain,
+                                ca_configured=None)
+
+    sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True)
 
 def main():
     """
@@ -746,7 +750,7 @@ def main():
 
     cleanup_kdc(fstore)
     setup_firefox_extension(fstore)
-    add_server_cname_records()
+    add_ca_dns_records()
     changed_psearch = named_enable_psearch()
     changed_autoincrement = named_enable_serial_autoincrement()
     if changed_psearch or changed_autoincrement:
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index a528320..bc250f0 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -28,7 +28,7 @@ import ldap
 import service
 from ipaserver import ipaldap
 from ipaserver.install.dsinstance import realm_to_serverid
-from ipaserver.install.cainstance import IPA_CA_CNAME
+from ipaserver.install.cainstance import IPA_CA_RECORD
 from ipaserver.install.installutils import resolve_host
 from ipapython import sysrestore
 from ipapython import ipautil
@@ -334,6 +334,13 @@ def del_rr(zone, name, type, rdata):
     except (errors.NotFound, errors.AttrValueNotFound, errors.EmptyModlist):
         pass
 
+def del_fwd_rr(zone, host, ip_address):
+    addr = netaddr.IPAddress(ip_address)
+    if addr.version == 4:
+        del_rr(zone, host, "A", ip_address)
+    elif addr.version == 6:
+        del_rr(zone, host, "AAAA", ip_address)
+
 def get_rr(zone, name, type):
     rectype = '%srecord' % unicode(type.lower())
     ret = api.Command.dnsrecord_find(unicode(zone), unicode(name))
@@ -344,6 +351,9 @@ def get_rr(zone, name, type):
 
     return []
 
+def get_fwd_rr(zone, host):
+    return [x for t in ("A", "AAAA") for x in get_rr(zone, host, t)]
+
 def zonemgr_callback(option, opt_str, value, parser):
     """
     Properly validate and convert --zonemgr Option to IA5String
@@ -500,7 +510,7 @@ class BindInstance(service.Service):
         if self.reverse_zone is not None:
             self.step("setting up reverse zone", self.__setup_reverse_zone)
         self.step("setting up our own record", self.__add_self)
-        self.step("setting up CA CNAME record", self.__add_ipa_ca_cname)
+        self.step("setting up CA record", self.__add_ipa_ca_record)
 
         self.step("setting up kerberos principal", self.__setup_principal)
         self.step("setting up named.conf", self.__setup_named_conf)
@@ -545,6 +555,15 @@ class BindInstance(service.Service):
         else:
             optional_ntp = ""
 
+        addr = netaddr.IPAddress(self.ip_address)
+        if addr.version in (4, 6):
+            ipa_ca = "%s\t\t\tIN %s\t\t\t%s\n" % (
+                IPA_CA_RECORD,
+                "A" if addr.version == 4 else "AAAA",
+                self.ip_address)
+        else:
+            ipa_ca = ""
+
         boolean_var = {}
         for var in ('persistent_search', 'serial_autoincrement'):
             boolean_var[var] = "yes" if getattr(self, var, False) else "no"
@@ -560,7 +579,7 @@ class BindInstance(service.Service):
                              OPTIONAL_NTP=optional_ntp,
                              ZONEMGR=self.zonemgr,
                              ZONE_REFRESH=self.zone_refresh,
-                             IPA_CA_CNAME=IPA_CA_CNAME,
+                             IPA_CA_RECORD=ipa_ca,
                              PERSISTENT_SEARCH=boolean_var['persistent_search'],
                              SERIAL_AUTOINCREMENT=boolean_var['serial_autoincrement'],)
 
@@ -587,27 +606,35 @@ class BindInstance(service.Service):
     def __add_self_ns(self):
         add_ns_rr(self.domain, api.env.host, self.dns_backup, force=True)
 
-    def __add_ipa_ca_cname(self):
-        if self.ca_configured is False:
-            root_logger.debug("CA is not configured, skip this step")
+    def _add_ipa_ca_dns_records(self, domain_name, fqdn, addrs, ca_configured):
+        if ca_configured is False:
+            root_logger.debug("CA is not configured")
             return
-        elif self.ca_configured is None:
+        elif ca_configured is None:
             # we do not know if CA is configured for this host and we can
-            # add the CA CNAME record. So we need to find out
+            # add the CA record. So we need to find out
             root_logger.debug("Check if CA is enabled for this host")
-            base_dn = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'),
+            base_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'),
                          ('cn', 'etc'), api.env.basedn)
             ldap_filter = '(&(objectClass=ipaConfigObject)(cn=CA))'
             try:
                 api.Backend.ldap2.find_entries(filter=ldap_filter, base_dn=base_dn)
             except ipalib.errors.NotFound:
-                # CA is not configured
                 root_logger.debug("CA is not configured")
                 return
             else:
-                root_logger.debug("CA is configured for this host, continue")
+                root_logger.debug("CA is configured for this host")
+
+        try:
+            for addr in addrs:
+                add_fwd_rr(domain_name, IPA_CA_RECORD, addr)
+        except errors.ValidationError:
+            # there is a CNAME record in ipa-ca, we can't add A/AAAA records
+            pass
 
-        add_rr(self.domain, IPA_CA_CNAME, "CNAME", self.host_in_rr)
+    def __add_ipa_ca_record(self):
+        self._add_ipa_ca_dns_records(self.domain, self.fqdn, [self.ip_address],
+                                     self.ca_configured)
 
     def __add_self(self):
         zone = self.domain
@@ -720,14 +747,62 @@ class BindInstance(service.Service):
         self.ca_configured = ca_configured
 
         self.__add_self()
-        self.__add_ipa_ca_cname()
+        self.__add_ipa_ca_record()
 
-    def add_ipa_ca_cname(self, fqdn, domain_name, ca_configured=True):
-        self.host = fqdn.split(".")[0]
-        self.fqdn = fqdn
-        self.domain = domain_name
-        self.ca_configured = ca_configured
-        self.__add_ipa_ca_cname()
+    def add_ipa_ca_dns_records(self, fqdn, domain_name, ca_configured=True):
+        host, zone = fqdn.split(".", 1)
+        if dns_zone_exists(zone):
+            addrs = get_fwd_rr(zone, host)
+        else:
+            addrs = installutils.resolve_host(fqdn)
+
+        self._add_ipa_ca_dns_records(domain_name, fqdn, addrs, ca_configured)
+
+    def convert_ipa_ca_cnames(self, domain_name):
+        # get ipa-ca CNAMEs
+        cnames = get_rr(domain_name, IPA_CA_RECORD, "CNAME")
+        if not cnames:
+            return
+
+        root_logger.info('Converting IPA CA CNAME records to A/AAAA records')
+
+        # create CNAME to FQDN mapping
+        cname_fqdn = {}
+        for cname in cnames:
+            if cname.endswith('.'):
+                fqdn = cname[:-1]
+            else:
+                fqdn = '%s.%s' % (cname, domain_name)
+            cname_fqdn[cname] = fqdn
+
+        # get FQDNs of all IPA masters
+        ldap = api.Backend.ldap2
+        try:
+            entries, truncated = ldap.find_entries(
+                base_dn=DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
+                   api.env.basedn),
+                scope=ldap.SCOPE_ONELEVEL, attrs_list=['cn'])
+            masters = set(e[1]['cn'][0] for e in entries)
+        except errors.NotFound:
+            masters = set()
+
+        # check if all CNAMEs point to IPA masters
+        for cname in cnames:
+            fqdn = cname_fqdn[cname]
+            if fqdn not in masters:
+                root_logger.warning(
+                    "Cannot convert IPA CA CNAME records to A/AAAA records, "
+                    "please convert them manually if necessary")
+                return
+
+        # delete all CNAMEs
+        for cname in cnames:
+            del_rr(domain_name, IPA_CA_RECORD, "CNAME", cname)
+
+        # add A/AAAA records
+        for cname in cnames:
+            fqdn = cname_fqdn[cname]
+            self.add_ipa_ca_dns_records(fqdn, domain_name, None)
 
     def remove_master_dns_records(self, fqdn, realm_name, domain_name):
         host = fqdn.split(".")[0]
@@ -746,16 +821,15 @@ class BindInstance(service.Service):
             ("_kpasswd._tcp", "SRV", "0 100 464 %s" % self.host_in_rr),
             ("_kpasswd._udp", "SRV", "0 100 464 %s" % self.host_in_rr),
             ("_ntp._udp", "SRV", "0 100 123 %s" % self.host_in_rr),
-            (IPA_CA_CNAME, "CNAME", self.host_in_rr),
             ("@", "NS", fqdn+"."),
         )
 
         for (record, type, rdata) in resource_records:
             del_rr(zone, record, type, rdata)
 
-        areclist = [("A", x) for x in get_rr(zone, host, "A")] + [("AAAA", x) for x in get_rr(zone, host, "AAAA")]
-        for (type, rdata) in areclist:
-            del_rr(zone, host, type, rdata)
+        areclist = get_fwd_rr(zone, host)
+        for rdata in areclist:
+            del_fwd_rr(zone, host, rdata)
 
             rzone = find_reverse_zone(rdata)
             if rzone is not None:
@@ -764,6 +838,16 @@ class BindInstance(service.Service):
                 # remove also master NS record from the reverse zone
                 del_rr(rzone, "@", "NS", fqdn+".")
 
+    def remove_ipa_ca_dns_records(self, fqdn, domain_name):
+        host, zone = fqdn.split(".", 1)
+        if dns_zone_exists(zone):
+            addrs = get_fwd_rr(zone, host)
+        else:
+            addrs = installutils.resolve_host(fqdn)
+
+        for addr in addrs:
+            del_fwd_rr(domain_name, IPA_CA_RECORD, addr)
+
     def check_global_configuration(self):
         """
         Check global DNS configuration in LDAP server and inform user when it
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 0d85691..01e784f 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -71,7 +71,7 @@ PKI_DS_USER = dogtag.install_constants.DS_USER
 
 # When IPA is installed with DNS support, this CNAME should hold all IPA
 # replicas with CA configured
-IPA_CA_CNAME = "ipa-ca"
+IPA_CA_RECORD = "ipa-ca"
 
 # We need to reset the template because the CA uses the regular boot
 # information
@@ -1275,7 +1275,7 @@ class CAInstance(service.Service):
         changed = False
 
         # OCSP extension
-        ocsp_url = 'http://%s.%s/ca/ocsp' % (IPA_CA_CNAME, ipautil.format_netloc(domain))
+        ocsp_url = 'http://%s.%s/ca/ocsp' % (IPA_CA_RECORD, ipautil.format_netloc(domain))
 
         ocsp_location_0 = installutils.get_directive(
             self.dogtag_constants.IPA_SERVICE_PROFILE,
@@ -1302,7 +1302,7 @@ class CAInstance(service.Service):
 
 
         # CRL extension
-        crl_url = 'http://%s.%s/ipa/crl/MasterCRL.bin'% (IPA_CA_CNAME, ipautil.format_netloc(domain))
+        crl_url = 'http://%s.%s/ipa/crl/MasterCRL.bin'% (IPA_CA_RECORD, ipautil.format_netloc(domain))
 
         crl_point_0 = installutils.get_directive(
             self.dogtag_constants.IPA_SERVICE_PROFILE,
-- 
1.8.1.4

>From 48c449285ee2b188bbe24eb872385b680c26a15c Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Mon, 15 Apr 2013 12:19:35 +0200
Subject: [PATCH 2/2] Delete DNS records in ipa-ca on ipa-csreplica-manage del.

https://fedorahosted.org/freeipa/ticket/3547
---
 install/tools/ipa-csreplica-manage | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage
index db368c6..55bf565 100755
--- a/install/tools/ipa-csreplica-manage
+++ b/install/tools/ipa-csreplica-manage
@@ -26,7 +26,7 @@ import ldap, krbV
 from ipapython.ipa_log_manager import *
 
 from ipapython import ipautil
-from ipaserver.install import replication, installutils
+from ipaserver.install import replication, installutils, bindinstance
 from ipaserver import ipaldap
 from ipapython import version
 from ipapython import dogtag
@@ -380,6 +380,18 @@ def del_master(realm, hostname, options):
         except Exception, e:
             sys.exit("There were issues removing a connection: %s" % convert_error(e))
 
+    # 6. And clean up the removed replica DNS entries if any.
+    try:
+        if bindinstance.dns_container_exists(options.host, api.env.basedn,
+                                             dm_password=options.dirman_passwd):
+            api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
+                                      bind_pw=options.dirman_passwd)
+            bind = bindinstance.BindInstance()
+            bind.remove_ipa_ca_dns_records(hostname, realm.lower())
+    except Exception, e:
+        print "Failed to cleanup %s DNS entries: %s" % (hostname, e)
+        print "You may need to manually remove them from the tree"
+
 def add_link(realm, replica1, replica2, dirman_passwd, options):
     repl2 = get_cs_replication_manager(realm, replica2, dirman_passwd)
     try:
-- 
1.8.1.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to