[Freeipa-devel] [PATCH] 0044-0045 Add profiles and default CA ACL on migration

Fraser Tweedale ftweedal at redhat.com
Tue Nov 24 07:37:54 UTC 2015


On Mon, Nov 23, 2015 at 10:05:32AM +0100, Jan Cholasta wrote:
> On 23.11.2015 06:54, Fraser Tweedale wrote:
> >Hi all,
> >
> >The attached patches fix #5459[1]: Default CA ACL rule is not
> >created during ipa-replica-install.
> >
> >These patches apply on branch ipa-4-2.  There is a (trivial)
> >conflict in imports when applying to master.
> 
> When a patch does not apply cleanly on all the target branches, you should
> attach a rebased patch as well.
> 
> >
> >I strongly recommend review / testing of these patches with patches
> >0042-0043[2] due to the prevalence of the other issue.
> >
> >[1] https://fedorahosted.org/freeipa/ticket/5459
> >[2] https://www.redhat.com/archives/freeipa-devel/2015-November/msg00298.html
> 
> Patch 0044: ACK
> 
> Patch 0045:
> 
> 1) The check in caacl_del could be better, please take a look at how the
> admins group is handled in ipalib/plugins/group.py for an example. You
> should at least raise ProtectedEntryError rather than ValidationError.
> 
> 2) _add_default_caacl() should be located in
> ipaserver/install/cainstance.py.
> 
> 3) Rather than calling the cainstance functions in replicainstall.install(),
> they should be called from CAInstance.configure_instance() to make them
> effective in ipa-ca-install and replica promotion as well.
> 
> Honza
> 
Updated patches for ipa-4-2 and master branches attached.

The new patch 0045 is somewhat more intrusive; I have tested server
install, replica install (with CA) from 3.0 and 4.2 master and
ipa-ca-install with replica file from 3.0 master... but more testing
would be no bad thing!

I'll be offline for a few hours but will check back later tonight;
see where things are at.

Thanks,
Fraser
-------------- next part --------------
From 354796196f029865e4f5a652900288e043d9c03a Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 23 Nov 2015 12:09:32 +1100
Subject: [PATCH 44/45] Do not erroneously reinit NSS in Dogtag interface

The Dogtag interface always attempts to (re)init NSS, which can fail
with SEC_ERROR_BUSY.  Do not reinitialise NSS when it has already
been initialised with the given dbdir.

Part of: https://fedorahosted.org/freeipa/ticket/5459
---
 ipapython/dogtag.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
