URL: https://github.com/freeipa/freeipa/pull/1406
Author: tiran
 Title: #1406: [Backport][ipa-4-6] Enable ephemeral KRA requests
Action: opened

PR body:
"""
This PR was opened automatically because PR #1405 was pushed to master and 
backport to ipa-4-6 is required.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1406/head:pr1406
git checkout pr1406
From a8070e091a8aff102d3b6ee1c627b3173c5f17f1 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Wed, 8 Nov 2017 13:21:22 -0500
Subject: [PATCH 1/2] Make the path to CS.cfg a class variable

Rather than passing around the path to CS.cfg for the CA and KRA
set it at object creation and use everywhere.

Make update_cert_config() a real class method instead of a static
method. It wasn't being called that way in any case and makes it
possible to use the class config file.

Related: https://pagure.io/freeipa/issue/6703

Signed-off-by: Rob Crittenden <rcrit...@redhat.com>
---
 ipaserver/install/ca.py             |  2 +-
 ipaserver/install/cainstance.py     | 17 ++++++++---------
 ipaserver/install/dogtaginstance.py | 32 ++++++++++++++++++--------------
 ipaserver/install/kra.py            |  2 +-
 ipaserver/install/krainstance.py    | 21 +++++++++++++++++----
 5 files changed, 45 insertions(+), 29 deletions(-)

diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index 1a104b4b5e..2f1718bc95 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -322,7 +322,7 @@ def install_step_1(standalone, replica_config, options):
     ca.stop('pki-tomcat')
 
     # This is done within stopped_service context, which restarts CA
-    ca.enable_client_auth_to_db(paths.CA_CS_CFG_PATH)
+    ca.enable_client_auth_to_db()
 
     # Lightweight CA key retrieval is configured in step 1 instead
     # of CAInstance.configure_instance (which is invoked from step
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 532a9f11d9..ca61c52162 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -304,6 +304,7 @@ def __init__(self, realm=None, host_name=None):
             service_desc="certificate server",
             host_name=host_name,
             service_prefix=ipalib.constants.PKI_GSSAPI_SERVICE_NAME,
+            config=paths.CA_CS_CFG_PATH,
         )
 
         # for external CAs
@@ -677,12 +678,12 @@ def __update_topology(self):
     def __disable_nonce(self):
         # Turn off Nonces
         update_result = installutils.update_file(
-            paths.CA_CS_CFG_PATH, 'ca.enableNonces=true',
+            self.config, 'ca.enableNonces=true',
             'ca.enableNonces=false')
         if update_result != 0:
             raise RuntimeError("Disabling nonces failed")
         pent = pwd.getpwnam(self.service_user)
-        os.chown(paths.CA_CS_CFG_PATH, pent.pw_uid, pent.pw_gid)
+        os.chown(self.config, pent.pw_uid, pent.pw_gid)
 
     def enable_pkix(self):
         installutils.set_directive(paths.SYSCONFIG_PKI_TOMCAT,
@@ -928,8 +929,7 @@ def __enable_crl_publish(self):
 
         https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Certificate_System/8.0/html/Admin_Guide/Setting_up_Publishing.html
         """
-
-        with installutils.DirectiveSetter(paths.CA_CS_CFG_PATH,
+        with installutils.DirectiveSetter(self.config,
                                           quotes=False, separator='=') as ds:
 
             # Enable file publishing, disable LDAP
@@ -1160,8 +1160,7 @@ def set_renewal_master(self, fqdn=None):
             master_entry['ipaConfigString'].append('caRenewalMaster')
             api.Backend.ldap2.update_entry(master_entry)
 
-    @staticmethod
-    def update_cert_config(nickname, cert):
+    def update_cert_config(self, nickname, cert):
         """
         When renewing a CA subsystem certificate the configuration file
         needs to get the new certificate as well.
@@ -1183,8 +1182,8 @@ def update_cert_config(nickname, cert):
             syslog.syslog(syslog.LOG_ERR, "Failed to backup CS.cfg: %s" % e)
 
         if nickname in directives:
-            DogtagInstance.update_cert_cs_cfg(
-                directives[nickname], cert, paths.CA_CS_CFG_PATH)
+            super(CAInstance, self).update_cert_cs_cfg(
+                directives[nickname], cert)
 
     def __create_ds_db(self):
         '''
@@ -1251,7 +1250,7 @@ def setup_lightweight_ca_key_retrieval(self):
         ]
         for k, v in directives:
             installutils.set_directive(
-                paths.CA_CS_CFG_PATH, k, v, quotes=False, separator='=')
+                self.config, k, v, quotes=False, separator='=')
 
         sysupgrade.set_upgrade_state('dogtag', 'setup_lwca_key_retieval', True)
 
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index 67edaf511c..eeeae8f0de 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -89,7 +89,8 @@ class DogtagInstance(service.Service):
     server_cert_name = None
 
     def __init__(self, realm, subsystem, service_desc, host_name=None,
-                 nss_db=paths.PKI_TOMCAT_ALIAS_DIR, service_prefix=None):
+                 nss_db=paths.PKI_TOMCAT_ALIAS_DIR, service_prefix=None,
+                 config=None):
         """Initializer"""
 
         super(DogtagInstance, self).__init__(
@@ -118,6 +119,7 @@ def __init__(self, realm, subsystem, service_desc, host_name=None,
         self.master_replication_port = None
         self.subject_base = None
         self.nss_db = nss_db
+        self.config = config  # Path to CS.cfg
 
     def is_installed(self):
         """
@@ -172,44 +174,43 @@ def stop_instance(self):
                 "Failed to stop the Dogtag instance."
                 "See the installation log for details.")
 
