2f4199
From 11e597217fe6f1dcee3a918eef0bc3a0d2928e6d Mon Sep 17 00:00:00 2001
2f4199
From: Christian Heimes <cheimes@redhat.com>
2f4199
Date: Thu, 26 Apr 2018 12:06:36 +0200
2f4199
Subject: [PATCH] Use single Custodia instance in installers
2f4199
2f4199
Installers now pass a single CustodiaInstance object around, instead of
2f4199
creating new instances on demand. In case of replica promotion with CA,
2f4199
the instance gets all secrets from a master with CA present. Before, an
2f4199
installer created multiple instances and may have requested CA key
2f4199
material from a different machine than DM password hash.
2f4199
2f4199
In case of Domain Level 1 and replica promotion, the CustodiaInstance no
2f4199
longer adds the keys to the local instance and waits for replication to
2f4199
other replica. Instead the installer directly uploads the new public
2f4199
keys to the remote 389-DS instance.
2f4199
2f4199
Without promotion, new Custodia public keys are still added to local
2f4199
389-DS over LDAPI.
2f4199
2f4199
Fixes: https://pagure.io/freeipa/issue/7518
2f4199
Signed-off-by: Christian Heimes <cheimes@redhat.com>
2f4199
Reviewed-By: Simo Sorce <ssorce@redhat.com>
2f4199
Reviewed-By: Simo Sorce <ssorce@redhat.com>
2f4199
---
2f4199
 install/tools/ipa-ca-install               |  13 ++-
2f4199
 ipaserver/install/ca.py                    |  26 +++--
2f4199
 ipaserver/install/cainstance.py            |   9 +-
2f4199
 ipaserver/install/custodiainstance.py      | 150 ++++++++++++++++++++++-------
2f4199
 ipaserver/install/ipa_kra_install.py       |  10 +-
2f4199
 ipaserver/install/kra.py                   |   6 +-
2f4199
 ipaserver/install/server/install.py        |  14 +--
2f4199
 ipaserver/install/server/replicainstall.py |  15 +--
2f4199
 8 files changed, 165 insertions(+), 78 deletions(-)
2f4199
2f4199
diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
2f4199
index f84b4749a3e2a80aca002a2aa057b200e6187f18..a3694007e5815d1c44f642057c749879d336dfc5 100755
2f4199
--- a/install/tools/ipa-ca-install
2f4199
+++ b/install/tools/ipa-ca-install
2f4199
@@ -31,6 +31,7 @@ from ipaserver.install.installutils import create_replica_config
2f4199
 from ipaserver.install.installutils import check_creds, ReplicaConfig
2f4199
 from ipaserver.install import dsinstance, ca
2f4199
 from ipaserver.install import cainstance, service
2f4199
+from ipaserver.install import custodiainstance
2f4199
 from ipapython import version
2f4199
 from ipalib import api
2f4199
 from ipalib.constants import DOMAIN_LEVEL_0
2f4199
@@ -193,13 +194,17 @@ def install_replica(safe_options, options, filename):
2f4199
     options.domain_name = config.domain_name
2f4199
     options.dm_password = config.dirman_password
2f4199
     options.host_name = config.host_name
2f4199
+    options.ca_host_name = config.ca_host_name
2f4199
     if os.path.exists(cafile):
2f4199
         options.ca_cert_file = cafile
2f4199
     else:
2f4199
         options.ca_cert_file = None
2f4199
 
2f4199
     ca.install_check(True, config, options)
2f4199
-    ca.install(True, config, options)
2f4199
+
2f4199
+    custodia = custodiainstance.get_custodia_instance(
2f4199
+        options, custodiainstance.CustodiaModes.CA_PEER)
2f4199
+    ca.install(True, config, options, custodia=custodia)
2f4199
 
2f4199
 
2f4199
 def install_master(safe_options, options):
2f4199
@@ -228,7 +233,11 @@ def install_master(safe_options, options):
2f4199
         sys.exit("CA subject: {}".format(e.message))
2f4199
 
2f4199
     ca.install_check(True, None, options)