index 71de96dc6889ca677db2cf7bb4f2d7b56df832f6..0436d5f464aac20c6b3c7db7b1c3a972d3533823 100644
--- a/ipapython/dogtag.py
+++ b/ipapython/dogtag.py
@@ -265,7 +265,8 @@ def https_request(host, port, url, secdir, password, nickname,
     """
 
     def connection_factory(host, port):
-        conn = nsslib.NSSConnection(host, port, dbdir=secdir,
+        no_init = secdir == nsslib.current_dbdir
+        conn = nsslib.NSSConnection(host, port, dbdir=secdir, no_init=no_init,
                                     tls_version_min=api.env.tls_version_min,
                                     tls_version_max=api.env.tls_version_max)
         conn.set_debuglevel(0)
-- 
2.4.3

-------------- next part --------------
From c0234a507fada45eb64a00e1d3e6ed39321564bc Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 23 Nov 2015 12:09:32 +1100
Subject: [PATCH 44/45] Do not erroneously reinit NSS in Dogtag interface

The Dogtag interface always attempts to (re)init NSS, which can fail
with SEC_ERROR_BUSY.  Do not reinitialise NSS when it has already
been initialised with the given dbdir.

Part of: https://fedorahosted.org/freeipa/ticket/5459
---
 ipapython/dogtag.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
index 26b2de6ca77202fa9ccc61ee16ed7623e10ecb5f..8996902ba92f0fdd6106e2650c2decde375c593b 100644
--- a/ipapython/dogtag.py
+++ b/ipapython/dogtag.py
@@ -255,7 +255,8 @@ def https_request(host, port, url, secdir, password, nickname,
     """
 
     def connection_factory(host, port):
-        conn = nsslib.NSSConnection(host, port, dbdir=secdir,
+        no_init = secdir == nsslib.current_dbdir
+        conn = nsslib.NSSConnection(host, port, dbdir=secdir, no_init=no_init,
                                     tls_version_min=api.env.tls_version_min,
                                     tls_version_max=api.env.tls_version_max)
         conn.set_debuglevel(0)
-- 
2.4.3

-------------- next part --------------
From 81d939ad6755ab80b7db2e592d08730d88f1e06b Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 23 Nov 2015 12:09:32 +1100
Subject: [PATCH 45/45] Add profiles and default CA ACL on migration

Profiles and the default CA ACL were not being added during replica
install from pre-4.2 servers.  Update ipa-replica-install to add
these if they are missing.

Also update the caacl plugin to prevent deletion of the default CA
ACL and instruct the administrator to disable it instead.

To ensure that the cainstance installation can add profiles, supply
the RA certificate as part of the instance configuration.
Certmonger renewal setup is avoided at this point because the NSSDB
gets reinitialised later in installation procedure.

Also move the addition of the default CA ACL from dsinstance
installation to cainstance installation.

Fixes: https://fedorahosted.org/freeipa/ticket/5459
---
 install/share/Makefile.am                    |   1 -
 install/share/default-caacl.ldif             |  11 ---
 install/updates/50-dogtag10-migration.update |   1 +
 ipalib/plugins/caacl.py                      |   8 +++
 ipaserver/install/ca.py                      |   5 +-
 ipaserver/install/cainstance.py              | 100 ++++++++++++++++++++-------
 ipaserver/install/dsinstance.py              |   4 --
 ipaserver/install/server/replicainstall.py   |   3 +
 ipaserver/install/server/upgrade.py          |  13 +---
 9 files changed, 90 insertions(+), 56 deletions(-)
 delete mode 100644 install/share/default-caacl.ldif

diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index 92508a9bab864fdfd3d299e52296f37580cabd2b..42f3972e1061fda5bfd23b2fa8f63d675f92f5ba 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -31,7 +31,6 @@ app_DATA =				\
 	caJarSigningCert.cfg.template	\
 	custodia.conf.template		\
 	default-aci.ldif		\
-	default-caacl.ldif		\
 	default-hbac.ldif		\
 	default-smb-group.ldif		\
 	default-trust-view.ldif		\
diff --git a/install/share/default-caacl.ldif b/install/share/default-caacl.ldif
deleted file mode 100644
index f3cd5b4d4e3a79bc6638dc1ffdd7028596ded254..0000000000000000000000000000000000000000
--- a/install/share/default-caacl.ldif
+++ /dev/null
@@ -1,11 +0,0 @@
-# default CA ACL that grants use of caIPAserviceCert on top-level CA to all hosts and services
-dn: ipauniqueid=autogenerate,cn=caacls,cn=ca,$SUFFIX
-changetype: add
-objectclass: ipaassociation
-objectclass: ipacaacl
-ipauniqueid: autogenerate
-cn: hosts_services_caIPAserviceCert
-ipaenabledflag: TRUE
-ipamembercertprofile: cn=caIPAserviceCert,cn=certprofiles,cn=ca,$SUFFIX
-hostcategory: all
-servicecategory: all
diff --git a/install/updates/50-dogtag10-migration.update b/install/updates/50-dogtag10-migration.update
index 2ab9d15bd220540dbc6b3fcd7928fc15c42caf80..0070c308aefc39aa4c27a046d185ce6d268e6270 100644
--- a/install/updates/50-dogtag10-migration.update
+++ b/install/updates/50-dogtag10-migration.update
@@ -16,3 +16,4 @@ addifexist:resourceACLS:certServer.ca.groups:execute:allow (execute) group="Admi
 addifexist:resourceACLS:certServer.ca.users:execute:allow (execute) group="Administrators":Admins may execute user operations
 replace:resourceACLS:certServer.securitydomain.domainxml:read,modify:allow (read) user="anybody";allow (modify) group="Subsystem Group":Anybody is allowed to read domain.xml but only Subsystem group is allowed to modify the domain.xml::certServer.securitydomain.domainxml:read,modify:allow (read) user="anybody";allow (modify) group="Subsystem Group" || group="Enterprise CA Administrators" || group="Enterprise KRA Administrators" || group="Enterprise RA Administrators" || group="Enterprise OCSP Administrators" || group="Enterprise TKS Administrators" || group="Enterprise TPS Administrators":Anybody is allowed to read domain.xml but only Subsystem group and Enterprise Administrators are allowed to modify the domain.xml
 replace:resourceACLS:certServer.ca.connectorInfo:read,modify:allow (modify,read) group="Enterprise KRA Administrators":Only Enterprise Administrators are allowed to update the connector information::certServer.ca.connectorInfo:read,modify:allow (read) group="Enterprise KRA Administrators";allow (modify) group="Enterprise KRA Administrators" || group="Subsystem Group":Only Enterprise Administrators and Subsystem Group are allowed to update the connector information
+addifexist:resourceACLS:certServer.profile.configuration:read,modify:allow (read,modify) group="Certificate Manager Agents":Certificate Manager agents may modify (create/update/delete) and read profiles
diff --git a/ipalib/plugins/caacl.py b/ipalib/plugins/caacl.py
index 247d6df143aef1fba9f0ee74a9f7d8386bef5180..64dbec16e11e9fa2a67287b195b4bd1180a379e7 100644
--- a/ipalib/plugins/caacl.py
+++ b/ipalib/plugins/caacl.py
@@ -307,6 +307,14 @@ class caacl_del(LDAPDelete):
 
     msg_summary = _('Deleted CA ACL "%(value)s"')
 
+    def pre_callback(self, ldap, dn, *keys, **options):
+        if keys[0] == 'hosts_services_caIPAserviceCert':
+            raise errors.ProtectedEntryError(
+                label=_("CA ACL"),
+                key=keys[0],
+                reason=_("default CA ACL can be only disabled"))
+        return dn
+
 
 @register()
 class caacl_mod(LDAPUpdate):
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index 8d0252cbb3c4141c882a252a7c65f062b1cb1447..51871f2dc18ae3b890dcd17656bef1914a658fee 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -138,9 +138,10 @@ def install_step_0(standalone, replica_config, options):
         if standalone:
             api.Backend.ldap2.disconnect()
 
-        cainstance.install_replica_ca(replica_config, postinstall)
+        cainstance.install_replica_ca(replica_config, postinstall,
+                ra_p12=getattr(options, 'ra_p12', None))
 
-        if standalone:
+        if standalone and not api.Backend.ldap2.isconnected():
             api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
                                       bind_pw=dm_password)
 
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 448e42e2bab8370c0ec7caa2a189d2a1b33eaa18..90edb362f496b89f433532bf8786c29da3902de9 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -410,7 +410,7 @@ class CAInstance(DogtagInstance):
                            cert_file=None, cert_chain_file=None,
                            master_replication_port=None,
                            subject_base=None, ca_signing_algorithm=None,
-                           ca_type=None):
+                           ca_type=None, ra_p12=None):
         """Create a CA instance.
 
            For Dogtag 9, this may involve creating the pki-ca instance.
@@ -484,7 +484,10 @@ class CAInstance(DogtagInstance):
                 self.step("requesting RA certificate from CA", self.__request_ra_certificate)
                 self.step("issuing RA agent certificate", self.__issue_ra_cert)
                 self.step("adding RA agent as a trusted user", self.__create_ca_agent)
-                self.step("authorizing RA to modify profiles", self.__configure_profiles_acl)
+            elif ra_p12 is not None:
+                self.step("importing RA certificate from PKCS #12 file",
+                          lambda: self.import_ra_cert(ra_p12, configure_renewal=False))
+            self.step("authorizing RA to modify profiles", configure_profiles_acl)
             self.step("configure certmonger for renewals", self.configure_certmonger_renewal)
             self.step("configure certificate renewals", self.configure_renewal)
             if not self.clone:
@@ -492,9 +495,12 @@ class CAInstance(DogtagInstance):
             self.step("configure Server-Cert certificate renewal", self.track_servercert)
             self.step("Configure HTTP to proxy connections",
                       self.http_proxy)
-            if not self.clone:
-                self.step("restarting certificate server", self.restart_instance)
-                self.step("Importing IPA certificate profiles", import_included_profiles)
+            self.step("restarting certificate server", self.restart_instance)
+            self.step("migrating certificate profiles to LDAP",
+                      migrate_profiles_to_ldap)
+            self.step("importing IPA certificate profiles",
+                      import_included_profiles)
+            self.step("adding default CA ACL", ensure_default_caacl)
 
         self.start_creation(runtime=210)
 
@@ -921,7 +927,7 @@ class CAInstance(DogtagInstance):
 
         export_kra_agent_pem()
 
-    def import_ra_cert(self, rafile):
+    def import_ra_cert(self, rafile, configure_renewal=True):
         """
         Cloned RAs will use the same RA agent cert as the master so we
         need to import from a PKCS#12 file.