-    def enable_client_auth_to_db(self, config):
+    def enable_client_auth_to_db(self):
         """
         Enable client auth connection to the internal db.
-        Path to CS.cfg config file passed in.
         """
 
         with stopped_service('pki-tomcatd', 'pki-tomcat'):
             installutils.set_directive(
-                config,
+                self.config,
                 'authz.instance.DirAclAuthz.ldap.ldapauth.authtype',
                 'SslClientAuth', quotes=False, separator='=')
             installutils.set_directive(
-                config,
+                self.config,
                 'authz.instance.DirAclAuthz.ldap.ldapauth.clientCertNickname',
                 'subsystemCert cert-pki-ca', quotes=False, separator='=')
             installutils.set_directive(
-                config,
+                self.config,
                 'authz.instance.DirAclAuthz.ldap.ldapconn.port', '636',
                 quotes=False, separator='=')
             installutils.set_directive(
-                config,
+                self.config,
                 'authz.instance.DirAclAuthz.ldap.ldapconn.secureConn',
                 'true', quotes=False, separator='=')
 
             installutils.set_directive(
-                config,
+                self.config,
                 'internaldb.ldapauth.authtype',
                 'SslClientAuth', quotes=False, separator='=')
 
             installutils.set_directive(
-                config,
+                self.config,
                 'internaldb.ldapauth.clientCertNickname',
                 'subsystemCert cert-pki-ca', quotes=False, separator='=')
             installutils.set_directive(
-                config,
+                self.config,
                 'internaldb.ldapconn.port', '636', quotes=False, separator='=')
             installutils.set_directive(
-                config,
+                self.config,
                 'internaldb.ldapconn.secureConn', 'true', quotes=False,
                 separator='=')
             # Remove internaldb password as is not needed anymore
@@ -338,8 +339,7 @@ def stop_tracking_certificates(self, stop_certmonger=True):
         if stop_certmonger:
             cmonger.stop()
 
-    @staticmethod
-    def update_cert_cs_cfg(directive, cert, cs_cfg):
+    def update_cert_cs_cfg(self, directive, cert):
         """
         When renewing a Dogtag subsystem certificate the configuration file
         needs to get the new certificate as well.
@@ -351,7 +351,7 @@ def update_cert_cs_cfg(directive, cert, cs_cfg):
 
         with stopped_service('pki-tomcatd', 'pki-tomcat'):
             installutils.set_directive(
-                cs_cfg,
+                self.config,
                 directive,
                 # the cert must be only the base64 string without headers
                 (base64.b64encode(cert.public_bytes(x509.Encoding.DER))
@@ -455,6 +455,10 @@ def teardown_admin(self):
         api.Backend.ldap2.delete_entry(self.admin_dn)
 
     def _use_ldaps_during_spawn(self, config, ds_cacert=paths.IPA_CA_CRT):
+        """
+        config is a RawConfigParser object
+        cs_cacert is path to a PEM CA certificate
+        """
         config.set(self.subsystem, "pki_ds_ldaps_port", "636")
         config.set(self.subsystem, "pki_ds_secure_connection", "True")
         config.set(self.subsystem, "pki_ds_secure_connection_ca_pem_file",
diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
index 3106e35519..77fd11b9ea 100644
--- a/ipaserver/install/kra.py
+++ b/ipaserver/install/kra.py
@@ -125,7 +125,7 @@ def install(api, replica_config, options):
     _service.print_msg("Restarting the directory server")
     ds = dsinstance.DsInstance()
     ds.restart()
-    kra.enable_client_auth_to_db(paths.KRA_CS_CFG_PATH)
+    kra.enable_client_auth_to_db()
 
     # Restart apache for new proxy config file
     services.knownservices.httpd.restart(capture_output=True)
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index 81b67f0d5d..ba5b8896fb 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -71,6 +71,7 @@ def __init__(self, realm):
             realm=realm,
             subsystem="KRA",
             service_desc="KRA server",
+            config=paths.KRA_CS_CFG_PATH,
         )
 
         self.basedn = DN(('o', 'kra'), ('o', 'ipaca'))
@@ -352,8 +353,20 @@ def __apply_updates(self):
                                    sub_dict=sub_dict)
         ld.update([os.path.join(paths.UPDATES_DIR, '40-vault.update')])
 
-    @staticmethod
-    def update_cert_config(nickname, cert):
+    def enable_ephemeral(self):
+        """
+        Enable ephemeral KRA requests to reduce the number of LDAP
+        write operations.
+        """
+        with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'):
+            installutils.set_directive(
+                self.config,
+                'kra.ephemeralRequests',
+                'true', quotes=False, separator='=')
+
+        # A restart is required
+
+    def update_cert_config(self, nickname, cert):
         """
         When renewing a KRA subsystem certificate the configuration file
         needs to get the new certificate as well.