2f4199
-    ca.install(True, None, options)
2f4199
+
2f4199
+    # No CA peer available yet.
2f4199
+    custodia = custodiainstance.get_custodia_instance(
2f4199
+        options, custodiainstance.CustodiaModes.STANDALONE)
2f4199
+    ca.install(True, None, options, custodia=custodia)
2f4199
 
2f4199
 
2f4199
 def install(safe_options, options, filename):
2f4199
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
2f4199
index 52cb20f1cb3612394544a6a41f10e9e939bc0657..2ac4382ccd24d217832950b94baddd113f7a8930 100644
2f4199
--- a/ipaserver/install/ca.py
2f4199
+++ b/ipaserver/install/ca.py
2f4199
@@ -19,10 +19,7 @@ from ipalib.install.service import enroll_only, master_install_only, replica_ins
2f4199
 from ipaserver.install import sysupgrade
2f4199
 from ipapython.install import typing
2f4199
 from ipapython.install.core import group, knob, extend_knob
2f4199
-from ipaserver.install import (cainstance,
2f4199
-                               custodiainstance,
2f4199
-                               dsinstance,
2f4199
-                               bindinstance)
2f4199
+from ipaserver.install import cainstance, bindinstance, dsinstance
2f4199
 from ipapython import ipautil, certdb
2f4199
 from ipapython.admintool import ScriptError
2f4199
 from ipaplatform import services
2f4199
@@ -201,12 +198,12 @@ def install_check(standalone, replica_config, options):
2f4199
                         "cannot continue." % (subject, db.secdir))
2f4199
 
2f4199
 
2f4199
-def install(standalone, replica_config, options):
2f4199
-    install_step_0(standalone, replica_config, options)
2f4199
-    install_step_1(standalone, replica_config, options)
2f4199
+def install(standalone, replica_config, options, custodia):
2f4199
+    install_step_0(standalone, replica_config, options, custodia=custodia)
2f4199
+    install_step_1(standalone, replica_config, options, custodia=custodia)
2f4199
 
2f4199
 
2f4199
-def install_step_0(standalone, replica_config, options):
2f4199
+def install_step_0(standalone, replica_config, options, custodia):
2f4199
     realm_name = options.realm_name
2f4199
     dm_password = options.dm_password
2f4199
     host_name = options.host_name
2f4199
@@ -237,9 +234,6 @@ def install_step_0(standalone, replica_config, options):
2f4199
     else:
2f4199
         cafile = os.path.join(replica_config.dir, 'cacert.p12')
2f4199
         if options.promote:
2f4199
-            custodia = custodiainstance.CustodiaInstance(
2f4199
-                replica_config.host_name,
2f4199
-                replica_config.realm_name)
2f4199
             custodia.get_ca_keys(
2f4199
                 replica_config.ca_host_name,
2f4199
                 cafile,
2f4199
@@ -266,7 +260,9 @@ def install_step_0(standalone, replica_config, options):
2f4199
         'certmap.conf', 'subject_base', str(subject_base))
2f4199
     dsinstance.write_certmap_conf(realm_name, ca_subject)
2f4199
 
2f4199
-    ca = cainstance.CAInstance(realm_name, host_name=host_name)
2f4199
+    ca = cainstance.CAInstance(
2f4199
+        realm=realm_name, host_name=host_name, custodia=custodia
2f4199
+    )
2f4199
     ca.configure_instance(host_name, dm_password, dm_password,
2f4199
                           subject_base=subject_base,
2f4199
                           ca_subject=ca_subject,
2f4199
@@ -284,7 +280,7 @@ def install_step_0(standalone, replica_config, options):
2f4199
                           use_ldaps=standalone)
2f4199
 
2f4199
 
2f4199
-def install_step_1(standalone, replica_config, options):
2f4199
+def install_step_1(standalone, replica_config, options, custodia):
2f4199
     if replica_config is not None and not replica_config.setup_ca:
2f4199
         return
2f4199
 
2f4199
@@ -293,7 +289,9 @@ def install_step_1(standalone, replica_config, options):
2f4199
     subject_base = options._subject_base
2f4199
     basedn = ipautil.realm_to_suffix(realm_name)
2f4199
 