@@ -937,7 +943,8 @@ class CAInstance(DogtagInstance):
         finally:
             os.remove(agent_name)
 
-        self.configure_agent_renewal()
+        if configure_renewal:
+            self.configure_agent_renewal()
 
         export_kra_agent_pem()
 
@@ -987,10 +994,6 @@ class CAInstance(DogtagInstance):
 
         conn.disconnect()
 
-    def __configure_profiles_acl(self):
-        """Allow the Certificate Manager Agents group to modify profiles."""
-        configure_profiles_acl()
-
     def __run_certutil(self, args, database=None, pwd_file=None, stdin=None):
         if not database:
             database = self.ra_agent_db
@@ -1654,7 +1657,7 @@ def replica_ca_install_check(config):
         exit('IPA schema missing on master CA directory server')
 
 
-def install_replica_ca(config, postinstall=False):
+def install_replica_ca(config, postinstall=False, ra_p12=None):
     """
     Install a CA on a replica.
 
@@ -1691,7 +1694,7 @@ def install_replica_ca(config, postinstall=False):
         ca.create_ra_agent_db = False
     ca.configure_instance(config.host_name,
                           config.dirman_password, config.dirman_password,
-                          pkcs12_info=(cafile,),
+                          pkcs12_info=(cafile,), ra_p12=ra_p12,
                           master_host=config.master_host_name,
                           master_replication_port=config.ca_ds_port,
                           subject_base=config.subject_base)
@@ -1816,6 +1819,14 @@ def update_people_entry(dercert):
     return True
 
 def ensure_ldap_profiles_container():
+    ensure_entry(
+        DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca')),
+        objectclass=['top', 'organizationalUnit'],
+        ou=['certificateProfiles'],
+    )
+
+
+def ensure_entry(dn, **attrs):
     server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
 
@@ -1823,40 +1834,39 @@ def ensure_ldap_profiles_container():
     if not conn.isconnected():
         conn.connect(autobind=True)
 
-    dn = DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca'))
     try:
         conn.get_entry(dn)
     except errors.NotFound:
         # entry doesn't exist; add it
-        entry = conn.make_entry(
-            dn,
-            objectclass=['top', 'organizationalUnit'],
-            ou=['certificateProfiles'],
-        )
+        entry = conn.make_entry(dn, **attrs)
         conn.add_entry(entry)
 
     conn.disconnect()
 
 
 def configure_profiles_acl():
+    """Allow the Certificate Manager Agents group to modify profiles."""
     server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
     updated = False
 
     dn = DN(('cn', 'aclResources'), ('o', 'ipaca'))
-    rule = (
+    new_rules = [
         'certServer.profile.configuration:read,modify:allow (read,modify) '
         'group="Certificate Manager Agents":'
-        'Certificate Manager agents may modify (create/update/delete) and read profiles'
-    )
-    modlist = [(ldap.MOD_ADD, 'resourceACLS', [rule])]
+        'Certificate Manager agents may modify (create/update/delete) and read profiles',
+
+        'certServer.ca.account:login,logout:allow (login,logout) '
+        'user="anybody":Anybody can login and logout',
+    ]
 
     conn = ldap2.ldap2(api, ldap_uri=dogtag_uri)
     if not conn.isconnected():
         conn.connect(autobind=True)
-    rules = conn.get_entry(dn).get('resourceACLS', [])
-    if rule not in rules:
-        conn.conn.modify_s(str(dn), modlist)
+    cur_rules = conn.get_entry(dn).get('resourceACLS', [])
+    add_rules = [rule for rule in new_rules if rule not in cur_rules]
+    if add_rules:
+        conn.conn.modify_s(str(dn), [(ldap.MOD_ADD, 'resourceACLS', add_rules)])
         updated = True
 
     conn.disconnect()
@@ -1876,6 +1886,17 @@ def import_included_profiles():
     if not conn.isconnected():
         conn.connect(autobind=True)
 
+    ensure_entry(
+        DN(('cn', 'ca'), api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['ca'],
+    )
+    ensure_entry(
+        DN(api.env.container_certprofile, api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['certprofiles'],
+    )
+
     api.Backend.ra_certprofile._read_password()
     api.Backend.ra_certprofile.override_port = 8443
 
@@ -1981,6 +2002,33 @@ def _create_dogtag_profile(profile_id, profile_data):
                 "(it is probably already enabled)")
 
 
+def ensure_default_caacl():
+    """Add the default CA ACL if missing."""
+    if not api.Backend.ldap2.isconnected():
+        try:
+            api.Backend.ldap2.connect(autobind=True)
+        except errors.PublicError as e:
+            root_logger.error("Cannot connect to LDAP to add CA ACLs: %s", e)
+            return
+
+    ensure_entry(
+        DN(('cn', 'ca'), api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['ca'],
+    )
+    ensure_entry(
+        DN(api.env.container_caacl, api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['certprofiles'],
+    )
+
+    if not api.Command.caacl_find()['result']:
+        api.Command.caacl_add(u'hosts_services_caIPAserviceCert',
+            hostcategory=u'all', servicecategory=u'all')
+        api.Command.caacl_add_profile(u'hosts_services_caIPAserviceCert',
+            certprofile=(u'caIPAserviceCert',))
+
+
 if __name__ == "__main__":
     standard_logging_setup("install.log")
     ds = dsinstance.DsInstance()
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 7bdcaea31dcdf593d1de3b98a2ddfb926c2ea990..c980ebf4e01c7524e34c41d064580c17a64f5f07 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -332,7 +332,6 @@ class DsInstance(service.Service):
         self.step("adding range check plugin", self.__add_range_check_plugin)
         if hbac_allow:
             self.step("creating default HBAC rule allow_all", self.add_hbac)
-        self.step("creating default CA ACL rule", self.add_caacl)
         self.step("adding sasl mappings to the directory",
                   self.__configure_sasl_mappings)
         self.step("adding entries for topology management", self.__add_topology_entries)
@@ -874,9 +873,6 @@ class DsInstance(service.Service):
     def add_hbac(self):
         self._ldap_mod("default-hbac.ldif", self.sub_dict)
 
-    def add_caacl(self):
-        self._ldap_mod("default-caacl.ldif", self.sub_dict)
-
     def change_admin_password(self, password):
         root_logger.debug("Changing admin password")
         dirname = config_dirname(self.serverid)
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 5ce9eb7092b5349cc9db13b465b3d5b033538ab6..492ea72d88665cce50f359d15d3c45e267ed2f41 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -672,6 +672,9 @@ def install(installer):
         options.domain_name = config.domain_name
         options.host_name = config.host_name
 
+        if ipautil.file_exists(config.dir + "/cacert.p12"):
+            options.ra_p12 = config.dir + "/ra.p12"
+
         ca.install(False, config, options)
 
     krb = install_krb(config, setup_pkinit=not options.no_pkinit)
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index b9621a39d6d5afc0f0e6eada7a635c98ee2f8e21..84339b0a26f1f45b668392739d014f051118c503 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1328,18 +1328,7 @@ def add_default_caacl(ca):
         return
 
     if ca.is_configured():
-        if not api.Backend.ldap2.isconnected():
-            try:
-                api.Backend.ldap2.connect(autobind=True)
-            except ipalib.errors.PublicError as e:
-                root_logger.error("Cannot connect to LDAP to add CA ACLs: %s", e)
-                return
-
-        if not api.Command.caacl_find()['result']:
-            api.Command.caacl_add(u'hosts_services_caIPAserviceCert',
-                hostcategory=u'all', servicecategory=u'all')
-            api.Command.caacl_add_profile(u'hosts_services_caIPAserviceCert',
-                certprofile=(u'caIPAserviceCert',))
+        cainstance.ensure_default_caacl()
 
     sysupgrade.set_upgrade_state('caacl', 'add_default_caacl', True)
 
-- 
2.4.3

-------------- next part --------------
From b9523d1d101f39cd56bc23c8bb3bc782f44ca7b4 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 23 Nov 2015 12:09:32 +1100
Subject: [PATCH 45/45] Add profiles and default CA ACL on migration

Profiles and the default CA ACL were not being added during replica
install from pre-4.2 servers.  Update ipa-replica-install to add
these if they are missing.

Also update the caacl plugin to prevent deletion of the default CA
ACL and instruct the administrator to disable it instead.

To ensure that the cainstance installation can add profiles, supply
the RA certificate as part of the instance configuration.
Certmonger renewal setup is avoided at this point because the NSSDB
gets reinitialised later in installation procedure.

Also move the addition of the default CA ACL from dsinstance
installation to cainstance installation.

Fixes: https://fedorahosted.org/freeipa/ticket/5459
---
 install/share/Makefile.am                    |   1 -
 install/share/default-caacl.ldif             |  11 ---
 install/updates/50-dogtag10-migration.update |   1 +
 ipalib/plugins/caacl.py                      |   8 +++
 ipaserver/install/ca.py                      |   5 +-
 ipaserver/install/cainstance.py              | 100 ++++++++++++++++++++-------
 ipaserver/install/dsinstance.py              |   4 --
 ipaserver/install/server/replicainstall.py   |   3 +
 ipaserver/install/server/upgrade.py          |  13 +---
 9 files changed, 90 insertions(+), 56 deletions(-)
 delete mode 100644 install/share/default-caacl.ldif

diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index d68c40e693a1d86c70d8ccd81ef2c915b2e1f61e..e4cca8708ab0042d6cb37eba31341e53e3cdac4d 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -29,7 +29,6 @@ app_DATA =				\
 	bootstrap-template.ldif		\
 	caJarSigningCert.cfg.template	\
 	default-aci.ldif		\
-	default-caacl.ldif		\
 	default-hbac.ldif		\
 	default-smb-group.ldif		\
 	default-trust-view.ldif		\
diff --git a/install/share/default-caacl.ldif b/install/share/default-caacl.ldif
deleted file mode 100644
index f3cd5b4d4e3a79bc6638dc1ffdd7028596ded254..0000000000000000000000000000000000000000
--- a/install/share/default-caacl.ldif
+++ /dev/null
@@ -1,11 +0,0 @@
-# default CA ACL that grants use of caIPAserviceCert on top-level CA to all hosts and services
-dn: ipauniqueid=autogenerate,cn=caacls,cn=ca,$SUFFIX
-changetype: add
-objectclass: ipaassociation
-objectclass: ipacaacl
-ipauniqueid: autogenerate
-cn: hosts_services_caIPAserviceCert
-ipaenabledflag: TRUE
-ipamembercertprofile: cn=caIPAserviceCert,cn=certprofiles,cn=ca,$SUFFIX
-hostcategory: all
-servicecategory: all
diff --git a/install/updates/50-dogtag10-migration.update b/install/updates/50-dogtag10-migration.update
index 2ab9d15bd220540dbc6b3fcd7928fc15c42caf80..0070c308aefc39aa4c27a046d185ce6d268e6270 100644
--- a/install/updates/50-dogtag10-migration.update
+++ b/install/updates/50-dogtag10-migration.update
@@ -16,3 +16,4 @@ addifexist:resourceACLS:certServer.ca.groups:execute:allow (execute) group="Admi
 addifexist:resourceACLS:certServer.ca.users:execute:allow (execute) group="Administrators":Admins may execute user operations
 replace:resourceACLS:certServer.securitydomain.domainxml:read,modify:allow (read) user="anybody";allow (modify) group="Subsystem Group":Anybody is allowed to read domain.xml but only Subsystem group is allowed to modify the domain.xml::certServer.securitydomain.domainxml:read,modify:allow (read) user="anybody";allow (modify) group="Subsystem Group" || group="Enterprise CA Administrators" || group="Enterprise KRA Administrators" || group="Enterprise RA Administrators" || group="Enterprise OCSP Administrators" || group="Enterprise TKS Administrators" || group="Enterprise TPS Administrators":Anybody is allowed to read domain.xml but only Subsystem group and Enterprise Administrators are allowed to modify the domain.xml
 replace:resourceACLS:certServer.ca.connectorInfo:read,modify:allow (modify,read) group="Enterprise KRA Administrators":Only Enterprise Administrators are allowed to update the connector information::certServer.ca.connectorInfo:read,modify:allow (read) group="Enterprise KRA Administrators";allow (modify) group="Enterprise KRA Administrators" || group="Subsystem Group":Only Enterprise Administrators and Subsystem Group are allowed to update the connector information
+addifexist:resourceACLS:certServer.profile.configuration:read,modify:allow (read,modify) group="Certificate Manager Agents":Certificate Manager agents may modify (create/update/delete) and read profiles
diff --git a/ipalib/plugins/caacl.py b/ipalib/plugins/caacl.py
index 247d6df143aef1fba9f0ee74a9f7d8386bef5180..64dbec16e11e9fa2a67287b195b4bd1180a379e7 100644
--- a/ipalib/plugins/caacl.py
+++ b/ipalib/plugins/caacl.py
@@ -307,6 +307,14 @@ class caacl_del(LDAPDelete):
 
     msg_summary = _('Deleted CA ACL "%(value)s"')
 
+    def pre_callback(self, ldap, dn, *keys, **options):
+        if keys[0] == 'hosts_services_caIPAserviceCert':
+            raise errors.ProtectedEntryError(
+                label=_("CA ACL"),
+                key=keys[0],
+                reason=_("default CA ACL can be only disabled"))
+        return dn
+
 
 @register()
 class caacl_mod(LDAPUpdate):
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index 39f4435e2d8f1b66b4b1acf2f2219c33120707dc..84cbf423246534259cd6b7a8cca25caa16e5594f 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -134,9 +134,10 @@ def install_step_0(standalone, replica_config, options):
         if standalone:
             api.Backend.ldap2.disconnect()
 
-        cainstance.install_replica_ca(replica_config, postinstall)
+        cainstance.install_replica_ca(replica_config, postinstall,
+                ra_p12=getattr(options, 'ra_p12', None))
 
-        if standalone:
+        if standalone and not api.Backend.ldap2.isconnected():
             api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
                                       bind_pw=dm_password)
 
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 3e3dce93de2b8ca48a3fe3ea5994ee92a1b0ce49..189876f3c0d980e78165d73eed86b2830ac8c5b8 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -391,7 +391,7 @@ class CAInstance(DogtagInstance):
                            cert_file=None, cert_chain_file=None,
                            master_replication_port=None,
                            subject_base=None, ca_signing_algorithm=None,
-                           ca_type=None):
+                           ca_type=None, ra_p12=None):
         """Create a CA instance.
 
            For Dogtag 9, this may involve creating the pki-ca instance.