@@ -371,8 +384,8 @@ def update_cert_config(nickname, cert):
             'Server-Cert cert-pki-ca': 'kra.sslserver.cert'}
 
         if nickname in directives:
-            DogtagInstance.update_cert_cs_cfg(
-                directives[nickname], cert, paths.KRA_CS_CFG_PATH)
+            super(KRAInstance, self).update_cert_cs_cfg(
+                directives[nickname], cert)
 
     def __enable_instance(self):
         self.ldap_enable('KRA', self.fqdn, None, self.suffix)

From 26796a7572efe95121cc9fc24a1e1d302e17c159 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Wed, 27 Sep 2017 17:45:38 -0400
Subject: [PATCH 2/2] Enable ephemeral KRA requests

Enabling ephemeral KRA requests will reduce the amount of LDAP
write operations and improve overall performance.

Re-order some imports and shorten some lines to make pep8 happy.

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

Signed-off-by: Rob Crittenden <rcrit...@redhat.com>
---
 ipaserver/install/cainstance.py     | 37 ++++++++++++++++++-----------------
 ipaserver/install/dogtaginstance.py | 10 ++++++++++
 ipaserver/install/krainstance.py    |  1 +
 ipaserver/install/server/upgrade.py | 39 ++++++++++++++++++++++++++-----------
 4 files changed, 58 insertions(+), 29 deletions(-)

diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index ca61c52162..3176742e00 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -396,14 +396,18 @@ def configure_instance(self, host_name, dm_password, admin_password,
                       self.__spawn_instance)
             self.step("exporting Dogtag certificate store pin",
                       self.create_certstore_passwdfile)
-            self.step("stopping certificate server instance to update CS.cfg", self.stop_instance)
-            self.step("backing up CS.cfg", self.backup_config)
+            self.step("stopping certificate server instance to update CS.cfg",
+                      self.stop_instance)
+            self.step("backing up CS.cfg", self.safe_backup_config)
             self.step("disabling nonces", self.__disable_nonce)
             self.step("set up CRL publishing", self.__enable_crl_publish)
-            self.step("enable PKIX certificate path discovery and validation", self.enable_pkix)
+            self.step("enable PKIX certificate path discovery and validation",
+                      self.enable_pkix)
             if promote:
-                self.step("destroying installation admin user", self.teardown_admin)
-            self.step("starting certificate server instance", self.start_instance)
+                self.step("destroying installation admin user",
+                          self.teardown_admin)
+            self.step("starting certificate server instance",
+                      self.start_instance)
         # Step 1 of external is getting a CSR so we don't need to do these
         # steps until we get a cert back from the external CA.
         if self.external != 1:
@@ -641,9 +645,16 @@ def __spawn_instance(self):
 
         logger.debug("completed creating ca instance")
 
-    def backup_config(self):
+    def safe_backup_config(self):
+        """
+        Safely handle exceptions if backup_config fails
+
+        The parent class raises an exception if the configuration
+        cannot be backed up. Catch that and log the message but
+        don't stop the current installer.
+        """
         try:
-            backup_config()
+            super(CAInstance, self).backup_config()
         except Exception as e:
             logger.warning("Failed to backup CS.cfg: %s", e)
 
@@ -1177,7 +1188,7 @@ def update_cert_config(self, nickname, cert):
                       'Server-Cert cert-pki-ca': 'ca.sslserver.cert'}
 
         try:
-            backup_config()
+            self.backup_config()
         except Exception as e:
             syslog.syslog(syslog.LOG_ERR, "Failed to backup CS.cfg: %s" % e)
 