2f4199
-    ca = cainstance.CAInstance(realm_name, host_name=host_name)
2f4199
+    ca = cainstance.CAInstance(
2f4199
+        realm=realm_name, host_name=host_name, custodia=custodia
2f4199
+    )
2f4199
 
2f4199
     ca.stop('pki-tomcat')
2f4199
 
2f4199
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
2f4199
index 20635eae22268ff72de73b8b9c430050114bb45b..eefc30b6e01dcf744703b8607cbe169fbec5d859 100644
2f4199
--- a/ipaserver/install/cainstance.py
2f4199
+++ b/ipaserver/install/cainstance.py
2f4199
@@ -59,7 +59,6 @@ from ipapython.ipa_log_manager import log_mgr,\
2f4199
 from ipaserver.secrets.kem import IPAKEMKeys
2f4199
 
2f4199
 from ipaserver.install import certs
2f4199
-from ipaserver.install import custodiainstance
2f4199
 from ipaserver.install import dsinstance
2f4199
 from ipaserver.install import installutils
2f4199
 from ipaserver.install import ldapupdate
2f4199
@@ -285,7 +284,7 @@ class CAInstance(DogtagInstance):
2f4199
                      'caSigningCert cert-pki-ca')
2f4199
     server_cert_name = 'Server-Cert cert-pki-ca'
2f4199
 