@@ -465,7 +465,10 @@ class CAInstance(DogtagInstance):
                 self.step("requesting RA certificate from CA", self.__request_ra_certificate)
                 self.step("issuing RA agent certificate", self.__issue_ra_cert)
                 self.step("adding RA agent as a trusted user", self.__create_ca_agent)
-                self.step("authorizing RA to modify profiles", self.__configure_profiles_acl)
+            elif ra_p12 is not None:
+                self.step("importing RA certificate from PKCS #12 file",
+                          lambda: self.import_ra_cert(ra_p12, configure_renewal=False))
+            self.step("authorizing RA to modify profiles", configure_profiles_acl)
             self.step("configure certmonger for renewals", self.configure_certmonger_renewal)
             self.step("configure certificate renewals", self.configure_renewal)
             if not self.clone:
@@ -473,9 +476,12 @@ class CAInstance(DogtagInstance):
             self.step("configure Server-Cert certificate renewal", self.track_servercert)
             self.step("Configure HTTP to proxy connections",
                       self.http_proxy)
-            if not self.clone:
-                self.step("restarting certificate server", self.restart_instance)
-                self.step("Importing IPA certificate profiles", import_included_profiles)
+            self.step("restarting certificate server", self.restart_instance)
+            self.step("migrating certificate profiles to LDAP",
+                      migrate_profiles_to_ldap)
+            self.step("importing IPA certificate profiles",
+                      import_included_profiles)
+            self.step("adding default CA ACL", ensure_default_caacl)
 
         self.start_creation(runtime=210)
 