@@ -1353,16 +1364,6 @@ def replica_ca_install_check(config, promote):
         exit('IPA schema missing on master CA directory server')
 
 
-def backup_config():
-    """
-    Create a backup copy of CS.cfg
-    """
-    path = paths.CA_CS_CFG_PATH
-    if services.knownservices['pki_tomcatd'].is_running('pki-tomcat'):
-        raise RuntimeError(
-            "Dogtag must be stopped when creating backup of %s" % path)
-    shutil.copy(path, path + '.ipabkp')
-
 def __update_entry_from_cert(make_filter, make_entry, cert):
     """
     Given a certificate and functions to make a filter based on the
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index eeeae8f0de..add7cbd88e 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -463,3 +463,13 @@ def _use_ldaps_during_spawn(self, config, ds_cacert=paths.IPA_CA_CRT):
         config.set(self.subsystem, "pki_ds_secure_connection", "True")
         config.set(self.subsystem, "pki_ds_secure_connection_ca_pem_file",
                    ds_cacert)
+
+    def backup_config(self):
+        """
+        Create a backup copy of CS.cfg
+        """
+        path = self.config
+        if services.knownservices['pki_tomcatd'].is_running('pki-tomcat'):
+            raise RuntimeError(
+                "Dogtag must be stopped when creating backup of %s" % path)
+        shutil.copy(path, path + '.ipabkp')
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index ba5b8896fb..9fd78ed941 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -121,6 +121,7 @@ def configure_instance(self, realm_name, host_name, dm_password,
         if promote:
             self.step("destroying installation admin user",
                       self.teardown_admin)
+        self.step("enabling ephemeral requests", self.enable_ephemeral)
         self.step("restarting KRA", self.restart_instance)
         self.step("configure certmonger for renewals",
                   self.configure_certmonger_renewal)
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 5c03392192..07cc18a78c 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -11,19 +11,8 @@
 import pwd
 import fileinput
 import sys
-
 from augeas import Augeas
 import dns.exception
-
-import six
-# pylint: disable=import-error
-if six.PY3:
-    # The SafeConfigParser class has been renamed to ConfigParser in Py3
-    from configparser import ConfigParser as SafeConfigParser
-else:
-    from ConfigParser import SafeConfigParser
-# pylint: enable=import-error
-
 from ipalib import api
 from ipalib.install import certmonger, sysrestore
 import SSSDConfig
@@ -44,6 +33,7 @@
 from ipaserver.install import bindinstance
 from ipaserver.install import service
 from ipaserver.install import cainstance
+from ipaserver.install import krainstance
 from ipaserver.install import certs
 from ipaserver.install import otpdinstance
 from ipaserver.install import schemaupdate
@@ -56,6 +46,15 @@
 from ipaserver.install.upgradeinstance import IPAUpgrade
 from ipaserver.install.ldapupdate import BadSyntax
 
+import six
+# pylint: disable=import-error
+if six.PY3:
+    # The SafeConfigParser class has been renamed to ConfigParser in Py3
+    from configparser import ConfigParser as SafeConfigParser
+else:
+    from ConfigParser import SafeConfigParser
+# pylint: enable=import-error
+
 if six.PY3:
     unicode = str
 
@@ -1668,6 +1667,8 @@ def upgrade_configuration():
             api.env.realm, host_name=api.env.host)
     ca_running = ca.is_running()
 
+    kra = krainstance.KRAInstance(api.env.realm)
+
     # create passswd.txt file in PKI_TOMCAT_ALIAS_DIR if it does not exist
     # this file will be required on most actions over this NSS DB in FIPS
     if ca.is_configured() and not os.path.exists(os.path.join(
@@ -1709,11 +1710,27 @@ def upgrade_configuration():
             )
         upgrade_pki(ca, fstore)
 
+        if kra.is_configured():
+            logger.info('[Ensuring ephemeralRequest is enabled in KRA]')
+            kra.backup_config()
+            value = installutils.get_directive(
+                paths.KRA_CS_CFG_PATH,
+                'kra.ephemeralRequests',
+                separator='=')
+            if value is None or value.lower() != 'true':
+                logger.info('Enabling ephemeralRequest')
+                kra.enable_ephemeral()
+            else:
+                logger.info('ephemeralRequest is already enabled')
+
     # several upgrade steps require running CA.  If CA is configured,
     # always run ca.start() because we need to wait until CA is really ready
     # by checking status using http
     if ca.is_configured():
         ca.start('pki-tomcat')
+    if kra.is_configured() and not kra.is_running():
+        # This is for future-proofing in case the KRA is ever standalone.
+        kra.start('pki-tomcat')
 
     certmonger_service = services.knownservices.certmonger
     if ca.is_configured() and not certmonger_service.is_running():
_______________________________________________
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