pgreco / rpms / ipa

Forked from forks/areguera/rpms/ipa 4 years ago
Clone

Blame SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch

7bbb43
From d3c09a6de06d8ae19d05c0b96cb9c2a5b789b472 Mon Sep 17 00:00:00 2001
7bbb43
From: Christian Heimes <cheimes@redhat.com>
7bbb43
Date: Thu, 7 Jun 2018 18:17:20 +0200
7bbb43
Subject: [PATCH] Use one Custodia peer to retrieve all secrets
7bbb43
7bbb43
Fix 994f71ac8a1bb7ba6bc9caf0f6e4f59af44ad9c4 was incomplete. Under some
7bbb43
circumstancs the DM hash and CA keys were still retrieved from two different
7bbb43
machines.
7bbb43
7bbb43
Custodia client now uses a single remote to upload keys and download all
7bbb43
secrets.
7bbb43
7bbb43
Fixes: https://pagure.io/freeipa/issue/7518
7bbb43
Signed-off-by: Christian Heimes <cheimes@redhat.com>
7bbb43
Reviewed-By: Simo Sorce <ssorce@redhat.com>
7bbb43
---
7bbb43
 ipaserver/install/ca.py                    |  1 -
7bbb43
 ipaserver/install/cainstance.py            |  2 +-
7bbb43
 ipaserver/install/custodiainstance.py      | 74 +++++++++++++++++-------------
7bbb43
 ipaserver/install/kra.py                   |  1 -
7bbb43
 ipaserver/install/server/install.py        |  4 +-
7bbb43
 ipaserver/install/server/replicainstall.py |  2 +-
7bbb43
 6 files changed, 46 insertions(+), 38 deletions(-)
7bbb43
7bbb43
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
7bbb43
index 2ac4382..1c7d375 100644
7bbb43
--- a/ipaserver/install/ca.py
7bbb43
+++ b/ipaserver/install/ca.py
7bbb43
@@ -235,7 +235,6 @@ def install_step_0(standalone, replica_config, options, custodia):
7bbb43
         cafile = os.path.join(replica_config.dir, 'cacert.p12')
7bbb43
         if options.promote:
7bbb43
             custodia.get_ca_keys(
7bbb43
-                replica_config.ca_host_name,
7bbb43
                 cafile,
7bbb43
                 replica_config.dirman_password)
7bbb43
 
7bbb43
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
7bbb43
index eefc30b..cc0dbf3 100644
7bbb43
--- a/ipaserver/install/cainstance.py
7bbb43
+++ b/ipaserver/install/cainstance.py
7bbb43
@@ -712,7 +712,7 @@ class CAInstance(DogtagInstance):
7bbb43
         self.configure_agent_renewal()
7bbb43
 
7bbb43
     def __import_ra_key(self):
7bbb43
-        self._custodia.import_ra_key(self.master_host)
7bbb43
+        self._custodia.import_ra_key()
7bbb43
         self.__set_ra_cert_perms()
7bbb43
 
7bbb43
         self.configure_agent_renewal()
7bbb43
diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
7bbb43
index 262ae58..ada8d03 100644
7bbb43
--- a/ipaserver/install/custodiainstance.py
7bbb43
+++ b/ipaserver/install/custodiainstance.py
7bbb43
@@ -71,41 +71,45 @@ def get_custodia_instance(config, mode):
7bbb43
         if mode == CustodiaModes.CA_PEER:
7bbb43
             # In case we install replica with CA, prefer CA host as source for
7bbb43
             # all Custodia secret material.
7bbb43
-            custodia_master = config.ca_host_name
7bbb43
+            custodia_peer = config.ca_host_name
7bbb43
         elif mode == CustodiaModes.KRA_PEER:
7bbb43
-            custodia_master = config.kra_host_name
7bbb43
+            custodia_peer = config.kra_host_name
7bbb43
         elif mode == CustodiaModes.MASTER_PEER:
7bbb43
-            custodia_master = config.master_host_name
7bbb43
+            custodia_peer = config.master_host_name
7bbb43
         elif mode == CustodiaModes.STANDALONE:
7bbb43
-            custodia_master = None
7bbb43
+            custodia_peer = None
7bbb43
     else:
7bbb43
-        custodia_master = None
7bbb43
+        custodia_peer = None
7bbb43
 
7bbb43
-    if custodia_master is None:
7bbb43
+    if custodia_peer is None:
7bbb43
         # use ldapi with local dirsrv instance
7bbb43
         root_logger.info("Custodia uses LDAPI.")
7bbb43
-        ldap_uri = None
7bbb43
     else:
7bbb43
-        root_logger.info("Custodia uses '%s' as master peer.",
7bbb43
-                         custodia_master)
7bbb43
-        ldap_uri = 'ldap://{}'.format(custodia_master)
7bbb43
+        root_logger.info("Custodia uses '%s' as master peer.", custodia_peer)
7bbb43
 
7bbb43
     return CustodiaInstance(
7bbb43
         host_name=config.host_name,
7bbb43
         realm=config.realm_name,
7bbb43
-        ldap_uri=ldap_uri
7bbb43
+        custodia_peer=custodia_peer
7bbb43
     )
7bbb43
 
7bbb43
 
7bbb43
 class CustodiaInstance(SimpleServiceInstance):
7bbb43
-    def __init__(self, host_name=None, realm=None, ldap_uri=None):
7bbb43
+    def __init__(self, host_name=None, realm=None, custodia_peer=None):
7bbb43
         super(CustodiaInstance, self).__init__("ipa-custodia")
7bbb43
         self.config_file = paths.IPA_CUSTODIA_CONF
7bbb43
         self.server_keys = paths.IPA_CUSTODIA_KEYS
7bbb43
-        self.ldap_uri = ldap_uri
7bbb43
+        self.custodia_peer = custodia_peer
7bbb43
         self.fqdn = host_name
7bbb43
         self.realm = realm
7bbb43
 
7bbb43
+    @property
7bbb43
+    def ldap_uri(self):
7bbb43
+        if self.custodia_peer is None:
7bbb43
+            return installutils.realm_to_ldapi_uri(self.realm)
7bbb43
+        else:
7bbb43
+            return "ldap://{}".format(self.custodia_peer)
7bbb43
+
7bbb43
     def __config_file(self):
7bbb43
         template_file = os.path.basename(self.config_file) + '.template'
7bbb43
         template = os.path.join(paths.USR_SHARE_IPA_DIR, template_file)
7bbb43
@@ -125,7 +129,7 @@ class CustodiaInstance(SimpleServiceInstance):
7bbb43
             ipautil.flush_sync(f)
7bbb43
 
7bbb43
     def create_instance(self):
7bbb43
-        if self.ldap_uri is None or self.ldap_uri.startswith('ldapi://'):
7bbb43
+        if self.ldap_uri.startswith('ldapi://'):
7bbb43
             # local case, ensure container exists
7bbb43
             self.step("Making sure custodia container exists",
7bbb43
                       self.__create_container)
7bbb43
@@ -174,25 +178,24 @@ class CustodiaInstance(SimpleServiceInstance):
7bbb43
         updater = ldapupdate.LDAPUpdate(sub_dict=sub_dict)
7bbb43
         updater.update([os.path.join(paths.UPDATES_DIR, '73-custodia.update')])
7bbb43
 
7bbb43
-    def import_ra_key(self, master_host_name):
7bbb43
-        cli = self._get_custodia_client(server=master_host_name)
7bbb43
+    def import_ra_key(self):
7bbb43
+        cli = self._get_custodia_client()
7bbb43
         # please note that ipaCert part has to stay here for historical
7bbb43
         # reasons (old servers expect you to ask for ra/ipaCert during