@@ -887,7 +893,7 @@ class CAInstance(DogtagInstance):
 
         export_kra_agent_pem()
 
-    def import_ra_cert(self, rafile):
+    def import_ra_cert(self, rafile, configure_renewal=True):
         """
         Cloned RAs will use the same RA agent cert as the master so we
         need to import from a PKCS#12 file.
@@ -903,7 +909,8 @@ class CAInstance(DogtagInstance):
         finally:
             os.remove(agent_name)
 
-        self.configure_agent_renewal()
+        if configure_renewal:
+            self.configure_agent_renewal()
 
         export_kra_agent_pem()
 
@@ -953,10 +960,6 @@ class CAInstance(DogtagInstance):
 
         conn.disconnect()
 
-    def __configure_profiles_acl(self):
-        """Allow the Certificate Manager Agents group to modify profiles."""
-        configure_profiles_acl()
-
     def __run_certutil(self, args, database=None, pwd_file=None, stdin=None):
         if not database:
             database = self.ra_agent_db
@@ -1491,7 +1494,7 @@ def replica_ca_install_check(config):
         exit('IPA schema missing on master CA directory server')
 
 
-def install_replica_ca(config, postinstall=False):
+def install_replica_ca(config, postinstall=False, ra_p12=None):
     """
     Install a CA on a replica.
 
