URL: https://github.com/freeipa/freeipa/pull/1405
Author: tiran
 Title: #1405: Enable ephemeral KRA requests
Action: opened

PR body:
"""
@rcritten's PR #1116 rebased to latest master. I had to create a new PR because 
I don't have permission to fix the merge conflict.

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

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

NOTE: I'm not 100% sure on the upgrade for existing instances. My logic is that 
tomcat is always stopped and then within that block the CA (if any) will be 
updated. Given that the KRA runs in the same service that is why I stuck that 
update code there. It worked in my testing.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1405/head:pr1405
git checkout pr1405
From cfbccedbebff9b7b86c6e729719b998fdfed86bc 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 72bc021ea7..8490175adb 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -336,7 +336,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 e6f5912daf21d3422f7f8ebf4df1ba859a893574 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