URL: https://github.com/freeipa/freeipa/pull/1232
Author: frasertweedale
 Title: #1232: Making ipa-ca-install more resilient
Action: opened

PR body:
"""
, or: *Proactively run ipa-certupdate for great good!*

These commits fix a couple of issues that can occur after a deployment has been
promoted from CA-less to CA-ful, and the admin does not follow up with
`ipa-certupdate`.  (And why should they have to?)

```
a9ad3b5ab (Fraser Tweedale, 6 days ago)
   Run certupdate after promoting to CA-ful deployment

   After installing a CA in a CA-less installations (using ipa-ca-install),
   the new CA certificate is not installed in
   /etc/httpd/alias. This causes communication failure between IPA framework
   and Dogtag (it cannot verify the Dogtag server certificate).

   Perform a CertUpdate as the final step when promoting a CA-less deployment
   to CA-ful.

   Fixes: https://pagure.io/freeipa/issue/7230

21fbf7088 (Fraser Tweedale, 7 days ago)
   ipa-ca-install: run certupdate as initial step

   When installing a CA replica, perform a certupdate to ensure that the
   relevant CA cert is present.  This is necessary if the admin has just
   promoted the topology from CA-less to CA-ful but didn't manually run
   ipa-certupdate afterwards.

   Fixes: https://pagure.io/freeipa/issue/6577

9520781fb (Fraser Tweedale, 7 days ago)
   CertUpdate: make it easy to invoke from other programs

   The guts of ipa-certupdate are useful to execute as part of other programs
   (e.g. as a first step of ipa-ca-install).  Refactor
   ipa_certupdate.CertUpdate to make it easy to do that.  In particular, make
   it possible to use an already-initialised API object.

   Part of: https://pagure.io/freeipa/issue/6577
```
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1232/head:pr1232
git checkout pr1232
From 9520781fb5d198f274cf7ccadec5c434ada69535 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftwee...@redhat.com>
Date: Mon, 30 Oct 2017 17:52:07 +1100
Subject: [PATCH 1/3] CertUpdate: make it easy to invoke from other programs

The guts of ipa-certupdate are useful to execute as part of other
programs (e.g. as a first step of ipa-ca-install).  Refactor
ipa_certupdate.CertUpdate to make it easy to do that.  In
particular, make it possible to use an already-initialised API
object.

Part of: https://pagure.io/freeipa/issue/6577
---
 ipaclient/install/ipa_certupdate.py | 63 ++++++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 25 deletions(-)

diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py
index 06fd079226..32407ad967 100644
--- a/ipaclient/install/ipa_certupdate.py
+++ b/ipaclient/install/ipa_certupdate.py
@@ -56,30 +56,36 @@ def run(self):
         api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA)
         api.finalize()
 
+        api.Backend.rpcclient.connect()
+        self.run_with_api(api)
+        api.Backend.rpcclient.disconnect()
+
+    @classmethod
+    def run_with_api(cls, api):
+        """
+        Run the certupdate procedure with the given API object.
+
+        :param api: API object with ldap2/rpcclient backend connected
+                    (such that Commands can be invoked)
+
+        """
         server = urlsplit(api.env.jsonrpc_uri).hostname
         ldap_uri = ipaldap.get_ldap_uri(server)
         ldap = ipaldap.LDAPClient(ldap_uri)
 
         tmpdir = tempfile.mkdtemp(prefix="tmp-")
         ccache_name = os.path.join(tmpdir, 'ccache')
+        old_krb5ccname = os.environ.get('KRB5CCNAME')
         try:
             principal = str('host/%s@%s' % (api.env.host, api.env.realm))
             kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_name)
             os.environ['KRB5CCNAME'] = ccache_name
 
-            api.Backend.rpcclient.connect()
             try:
-                result = api.Backend.rpcclient.forward(
-                    'ca_is_enabled',
-                    version=u'2.107',
-                )
+                result = api.Command.ca_is_enabled(version=u'2.107')
                 ca_enabled = result['result']
             except (errors.CommandError, errors.NetworkError):
-                result = api.Backend.rpcclient.forward(
-                    'env',
-                    server=True,
-                    version=u'2.0',
-                )
+                result = api.Command.env(server=True, version=u'2.0')
                 ca_enabled = result['result']['enable_ra']
 
             ldap.gssapi_bind()
@@ -92,13 +98,16 @@ def run(self):
             else:
                 lwcas = []
 
-            api.Backend.rpcclient.disconnect()
         finally:
+            if old_krb5ccname is None:
+                del os.environ['KRB5CCNAME']
+            else:
+                os.environ['KRB5CCNAME'] = old_krb5ccname
             shutil.rmtree(tmpdir)
 
         server_fstore = sysrestore.FileStore(paths.SYSRESTORE)
         if server_fstore.has_files():
-            self.update_server(certs)
+            cls.update_server(certs)
             try:
                 # pylint: disable=import-error,ipa-forbidden-import
                 from ipaserver.install import cainstance
@@ -108,12 +117,13 @@ def run(self):
                 logger.exception(
                     "Failed to add lightweight CA tracking requests")
 
-        self.update_client(certs)
+        cls.update_client(certs)
 
-    def update_client(self, certs):
-        self.update_file(paths.IPA_CA_CRT, certs)
-        self.update_file(paths.KDC_CA_BUNDLE_PEM, certs)
-        self.update_file(paths.CA_BUNDLE_PEM, certs)
+    @classmethod
+    def update_client(cls, certs):
+        cls.update_file(paths.IPA_CA_CRT, certs)
+        cls.update_file(paths.KDC_CA_BUNDLE_PEM, certs)
+        cls.update_file(paths.CA_BUNDLE_PEM, certs)
 
         ipa_db = certdb.NSSDatabase(api.env.nss_dir)
 
@@ -127,19 +137,20 @@ def update_client(self, certs):
                                  nickname, ipa_db.secdir, e)
                     break
 
-        self.update_db(ipa_db.secdir, certs)
+        cls.update_db(ipa_db.secdir, certs)
 
         tasks.remove_ca_certs_from_systemwide_ca_store()
         tasks.insert_ca_certs_into_systemwide_ca_store(certs)
 
-    def update_server(self, certs):
+    @classmethod
+    def update_server(cls, certs):
         instance = '-'.join(api.env.realm.split('.'))
-        self.update_db(
+        cls.update_db(
             paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs)
         if services.knownservices.dirsrv.is_running():
             services.knownservices.dirsrv.restart(instance)
 
-        self.update_db(paths.HTTPD_ALIAS_DIR, certs)
+        cls.update_db(paths.HTTPD_ALIAS_DIR, certs)
         if services.knownservices.httpd.is_running():
             services.knownservices.httpd.restart()
 
@@ -170,17 +181,19 @@ def update_server(self, certs):
             logger.debug("modifying certmonger request '%s'", request_id)
             certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent')
 
-        self.update_file(paths.CA_CRT, certs)
-        self.update_file(paths.CACERT_PEM, certs)
+        cls.update_file(paths.CA_CRT, certs)
+        cls.update_file(paths.CACERT_PEM, certs)
 
-    def update_file(self, filename, certs, mode=0o444):
+    @staticmethod
+    def update_file(filename, certs, mode=0o444):
         certs = (c[0] for c in certs if c[2] is not False)
         try:
             x509.write_certificate_list(certs, filename)
         except Exception as e:
             logger.error("failed to update %s: %s", filename, e)
 
-    def update_db(self, path, certs):
+    @staticmethod
+    def update_db(path, certs):
         db = certdb.NSSDatabase(path)
         for cert, nickname, trusted, eku in certs:
             trust_flags = certstore.key_policy_to_trust_flags(

From 21fbf7088f9c129f77d7308186e295e2a486c1da Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftwee...@redhat.com>
Date: Mon, 30 Oct 2017 18:05:56 +1100
Subject: [PATCH 2/3] ipa-ca-install: run certupdate as initial step

When installing a CA replica, perform a certupdate to ensure that
the relevant CA cert is present.  This is necessary if the admin has
just promoted the topology from CA-less to CA-ful but didn't
manually run ipa-certupdate afterwards.

Fixes: https://pagure.io/freeipa/issue/6577
---
 install/tools/ipa-ca-install | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 64478bb0e8..498a5cf114 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -27,6 +27,7 @@ import tempfile
 from ipalib.install.kinit import kinit_keytab
 from ipapython import ipautil
 
+from ipaclient.install.ipa_certupdate import CertUpdate
 from ipaserver.install import installutils
 from ipaserver.install.installutils import create_replica_config
 from ipaserver.install.installutils import check_creds, ReplicaConfig
@@ -174,6 +175,16 @@ def install_replica(safe_options, options, filename):
             not options.skip_conncheck and options.unattended):
         sys.exit('admin password required')
 
+    # Run ipa-certupdate to ensure we have the CA cert.  This is
+    # necessary if the admin has just promoted the topology from
+    # CA-less to CA-ful, and ipa-certupdate has not been run yet.
+    CertUpdate.run_with_api(api)
+
+    # CertUpdate restarts DS causing broken pipe on the original
+    # connection, so reconnect the backend.
+    api.Backend.ldap2.disconnect()
+    api.Backend.ldap2.connect()
+
     if options.promote:
         config = ReplicaConfig()
         config.ca_host_name = None

From a9ad3b5ab72a12144e936faf4bc7160fc10ee209 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftwee...@redhat.com>
Date: Tue, 31 Oct 2017 18:20:15 +1100
Subject: [PATCH 3/3] Run certupdate after promoting to CA-ful deployment

After installing a CA in a CA-less installations (using
ipa-ca-install), the new CA certificate is not installed in
/etc/httpd/alias. This causes communication failure between IPA
framework and Dogtag (it cannot verify the Dogtag server
certificate).

Perform a CertUpdate as the final step when promoting a CA-less
deployment to CA-ful.

Fixes: https://pagure.io/freeipa/issue/7230
---
 install/tools/ipa-ca-install | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 498a5cf114..65d0b38f65 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -254,6 +254,10 @@ def install_master(safe_options, options):
     ca.install_check(True, None, options)
     ca.install(True, None, options)
 
+    # Run ipa-certupdate to add the new CA certificate to
+    # certificate databases on this server.
+    logger.info("Updating certificate databases.")
+    CertUpdate.run_with_api(api)
 
 def install(safe_options, options, filename):
     options.promote = False
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to