2f4199
-    def __init__(self, realm=None, host_name=None):
2f4199
+    def __init__(self, realm=None, host_name=None, custodia=None):
2f4199
         super(CAInstance, self).__init__(
2f4199
             realm=realm,
2f4199
             subsystem="CA",
2f4199
@@ -310,6 +309,8 @@ class CAInstance(DogtagInstance):
2f4199
         self.no_db_setup = False
2f4199
         self.keytab = os.path.join(
2f4199
             paths.PKI_TOMCAT, self.service_prefix + '.keytab')
2f4199
+        # Custodia instance for RA key retrieval
2f4199
+        self._custodia = custodia
2f4199
 
2f4199
     def configure_instance(self, host_name, dm_password, admin_password,
2f4199
                            pkcs12_info=None, master_host=None, csr_file=None,
2f4199
@@ -711,9 +712,7 @@ class CAInstance(DogtagInstance):
2f4199
         self.configure_agent_renewal()
2f4199
 
2f4199
     def __import_ra_key(self):
2f4199
-        custodia = custodiainstance.CustodiaInstance(host_name=self.fqdn,
2f4199
-                                                     realm=self.realm)
2f4199
-        custodia.import_ra_key(self.master_host)
2f4199
+        self._custodia.import_ra_key(self.master_host)
2f4199
         self.__set_ra_cert_perms()
2f4199
 
2f4199
         self.configure_agent_renewal()
2f4199
diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
2f4199
index 0a90bb3954486b9773e3553e9981d2a8d0d4e44a..262ae5857c64719ff5cebde31b4b107e1245d458 100644
2f4199
--- a/ipaserver/install/custodiainstance.py
2f4199
+++ b/ipaserver/install/custodiainstance.py
2f4199
@@ -1,5 +1,9 @@
2f4199
 # Copyright (C) 2015 FreeIPa Project Contributors, see 'COPYING' for license.
2f4199
 
2f4199
+from __future__ import print_function, absolute_import
2f4199
+
2f4199
+import enum
2f4199
+
2f4199
 from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap
2f4199
 from ipaserver.secrets.client import CustodiaClient
2f4199
 from ipaplatform.paths import paths
2f4199
@@ -21,12 +25,84 @@ import time
2f4199
 import pwd
2f4199
 
2f4199
 
2f4199
+class CustodiaModes(enum.Enum):
2f4199
+    # peer must have a CA
2f4199
+    CA_PEER = 'Custodia CA peer'
2f4199
+    # peer must have a CA, KRA preferred
2f4199
+    KRA_PEER = 'Custodia KRA peer'
2f4199
+    # any master will do
2f4199
+    MASTER_PEER = 'Custodia master peer'
2f4199
+    # standalone / local instance
2f4199
+    STANDALONE = 'Custodia standalone'
2f4199
+
2f4199
+
2f4199
+def get_custodia_instance(config, mode):
2f4199
+    """Create Custodia instance
2f4199
+
2f4199
+    :param config: configuration/installer object
2f4199
+    :param mode: CustodiaModes member
2f4199
+    :return: CustodiaInstance object
2f4199
+
2f4199
+    The config object must have the following attribute
2f4199
+
2f4199
+    *host_name*
2f4199
+      FQDN of the new replica/master
2f4199
+    *realm_name*
2f4199
+      Kerberos realm
2f4199
+    *promote*
2f4199
+      True, when instance will be promoted from client to replica
2f4199
+    *master_host_name* (for *CustodiaModes.MASTER_PEER*)
2f4199
+      hostname of a master (may not have a CA)
2f4199
+    *ca_host_name* (for *CustodiaModes.CA_PEER*)
2f4199
+      hostname of a master with CA
2f4199
+    *kra_host_name* (for *CustodiaModes.KRA_PEER*)
2f4199
+      hostname of a master with KRA or CA
2f4199
+
2f4199
+    For promotion, the instance will upload new keys and retrieve secrets
2f4199
+    from the same host. Therefore it uses *ca_host_name* instead of
2f4199
+    *master_host_name* to create a replica with CA.
2f4199
+    """
2f4199
+    assert isinstance(mode, CustodiaModes)
2f4199
+    root_logger.info(
2f4199
+        "Custodia client for '%r' with promotion %s.",
2f4199
+        mode, 'yes' if config.promote else 'no'
2f4199
+    )
2f4199
+    if config.promote:
2f4199
+        if mode == CustodiaModes.CA_PEER:
2f4199
+            # In case we install replica with CA, prefer CA host as source for
2f4199
+            # all Custodia secret material.
2f4199
+            custodia_master = config.ca_host_name
2f4199
+        elif mode == CustodiaModes.KRA_PEER:
2f4199
+            custodia_master = config.kra_host_name
2f4199
+        elif mode == CustodiaModes.MASTER_PEER:
2f4199
+            custodia_master = config.master_host_name
2f4199
+        elif mode == CustodiaModes.STANDALONE:
2f4199
+            custodia_master = None
2f4199
+    else:
2f4199
+        custodia_master = None
2f4199
+
2f4199
+    if custodia_master is None:
2f4199
+        # use ldapi with local dirsrv instance
2f4199
+        root_logger.info("Custodia uses LDAPI.")
2f4199
+        ldap_uri = None
2f4199
+    else:
2f4199
+        root_logger.info("Custodia uses '%s' as master peer.",
2f4199
+                         custodia_master)
2f4199
+        ldap_uri = 'ldap://{}'.format(custodia_master)
2f4199
+
2f4199
+    return CustodiaInstance(
2f4199
+        host_name=config.host_name,
2f4199
+        realm=config.realm_name,
2f4199
+        ldap_uri=ldap_uri
2f4199
+    )
2f4199
+
2f4199
+
2f4199
 class CustodiaInstance(SimpleServiceInstance):
2f4199
-    def __init__(self, host_name=None, realm=None):
2f4199
+    def __init__(self, host_name=None, realm=None, ldap_uri=None):
2f4199
         super(CustodiaInstance, self).__init__("ipa-custodia")
2f4199
         self.config_file = paths.IPA_CUSTODIA_CONF
2f4199
         self.server_keys = paths.IPA_CUSTODIA_KEYS
2f4199
-        self.ldap_uri = None
2f4199
+        self.ldap_uri = ldap_uri
2f4199
         self.fqdn = host_name
2f4199
         self.realm = realm
2f4199
 
2f4199
@@ -49,14 +125,19 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
             ipautil.flush_sync(f)
2f4199
 
2f4199
     def create_instance(self):
2f4199
-        suffix = ipautil.realm_to_suffix(self.realm)
2f4199
+        if self.ldap_uri is None or self.ldap_uri.startswith('ldapi://'):
2f4199
+            # local case, ensure container exists
2f4199
+            self.step("Making sure custodia container exists",
2f4199
+                      self.__create_container)
2f4199
+
2f4199
         self.step("Generating ipa-custodia config file", self.__config_file)
2f4199
-        self.step("Making sure custodia container exists", self.__create_container)
2f4199
         self.step("Generating ipa-custodia keys", self.__gen_keys)
2f4199
-        super(CustodiaInstance, self).create_instance(gensvc_name='KEYS',
2f4199
-                                                      fqdn=self.fqdn,
2f4199
-                                                      ldap_suffix=suffix,
2f4199
-                                                      realm=self.realm)
2f4199
+        super(CustodiaInstance, self).create_instance(
2f4199
+            gensvc_name='KEYS',
2f4199
+            fqdn=self.fqdn,
2f4199
+            ldap_suffix=ipautil.realm_to_suffix(self.realm),
2f4199
+            realm=self.realm
2f4199
+        )
2f4199
         sysupgrade.set_upgrade_state('custodia', 'installed', True)
2f4199
 
2f4199
     def __gen_keys(self):
2f4199
@@ -81,18 +162,6 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
             root_logger.info("Secure server.keys mode")
2f4199
             os.chmod(self.server_keys, 0o600)
2f4199
 
2f4199
-    def create_replica(self, master_host_name):
2f4199
-        suffix = ipautil.realm_to_suffix(self.realm)
2f4199
-        self.ldap_uri = 'ldap://%s' % master_host_name
2f4199
-        self.master_host_name = master_host_name
2f4199
-
2f4199
-        self.step("Generating ipa-custodia config file", self.__config_file)
2f4199
-        self.step("Generating ipa-custodia keys", self.__gen_keys)
2f4199
-        super(CustodiaInstance, self).create_instance(gensvc_name='KEYS',
2f4199
-                                                      fqdn=self.fqdn,
2f4199
-                                                      ldap_suffix=suffix,
2f4199
-                                                      realm=self.realm)
2f4199
-
2f4199
     def __create_container(self):
2f4199
         """
2f4199
         Runs the custodia update file to ensure custodia container is present.
2f4199
@@ -106,7 +175,7 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
         updater.update([os.path.join(paths.UPDATES_DIR, '73-custodia.update')])
2f4199
 
2f4199
     def import_ra_key(self, master_host_name):
2f4199
-        cli = self.__CustodiaClient(server=master_host_name)
2f4199
+        cli = self._get_custodia_client(server=master_host_name)
2f4199
         # please note that ipaCert part has to stay here for historical
2f4199
         # reasons (old servers expect you to ask for ra/ipaCert during
2f4199
         # replication as they store the RA agent cert in an NSS database
2f4199
@@ -114,14 +183,14 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
         cli.fetch_key('ra/ipaCert')
2f4199
 
2f4199
     def import_dm_password(self, master_host_name):
2f4199
-        cli = self.__CustodiaClient(server=master_host_name)
2f4199
+        cli = self._get_custodia_client(server=master_host_name)
2f4199
         cli.fetch_key('dm/DMHash')
2f4199
 
2f4199
-    def __wait_keys(self, host, timeout=300):
2f4199
+    def _wait_keys(self, host, timeout=300):
2f4199
         ldap_uri = 'ldap://%s' % host
2f4199
         deadline = int(time.time()) + timeout
2f4199
-        root_logger.info("Waiting up to {} seconds to see our keys "
2f4199
-                         "appear on host: {}".format(timeout, host))
2f4199
+        root_logger.info("Waiting up to %s seconds to see our keys "
2f4199
+                         "appear on host: %s", timeout, host)
2f4199
 
2f4199
         konn = KEMLdap(ldap_uri)
2f4199
         saved_e = None
2f4199
@@ -129,6 +198,12 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
             try:
2f4199
                 return konn.check_host_keys(self.fqdn)
2f4199
             except Exception as e:
2f4199
+                # Print message to console only once for first error.
2f4199
+                if saved_e is None:
2f4199
+                    # FIXME: Change once there's better way to show this
2f4199
+                    # message in installer output,
2f4199
+                    print("  Waiting for keys to appear on host: {}, please "
2f4199
+                          "wait until this has completed.".format(host))
2f4199
                 # log only once for the same error
2f4199
                 if not isinstance(e, type(saved_e)):
2f4199
                     root_logger.debug(
2f4199
@@ -138,22 +213,23 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
                     raise RuntimeError("Timed out trying to obtain keys.")
2f4199
                 time.sleep(1)
2f4199
 
2f4199
-    def __CustodiaClient(self, server):
2f4199
+    def _get_custodia_client(self, server):
2f4199
         # Before we attempt to fetch keys from this host, make sure our public
2f4199
         # keys have been replicated there.
2f4199
-        self.__wait_keys(server)
2f4199
-
2f4199
-        return CustodiaClient('host@%s' % self.fqdn, self.server_keys,
2f4199
-                              paths.KRB5_KEYTAB, server, realm=self.realm)
2f4199
+        self._wait_keys(server)
2f4199
 
2f4199
-    def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
2f4199
-        # Fecth all needed certs one by one, then combine them in a single
2f4199
-        # p12 file
2f4199
+        return CustodiaClient(
2f4199
+            client_service='host@{}'.format(self.fqdn),
2f4199
+            keyfile=self.server_keys, keytab=paths.KRB5_KEYTAB,
2f4199
+            server=server, realm=self.realm
2f4199
+        )
2f4199
 
2f4199
+    def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
2f4199
+        # Fetch all needed certs one by one, then combine them in a single
2f4199
+        # PKCS12 file
2f4199
         prefix = data['prefix']
2f4199
         certlist = data['list']
2f4199
-
2f4199
-        cli = self.__CustodiaClient(server=ca_host)
2f4199
+        cli = self._get_custodia_client(server=ca_host)
2f4199
 
2f4199
         # Temporary nssdb
2f4199
         tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
2f4199
@@ -203,7 +279,7 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
                     'subsystemCert cert-pki-ca']
2f4199
         data = {'prefix': 'ca',
2f4199
                 'list': certlist}
2f4199
-        self.__get_keys(ca_host, cacerts_file, cacerts_pwd, data)
2f4199
+        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
2f4199
 
2f4199
     def get_kra_keys(self, ca_host, cacerts_file, cacerts_pwd):
2f4199
         certlist = ['auditSigningCert cert-pki-kra',
2f4199
@@ -212,7 +288,7 @@ class CustodiaInstance(SimpleServiceInstance):
2f4199
                     'transportCert cert-pki-kra']
2f4199
         data = {'prefix': 'ca',
2f4199
                 'list': certlist}
2f4199
-        self.__get_keys(ca_host, cacerts_file, cacerts_pwd, data)
2f4199
+        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
2f4199
 
2f4199
     def __start(self):
2f4199
         super(CustodiaInstance, self).__start()
2f4199
diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py
2f4199
index 3e08f4da94651b49876e1427daddbd957f0027ae..9ebabe057513141ee76d238a3f20e76a27dd932e 100644
2f4199
--- a/ipaserver/install/ipa_kra_install.py
2f4199
+++ b/ipaserver/install/ipa_kra_install.py
2f4199
@@ -32,6 +32,7 @@ from ipapython import admintool
2f4199
 from ipapython import ipautil
2f4199
 from ipaserver.install import service
2f4199
 from ipaserver.install import cainstance
2f4199
+from ipaserver.install import custodiainstance
2f4199
 from ipaserver.install import krainstance
2f4199
 from ipaserver.install import dsinstance
2f4199
 from ipaserver.install import installutils
2f4199
@@ -176,7 +177,6 @@ class KRAInstaller(KRAInstall):
2f4199
 
2f4199
         api.Backend.ldap2.connect()
2f4199
 
2f4199
-        config = None
2f4199
         if self.installing_replica:
2f4199
             if self.options.promote:
2f4199
                 config = ReplicaConfig()
2f4199
@@ -196,6 +196,7 @@ class KRAInstaller(KRAInstall):
2f4199
                 config.kra_host_name = config.master_host_name
2f4199
 
2f4199
             config.setup_kra = True
2f4199
+            config.promote = self.options.promote
2f4199
 
2f4199
             if config.subject_base is None:
2f4199
                 attrs = api.Backend.ldap2.get_ipa_config()
2f4199
@@ -204,6 +205,11 @@ class KRAInstaller(KRAInstall):
2f4199
             if config.kra_host_name is None:
2f4199
                 config.kra_host_name = service.find_providing_server(
2f4199
                     'KRA', api.Backend.ldap2, api.env.ca_host)
2f4199
+            custodia = custodiainstance.get_custodia_instance(
2f4199
+                config, custodiainstance.CustodiaModes.KRA_PEER)
2f4199
+        else:
2f4199
+            config = None
2f4199
+            custodia = None
2f4199
 
2f4199
         try:
2f4199
             kra.install_check(api, config, self.options)
2f4199
@@ -213,7 +219,7 @@ class KRAInstaller(KRAInstall):
2f4199
         print(dedent(self.INSTALLER_START_MESSAGE))
2f4199
 
2f4199
         try:
2f4199
-            kra.install(api, config, self.options)
2f4199
+            kra.install(api, config, self.options, custodia=custodia)
2f4199
         except:
2f4199
             self.log.error(dedent(self.FAIL_MESSAGE))
2f4199
             raise
2f4199
diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
2f4199
index 3545b301a977f4b7e7801ca1ef87d594bb3ba54f..3333970e8af9e36d6b7614286cc1e774f6eb9b25 100644
2f4199
--- a/ipaserver/install/kra.py
2f4199
+++ b/ipaserver/install/kra.py
2f4199
@@ -16,7 +16,6 @@ from ipaplatform.paths import paths
2f4199
 from ipapython import certdb
2f4199
 from ipapython import ipautil
2f4199
 from ipapython.install.core import group
2f4199
-from ipaserver.install import custodiainstance
2f4199
 from ipaserver.install import cainstance
2f4199
 from ipaserver.install import krainstance
2f4199
 from ipaserver.install import dsinstance
2f4199
@@ -68,7 +67,7 @@ def install_check(api, replica_config, options):
2f4199
                                    "new replica file.")
2f4199
 
2f4199
 
2f4199
-def install(api, replica_config, options):
2f4199
+def install(api, replica_config, options, custodia):
2f4199
     if replica_config is None:
2f4199
         if not options.setup_kra:
2f4199
             return
2f4199
@@ -91,9 +90,6 @@ def install(api, replica_config, options):
2f4199
                     'host/{env.host}@{env.realm}'.format(env=api.env),
2f4199
                     paths.KRB5_KEYTAB,
2f4199
                     ccache)
2f4199
-                custodia = custodiainstance.CustodiaInstance(
2f4199
-                    replica_config.host_name,
2f4199
-                    replica_config.realm_name)
2f4199
                 custodia.get_kra_keys(
2f4199
                     replica_config.kra_host_name,
2f4199
                     krafile,
2f4199
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
2f4199
index 422474fa915b4876530f304ef9424f6b31cf26cc..f4338ed0428f7f44decd004f6a183258bef7f795 100644
2f4199
--- a/ipaserver/install/server/install.py
2f4199
+++ b/ipaserver/install/server/install.py
2f4199
@@ -709,6 +709,7 @@ def install(installer):
2f4199
     host_name = options.host_name
2f4199
     ip_addresses = options.ip_addresses
2f4199
     setup_ca = options.setup_ca
2f4199
+    options.promote = False  # first master, no promotion
2f4199
 
2f4199
     # Installation has started. No IPA sysrestore items are restored in case of
2f4199
     # failure to enable root cause investigation
2f4199
@@ -789,6 +790,10 @@ def install(installer):
2f4199
                       setup_pkinit=not options.no_pkinit,
2f4199
                       subject_base=options.subject_base)
2f4199
 
2f4199
+    custodia = custodiainstance.get_custodia_instance(
2f4199
+        options, custodiainstance.CustodiaModes.MASTER_PEER)
2f4199
+    custodia.create_instance()
2f4199
+
2f4199
     if setup_ca:
2f4199
         if not options.external_cert_files and options.external_ca:
2f4199
             # stage 1 of external CA installation
2f4199
@@ -803,7 +808,7 @@ def install(installer):
2f4199
                           if n in options.__dict__}
2f4199
             write_cache(cache_vars)
2f4199
 
2f4199
-        ca.install_step_0(False, None, options)
2f4199
+        ca.install_step_0(False, None, options, custodia=custodia)
2f4199
     else:
2f4199
         # Put the CA cert where other instances expect it
2f4199
         x509.write_certificate(http_ca_cert, paths.IPA_CA_CRT)
2f4199
@@ -823,15 +828,12 @@ def install(installer):
2f4199
     ds.enable_ssl()
2f4199
 
2f4199
     if setup_ca:
2f4199
-        ca.install_step_1(False, None, options)
2f4199
+        ca.install_step_1(False, None, options, custodia=custodia)
2f4199
 
2f4199
     otpd = otpdinstance.OtpdInstance()
2f4199
     otpd.create_instance('OTPD', host_name,
2f4199
                          ipautil.realm_to_suffix(realm_name))
2f4199
 
2f4199
-    custodia = custodiainstance.CustodiaInstance(host_name, realm_name)
2f4199
-    custodia.create_instance()
2f4199
-
2f4199
     # Create a HTTP instance
2f4199
     http = httpinstance.HTTPInstance(fstore)
2f4199
     if options.http_cert_files:
2f4199
@@ -863,7 +865,7 @@ def install(installer):
2f4199
     krb.restart()
2f4199
 
2f4199
     if options.setup_kra:
2f4199
-        kra.install(api, None, options)
2f4199
+        kra.install(api, None, options, custodia=custodia)
2f4199
 
2f4199
     if options.setup_dns:
2f4199
         dns.install(False, False, options)
2f4199
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
2f4199
index 42e4615ad2dc1f604f5d8d14f8e57e3e4674bcb9..2ecc0abe0c5918cf5aefccc1bd6f09e70503baab 100644
2f4199
--- a/ipaserver/install/server/replicainstall.py
2f4199
+++ b/ipaserver/install/server/replicainstall.py
2f4199
@@ -1357,6 +1357,7 @@ def install(installer):
2f4199
     fstore = installer._fstore
2f4199
     sstore = installer._sstore
2f4199
     config = installer._config
2f4199
+    config.promote = installer.promote
2f4199
     promote = installer.promote
2f4199
     cafile = installer._ca_file
2f4199
     dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
2f4199
@@ -1483,19 +1484,19 @@ def install(installer):
2f4199
     otpd.create_instance('OTPD', config.host_name,
2f4199
                          ipautil.realm_to_suffix(config.realm_name))
2f4199
 
2f4199
-    custodia = custodiainstance.CustodiaInstance(config.host_name,
2f4199
-                                                 config.realm_name)
2f4199
-    if promote:
2f4199
-        custodia.create_replica(config.master_host_name)
2f4199
+    if ca_enabled:
2f4199
+        mode = custodiainstance.CustodiaModes.CA_PEER
2f4199
     else:
2f4199
-        custodia.create_instance()
2f4199
+        mode = custodiainstance.CustodiaModes.MASTER_PEER
2f4199
+    custodia = custodiainstance.get_custodia_instance(config, mode)
2f4199
+    custodia.create_instance()
2f4199
 
2f4199
     if ca_enabled:
2f4199
         options.realm_name = config.realm_name
2f4199
         options.domain_name = config.domain_name
2f4199
         options.host_name = config.host_name
2f4199
         options.dm_password = config.dirman_password
2f4199
-        ca.install(False, config, options)
2f4199
+        ca.install(False, config, options, custodia=custodia)
2f4199
 
2f4199
     # configure PKINIT now that all required services are in place
2f4199
     krb.enable_ssl()
2f4199
@@ -1505,7 +1506,7 @@ def install(installer):
2f4199
     ds.apply_updates()
2f4199
 
2f4199
     if kra_enabled:
2f4199
-        kra.install(api, config, options)
2f4199
+        kra.install(api, config, options, custodia=custodia)
2f4199
 
2f4199
     service.print_msg("Restarting the KDC")
2f4199
     krb.restart()
2f4199
-- 
2f4199
2.14.3
2f4199