@@ -1533,7 +1536,7 @@ def install_replica_ca(config, postinstall=False):
         ca.create_ra_agent_db = False
     ca.configure_instance(config.host_name, config.domain_name,
                           config.dirman_password, config.dirman_password,
-                          pkcs12_info=(cafile,),
+                          pkcs12_info=(cafile,), ra_p12=ra_p12,
                           master_host=config.master_host_name,
                           master_replication_port=config.ca_ds_port,
                           subject_base=config.subject_base)
@@ -1658,6 +1661,14 @@ def update_people_entry(dercert):
     return True
 
 def ensure_ldap_profiles_container():
+    ensure_entry(
+        DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca')),
+        objectclass=['top', 'organizationalUnit'],
+        ou=['certificateProfiles'],
+    )
+
+
+def ensure_entry(dn, **attrs):
     server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
 
@@ -1665,40 +1676,39 @@ def ensure_ldap_profiles_container():
     if not conn.isconnected():
         conn.connect(autobind=True)
 
-    dn = DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca'))
     try:
         conn.get_entry(dn)
     except errors.NotFound:
         # entry doesn't exist; add it
-        entry = conn.make_entry(
-            dn,
-            objectclass=['top', 'organizationalUnit'],
-            ou=['certificateProfiles'],
-        )
+        entry = conn.make_entry(dn, **attrs)
         conn.add_entry(entry)
 
     conn.disconnect()
 
 
 def configure_profiles_acl():