7bbb43
         # replication as they store the RA agent cert in an NSS database
7bbb43
         # with this nickname)
7bbb43
         cli.fetch_key('ra/ipaCert')
7bbb43
 
7bbb43
-    def import_dm_password(self, master_host_name):
7bbb43
-        cli = self._get_custodia_client(server=master_host_name)
7bbb43
+    def import_dm_password(self):
7bbb43
+        cli = self._get_custodia_client()
7bbb43
         cli.fetch_key('dm/DMHash')
7bbb43
 
7bbb43
-    def _wait_keys(self, host, timeout=300):
7bbb43
-        ldap_uri = 'ldap://%s' % host
7bbb43
+    def _wait_keys(self, timeout=300):
7bbb43
         deadline = int(time.time()) + timeout
7bbb43
         root_logger.info("Waiting up to %s seconds to see our keys "
7bbb43
-                         "appear on host: %s", timeout, host)
7bbb43
+                         "appear on host %s", timeout, self.ldap_uri)
7bbb43
 
7bbb43
-        konn = KEMLdap(ldap_uri)
7bbb43
+        konn = KEMLdap(self.ldap_uri)
7bbb43
         saved_e = None
7bbb43
         while True:
7bbb43
             try:
7bbb43
@@ -202,8 +205,11 @@ class CustodiaInstance(SimpleServiceInstance):
7bbb43
                 if saved_e is None:
7bbb43
                     # FIXME: Change once there's better way to show this
7bbb43
                     # message in installer output,
7bbb43
-                    print("  Waiting for keys to appear on host: {}, please "
7bbb43
-                          "wait until this has completed.".format(host))
7bbb43
+                    print(
7bbb43
+                        "  Waiting for keys to appear on host: {}, please "
7bbb43
+                        "wait until this has completed.".format(
7bbb43
+                            self.ldap_uri)
7bbb43
+                    )
7bbb43
                 # log only once for the same error
7bbb43
                 if not isinstance(e, type(saved_e)):
7bbb43
                     root_logger.debug(
7bbb43
@@ -213,23 +219,25 @@ class CustodiaInstance(SimpleServiceInstance):
7bbb43
                     raise RuntimeError("Timed out trying to obtain keys.")
7bbb43
                 time.sleep(1)
7bbb43
 
7bbb43
-    def _get_custodia_client(self, server):
7bbb43
+    def _get_custodia_client(self):
7bbb43
+        if self.custodia_peer is None:
7bbb43
+            raise ValueError("Can't replicate secrets without Custodia peer")
7bbb43
         # Before we attempt to fetch keys from this host, make sure our public
7bbb43
         # keys have been replicated there.
7bbb43
-        self._wait_keys(server)
7bbb43
+        self._wait_keys()
7bbb43
 
7bbb43
         return CustodiaClient(
7bbb43
             client_service='host@{}'.format(self.fqdn),
7bbb43
             keyfile=self.server_keys, keytab=paths.KRB5_KEYTAB,
7bbb43
-            server=server, realm=self.realm
7bbb43
+            server=self.custodia_peer, realm=self.realm
7bbb43
         )
7bbb43
 
7bbb43
-    def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
7bbb43
+    def _get_keys(self, cacerts_file, cacerts_pwd, data):
7bbb43
         # Fetch all needed certs one by one, then combine them in a single
7bbb43
         # PKCS12 file
7bbb43
         prefix = data['prefix']
7bbb43
         certlist = data['list']
7bbb43
-        cli = self._get_custodia_client(server=ca_host)
7bbb43
+        cli = self._get_custodia_client()
7bbb43
 
7bbb43
         # Temporary nssdb
7bbb43
         tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
7bbb43
@@ -272,23 +280,23 @@ class CustodiaInstance(SimpleServiceInstance):
7bbb43
         finally:
7bbb43
             shutil.rmtree(tmpnssdir)
7bbb43
 
7bbb43
-    def get_ca_keys(self, ca_host, cacerts_file, cacerts_pwd):
7bbb43
+    def get_ca_keys(self, cacerts_file, cacerts_pwd):
7bbb43
         certlist = ['caSigningCert cert-pki-ca',
7bbb43
                     'ocspSigningCert cert-pki-ca',
7bbb43
                     'auditSigningCert cert-pki-ca',
7bbb43
                     'subsystemCert cert-pki-ca']
7bbb43
         data = {'prefix': 'ca',
7bbb43
                 'list': certlist}
7bbb43
-        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
7bbb43
+        self._get_keys(cacerts_file, cacerts_pwd, data)
7bbb43
 
7bbb43
-    def get_kra_keys(self, ca_host, cacerts_file, cacerts_pwd):
7bbb43
+    def get_kra_keys(self, cacerts_file, cacerts_pwd):
7bbb43
         certlist = ['auditSigningCert cert-pki-kra',
7bbb43
                     'storageCert cert-pki-kra',
7bbb43
                     'subsystemCert cert-pki-ca',
7bbb43
                     'transportCert cert-pki-kra']
7bbb43
         data = {'prefix': 'ca',
7bbb43
                 'list': certlist}
7bbb43
-        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
7bbb43
+        self._get_keys(cacerts_file, cacerts_pwd, data)
7bbb43
 
7bbb43
     def __start(self):
7bbb43
         super(CustodiaInstance, self).__start()
7bbb43
diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
7bbb43
index 3333970..d8773b9 100644
7bbb43
--- a/ipaserver/install/kra.py
7bbb43
+++ b/ipaserver/install/kra.py
7bbb43
@@ -91,7 +91,6 @@ def install(api, replica_config, options, custodia):
7bbb43
                     paths.KRB5_KEYTAB,
7bbb43
                     ccache)