+    """Allow the Certificate Manager Agents group to modify profiles."""
     server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
     updated = False
 
     dn = DN(('cn', 'aclResources'), ('o', 'ipaca'))
-    rule = (
+    new_rules = [
         'certServer.profile.configuration:read,modify:allow (read,modify) '
         'group="Certificate Manager Agents":'
-        'Certificate Manager agents may modify (create/update/delete) and read profiles'
-    )
-    modlist = [(ldap.MOD_ADD, 'resourceACLS', [rule])]
+        'Certificate Manager agents may modify (create/update/delete) and read profiles',
+
+        'certServer.ca.account:login,logout:allow (login,logout) '
+        'user="anybody":Anybody can login and logout',
+    ]
 
     conn = ldap2.ldap2(api, ldap_uri=dogtag_uri)
     if not conn.isconnected():
         conn.connect(autobind=True)
-    rules = conn.get_entry(dn).get('resourceACLS', [])
-    if rule not in rules:
-        conn.conn.modify_s(str(dn), modlist)
+    cur_rules = conn.get_entry(dn).get('resourceACLS', [])
+    add_rules = [rule for rule in new_rules if rule not in cur_rules]
+    if add_rules:
+        conn.conn.modify_s(str(dn), [(ldap.MOD_ADD, 'resourceACLS', add_rules)])
         updated = True
 
     conn.disconnect()