7bbb43
                 custodia.get_kra_keys(
7bbb43
-                    replica_config.kra_host_name,
7bbb43
                     krafile,
7bbb43
                     replica_config.dirman_password)
7bbb43
         else:
7bbb43
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
7bbb43
index f4338ed..3651cde 100644
7bbb43
--- a/ipaserver/install/server/install.py
7bbb43
+++ b/ipaserver/install/server/install.py
7bbb43
@@ -1085,7 +1085,9 @@ def uninstall(installer):
7bbb43
     dsinstance.DsInstance(fstore=fstore).uninstall()
7bbb43
     if _server_trust_ad_installed:
7bbb43
         adtrustinstance.ADTRUSTInstance(fstore).uninstall()
7bbb43
-    custodiainstance.CustodiaInstance().uninstall()
7bbb43
+    # realm isn't used, but IPAKEMKeys parses /etc/ipa/default.conf
7bbb43
+    # otherwise, see https://pagure.io/freeipa/issue/7474 .
7bbb43
+    custodiainstance.CustodiaInstance(realm='REALM.INVALID').uninstall()
7bbb43
     otpdinstance.OtpdInstance().uninstall()
7bbb43
     tasks.restore_hostname(fstore, sstore)
7bbb43
     fstore.restore_all_files()
7bbb43
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
7bbb43
index ef61590..b9cd518 100644
7bbb43
--- a/ipaserver/install/server/replicainstall.py
7bbb43
+++ b/ipaserver/install/server/replicainstall.py
7bbb43
@@ -1512,7 +1512,7 @@ def install(installer):
7bbb43
     krb.restart()
7bbb43
 
7bbb43
     if promote:
7bbb43
-        custodia.import_dm_password(config.master_host_name)
7bbb43
+        custodia.import_dm_password()
7bbb43
         promote_sssd(config.host_name)
7bbb43
         promote_openldap_conf(config.host_name, config.master_host_name)
7bbb43
 
7bbb43
-- 
7bbb43
2.9.3
7bbb43