@@ -1718,6 +1728,17 @@ def import_included_profiles():
     if not conn.isconnected():
         conn.connect(autobind=True)
 
+    ensure_entry(
+        DN(('cn', 'ca'), api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['ca'],
+    )
+    ensure_entry(
+        DN(api.env.container_certprofile, api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['certprofiles'],
+    )
+
     api.Backend.ra_certprofile._read_password()
     api.Backend.ra_certprofile.override_port = 8443
 
@@ -1823,6 +1844,33 @@ def _create_dogtag_profile(profile_id, profile_data):
                 "(it is probably already enabled)")
 
 
+def ensure_default_caacl():
+    """Add the default CA ACL if missing."""
+    if not api.Backend.ldap2.isconnected():
+        try:
+            api.Backend.ldap2.connect(autobind=True)
+        except errors.PublicError as e:
+            root_logger.error("Cannot connect to LDAP to add CA ACLs: %s", e)
+            return
+
+    ensure_entry(
+        DN(('cn', 'ca'), api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['ca'],
+    )
+    ensure_entry(
+        DN(api.env.container_caacl, api.env.basedn),
+        objectclass=['top', 'nsContainer'],
+        cn=['certprofiles'],
+    )
+
+    if not api.Command.caacl_find()['result']:
+        api.Command.caacl_add(u'hosts_services_caIPAserviceCert',
+            hostcategory=u'all', servicecategory=u'all')
+        api.Command.caacl_add_profile(u'hosts_services_caIPAserviceCert',
+            certprofile=(u'caIPAserviceCert',))
+
+
 if __name__ == "__main__":
     standard_logging_setup("install.log")
     ds = dsinstance.DsInstance()
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index f33a9e03a4148dde69fc61441c878f5126f8e455..d78158532c4c88d9aa9acf3c65d278f5151458d8 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -310,7 +310,6 @@ class DsInstance(service.Service):
         self.step("adding range check plugin", self.__add_range_check_plugin)
         if hbac_allow:
             self.step("creating default HBAC rule allow_all", self.add_hbac)
-        self.step("creating default CA ACL rule", self.add_caacl)
         self.step("adding entries for topology management", self.__add_topology_entries)
 
         self.__common_post_setup()
@@ -745,9 +744,6 @@ class DsInstance(service.Service):
     def add_hbac(self):
         self._ldap_mod("default-hbac.ldif", self.sub_dict)
 
-    def add_caacl(self):
-        self._ldap_mod("default-caacl.ldif", self.sub_dict)
-
     def change_admin_password(self, password):
         root_logger.debug("Changing admin password")
         dirname = config_dirname(self.serverid)
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index c1edd3e48d36c8ad62c6a72e988604b59c574c0c..4cb0fa7902903f976ea1f7d3ec9614dc93acd4a7 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -575,6 +575,9 @@ def install(installer):
         options.domain_name = config.domain_name
         options.host_name = config.host_name
 
+        if ipautil.file_exists(config.dir + "/cacert.p12"):
+            options.ra_p12 = config.dir + "/ra.p12"
+
         ca.install(False, config, options)
 
     krb = install_krb(config, setup_pkinit=not options.no_pkinit)
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index c8f744c392c7b859459bda63c1f397226553d4ba..945cb3ebd63767cb1d57083e1da7c5605ac5a2f9 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1321,18 +1321,7 @@ def add_default_caacl(ca):
         return
 
     if ca.is_configured():
-        if not api.Backend.ldap2.isconnected():
-            try:
-                api.Backend.ldap2.connect(autobind=True)
-            except ipalib.errors.PublicError as e:
-                root_logger.error("Cannot connect to LDAP to add CA ACLs: %s", e)
-                return
-
-        if not api.Command.caacl_find()['result']:
-            api.Command.caacl_add(u'hosts_services_caIPAserviceCert',
-                hostcategory=u'all', servicecategory=u'all')
-            api.Command.caacl_add_profile(u'hosts_services_caIPAserviceCert',
-                certprofile=(u'caIPAserviceCert',))
+        cainstance.ensure_default_caacl()
 
     sysupgrade.set_upgrade_state('caacl', 'add_default_caacl', True)
 
-- 
2.4.3



More information about the Freeipa-devel mailing list