diff --git a/SOURCES/0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch b/SOURCES/0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch
new file mode 100644
index 0000000..7dea73f
--- /dev/null
+++ b/SOURCES/0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch
@@ -0,0 +1,107 @@
+From 7076fd22e744fd51dbcc0c4e4a4089884a3dae48 Mon Sep 17 00:00:00 2001
+From: Christian Heimes <cheimes@redhat.com>
+Date: Wed, 11 Apr 2018 13:34:41 +0200
+Subject: [PATCH] Add nsds5ReplicaReleaseTimeout to replica config
+
+The nsds5ReplicaReleaseTimeout setting prevents the monopolization of
+replicas during initial or busy master-master replication. 389-DS
+documentation suggets a timeout of 60 seconds to improve convergence of
+replicas.
+
+See: http://directory.fedoraproject.org/docs/389ds/design/repl-conv-design.html
+Fixes: https://pagure.io/freeipa/issue/7488
+Signed-off-by: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+---
+ ipaserver/install/replication.py    | 21 ++++++++++++++++-----
+ ipaserver/install/server/upgrade.py | 17 +++++++++++++++++
+ 2 files changed, 33 insertions(+), 5 deletions(-)
+
+diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
+index 3cd871e5df44398fd994504a3807a5648af5e048..e0055b792ce5b51fd411a7ea1f4316bb017984ba 100644
+--- a/ipaserver/install/replication.py
++++ b/ipaserver/install/replication.py
+@@ -468,20 +468,30 @@ class ReplicationManager(object):
+ 
+         try:
+             entry = conn.get_entry(dn)
++        except errors.NotFound:
++            pass
++        else:
+             managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])}
+ 
++            mods = []
+             if replica_binddn not in managers:
+                 # Add the new replication manager
+-                mod = [(ldap.MOD_ADD, 'nsDS5ReplicaBindDN',
+-                        replica_binddn)]
+-                conn.modify_s(dn, mod)
++                mods.append(
++                    (ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn)
++                )
++            if 'nsds5replicareleasetimeout' not in entry:
++                # See https://pagure.io/freeipa/issue/7488
++                mods.append(
++                    (ldap.MOD_ADD, 'nsds5replicareleasetimeout', ['60'])
++                )
++
++            if mods:
++                conn.modify_s(dn, mods)
+ 
+             self.set_replica_binddngroup(conn, entry)
+ 
+             # replication is already configured
+             return
+-        except errors.NotFound:
+-            pass
+ 
+         replica_type = self.get_replica_type()
+ 
+@@ -496,6 +506,7 @@ class ReplicationManager(object):
+             nsds5replicabinddn=[replica_binddn],
+             nsds5replicabinddngroup=[self.repl_man_group_dn],
+             nsds5replicabinddngroupcheckinterval=["60"],
++            nsds5replicareleasetimeout=["60"],
+             nsds5replicalegacyconsumer=["off"],
+         )
+         conn.add_entry(entry)
+diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
+index 62665d56ca0fb2c632f8ba135f8b6191a18b6aa1..62a75510ad331923f468c28908ea407789ec380c 100644
+--- a/ipaserver/install/server/upgrade.py
++++ b/ipaserver/install/server/upgrade.py
+@@ -1565,6 +1565,19 @@ def disable_httpd_system_trust(http):
+             db.add_cert(cert, nickname, trust_flags)
+ 
+ 
++def update_replica_config(db_suffix):
++    dn = DN(
++        ('cn', 'replica'), ('cn', db_suffix), ('cn', 'mapping tree'),
++        ('cn', 'config')
++    )
++    entry = api.Backend.ldap2.get_entry(dn)
++    if 'nsds5replicareleasetimeout' not in entry:
++        # See https://pagure.io/freeipa/issue/7488
++        root_logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn)
++        entry['nsds5replicareleasetimeout'] = '60'
++        api.Backend.ldap2.update_entry(entry)
++
++
+ def upgrade_configuration():
+     """
+     Execute configuration upgrade of the IPA services
+@@ -1681,6 +1694,10 @@ def upgrade_configuration():
+ 
+     ds.configure_dirsrv_ccache()
+ 
++    update_replica_config(ipautil.realm_to_suffix(api.env.realm))
++    if ca.is_configured():
++        update_replica_config(DN(('o', 'ipaca')))
++
+     ntpinstance.ntp_ldap_enable(api.env.host, api.env.basedn, api.env.realm)
+ 
+     ds.stop(ds_serverid)
+-- 
+2.14.3
+
diff --git a/SOURCES/0046-Fix-upgrade-update_replica_config-in-single-master-m.patch b/SOURCES/0046-Fix-upgrade-update_replica_config-in-single-master-m.patch
new file mode 100644
index 0000000..78b5617
--- /dev/null
+++ b/SOURCES/0046-Fix-upgrade-update_replica_config-in-single-master-m.patch
@@ -0,0 +1,39 @@
+From 6d868b2dd17ada072553c8d7440ee6fbd95a052a Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Mon, 16 Apr 2018 16:02:03 +1000
+Subject: [PATCH] Fix upgrade (update_replica_config) in single master mode
+
+Commit afc0d4b62d043cd568ce87400f60e8fa8273495f added an upgrade
+step that add an attribute to a replica config entry.  The entry
+only exists after a replica has been added, so upgrade was broken
+for standalone server.  Catch and suppress the NotFound error.
+
+Related to: https://pagure.io/freeipa/issue/7488
+
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+---
+ ipaserver/install/server/upgrade.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
+index 62a75510ad331923f468c28908ea407789ec380c..c55242a4af990c3218d8451fac7b082066a23be3 100644
+--- a/ipaserver/install/server/upgrade.py
++++ b/ipaserver/install/server/upgrade.py
+@@ -1570,7 +1570,11 @@ def update_replica_config(db_suffix):
+         ('cn', 'replica'), ('cn', db_suffix), ('cn', 'mapping tree'),
+         ('cn', 'config')
+     )
+-    entry = api.Backend.ldap2.get_entry(dn)
++    try:
++        entry = api.Backend.ldap2.get_entry(dn)
++    except ipalib.errors.NotFound:
++        return  # entry does not exist until a replica is installed
++
+     if 'nsds5replicareleasetimeout' not in entry:
+         # See https://pagure.io/freeipa/issue/7488
+         root_logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn)
+-- 
+2.14.3
+
diff --git a/SOURCES/0047-Use-single-Custodia-instance-in-installers.patch b/SOURCES/0047-Use-single-Custodia-instance-in-installers.patch
new file mode 100644
index 0000000..6ff3f36
--- /dev/null
+++ b/SOURCES/0047-Use-single-Custodia-instance-in-installers.patch
@@ -0,0 +1,620 @@
+From 11e597217fe6f1dcee3a918eef0bc3a0d2928e6d Mon Sep 17 00:00:00 2001
+From: Christian Heimes <cheimes@redhat.com>
+Date: Thu, 26 Apr 2018 12:06:36 +0200
+Subject: [PATCH] Use single Custodia instance in installers
+
+Installers now pass a single CustodiaInstance object around, instead of
+creating new instances on demand. In case of replica promotion with CA,
+the instance gets all secrets from a master with CA present. Before, an
+installer created multiple instances and may have requested CA key
+material from a different machine than DM password hash.
+
+In case of Domain Level 1 and replica promotion, the CustodiaInstance no
+longer adds the keys to the local instance and waits for replication to
+other replica. Instead the installer directly uploads the new public
+keys to the remote 389-DS instance.
+
+Without promotion, new Custodia public keys are still added to local
+389-DS over LDAPI.
+
+Fixes: https://pagure.io/freeipa/issue/7518
+Signed-off-by: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Simo Sorce <ssorce@redhat.com>
+Reviewed-By: Simo Sorce <ssorce@redhat.com>
+---
+ install/tools/ipa-ca-install               |  13 ++-
+ ipaserver/install/ca.py                    |  26 +++--
+ ipaserver/install/cainstance.py            |   9 +-
+ ipaserver/install/custodiainstance.py      | 150 ++++++++++++++++++++++-------
+ ipaserver/install/ipa_kra_install.py       |  10 +-
+ ipaserver/install/kra.py                   |   6 +-
+ ipaserver/install/server/install.py        |  14 +--
+ ipaserver/install/server/replicainstall.py |  15 +--
+ 8 files changed, 165 insertions(+), 78 deletions(-)
+
+diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
+index f84b4749a3e2a80aca002a2aa057b200e6187f18..a3694007e5815d1c44f642057c749879d336dfc5 100755
+--- a/install/tools/ipa-ca-install
++++ b/install/tools/ipa-ca-install
+@@ -31,6 +31,7 @@ from ipaserver.install.installutils import create_replica_config
+ from ipaserver.install.installutils import check_creds, ReplicaConfig
+ from ipaserver.install import dsinstance, ca
+ from ipaserver.install import cainstance, service
++from ipaserver.install import custodiainstance
+ from ipapython import version
+ from ipalib import api
+ from ipalib.constants import DOMAIN_LEVEL_0
+@@ -193,13 +194,17 @@ def install_replica(safe_options, options, filename):
+     options.domain_name = config.domain_name
+     options.dm_password = config.dirman_password
+     options.host_name = config.host_name
++    options.ca_host_name = config.ca_host_name
+     if os.path.exists(cafile):
+         options.ca_cert_file = cafile
+     else:
+         options.ca_cert_file = None
+ 
+     ca.install_check(True, config, options)
+-    ca.install(True, config, options)
++
++    custodia = custodiainstance.get_custodia_instance(
++        options, custodiainstance.CustodiaModes.CA_PEER)
++    ca.install(True, config, options, custodia=custodia)
+ 
+ 
+ def install_master(safe_options, options):
+@@ -228,7 +233,11 @@ def install_master(safe_options, options):
+         sys.exit("CA subject: {}".format(e.message))
+ 
+     ca.install_check(True, None, options)
+-    ca.install(True, None, options)
++
++    # No CA peer available yet.
++    custodia = custodiainstance.get_custodia_instance(
++        options, custodiainstance.CustodiaModes.STANDALONE)
++    ca.install(True, None, options, custodia=custodia)
+ 
+ 
+ def install(safe_options, options, filename):
+diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
+index 52cb20f1cb3612394544a6a41f10e9e939bc0657..2ac4382ccd24d217832950b94baddd113f7a8930 100644
+--- a/ipaserver/install/ca.py
++++ b/ipaserver/install/ca.py
+@@ -19,10 +19,7 @@ from ipalib.install.service import enroll_only, master_install_only, replica_ins
+ from ipaserver.install import sysupgrade
+ from ipapython.install import typing
+ from ipapython.install.core import group, knob, extend_knob
+-from ipaserver.install import (cainstance,
+-                               custodiainstance,
+-                               dsinstance,
+-                               bindinstance)
++from ipaserver.install import cainstance, bindinstance, dsinstance
+ from ipapython import ipautil, certdb
+ from ipapython.admintool import ScriptError
+ from ipaplatform import services
+@@ -201,12 +198,12 @@ def install_check(standalone, replica_config, options):
+                         "cannot continue." % (subject, db.secdir))
+ 
+ 
+-def install(standalone, replica_config, options):
+-    install_step_0(standalone, replica_config, options)
+-    install_step_1(standalone, replica_config, options)
++def install(standalone, replica_config, options, custodia):
++    install_step_0(standalone, replica_config, options, custodia=custodia)
++    install_step_1(standalone, replica_config, options, custodia=custodia)
+ 
+ 
+-def install_step_0(standalone, replica_config, options):
++def install_step_0(standalone, replica_config, options, custodia):
+     realm_name = options.realm_name
+     dm_password = options.dm_password
+     host_name = options.host_name
+@@ -237,9 +234,6 @@ def install_step_0(standalone, replica_config, options):
+     else:
+         cafile = os.path.join(replica_config.dir, 'cacert.p12')
+         if options.promote:
+-            custodia = custodiainstance.CustodiaInstance(
+-                replica_config.host_name,
+-                replica_config.realm_name)
+             custodia.get_ca_keys(
+                 replica_config.ca_host_name,
+                 cafile,
+@@ -266,7 +260,9 @@ def install_step_0(standalone, replica_config, options):
+         'certmap.conf', 'subject_base', str(subject_base))
+     dsinstance.write_certmap_conf(realm_name, ca_subject)
+ 
+-    ca = cainstance.CAInstance(realm_name, host_name=host_name)
++    ca = cainstance.CAInstance(
++        realm=realm_name, host_name=host_name, custodia=custodia
++    )
+     ca.configure_instance(host_name, dm_password, dm_password,
+                           subject_base=subject_base,
+                           ca_subject=ca_subject,
+@@ -284,7 +280,7 @@ def install_step_0(standalone, replica_config, options):
+                           use_ldaps=standalone)
+ 
+ 
+-def install_step_1(standalone, replica_config, options):
++def install_step_1(standalone, replica_config, options, custodia):
+     if replica_config is not None and not replica_config.setup_ca:
+         return
+ 
+@@ -293,7 +289,9 @@ def install_step_1(standalone, replica_config, options):
+     subject_base = options._subject_base
+     basedn = ipautil.realm_to_suffix(realm_name)
+ 
+-    ca = cainstance.CAInstance(realm_name, host_name=host_name)
++    ca = cainstance.CAInstance(
++        realm=realm_name, host_name=host_name, custodia=custodia
++    )
+ 
+     ca.stop('pki-tomcat')
+ 
+diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
+index 20635eae22268ff72de73b8b9c430050114bb45b..eefc30b6e01dcf744703b8607cbe169fbec5d859 100644
+--- a/ipaserver/install/cainstance.py
++++ b/ipaserver/install/cainstance.py
+@@ -59,7 +59,6 @@ from ipapython.ipa_log_manager import log_mgr,\
+ from ipaserver.secrets.kem import IPAKEMKeys
+ 
+ from ipaserver.install import certs
+-from ipaserver.install import custodiainstance
+ from ipaserver.install import dsinstance
+ from ipaserver.install import installutils
+ from ipaserver.install import ldapupdate
+@@ -285,7 +284,7 @@ class CAInstance(DogtagInstance):
+                      'caSigningCert cert-pki-ca')
+     server_cert_name = 'Server-Cert cert-pki-ca'
+ 
+-    def __init__(self, realm=None, host_name=None):
++    def __init__(self, realm=None, host_name=None, custodia=None):
+         super(CAInstance, self).__init__(
+             realm=realm,
+             subsystem="CA",
+@@ -310,6 +309,8 @@ class CAInstance(DogtagInstance):
+         self.no_db_setup = False
+         self.keytab = os.path.join(
+             paths.PKI_TOMCAT, self.service_prefix + '.keytab')
++        # Custodia instance for RA key retrieval
++        self._custodia = custodia
+ 
+     def configure_instance(self, host_name, dm_password, admin_password,
+                            pkcs12_info=None, master_host=None, csr_file=None,
+@@ -711,9 +712,7 @@ class CAInstance(DogtagInstance):
+         self.configure_agent_renewal()
+ 
+     def __import_ra_key(self):
+-        custodia = custodiainstance.CustodiaInstance(host_name=self.fqdn,
+-                                                     realm=self.realm)
+-        custodia.import_ra_key(self.master_host)
++        self._custodia.import_ra_key(self.master_host)
+         self.__set_ra_cert_perms()
+ 
+         self.configure_agent_renewal()
+diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
+index 0a90bb3954486b9773e3553e9981d2a8d0d4e44a..262ae5857c64719ff5cebde31b4b107e1245d458 100644
+--- a/ipaserver/install/custodiainstance.py
++++ b/ipaserver/install/custodiainstance.py
+@@ -1,5 +1,9 @@
+ # Copyright (C) 2015 FreeIPa Project Contributors, see 'COPYING' for license.
+ 
++from __future__ import print_function, absolute_import
++
++import enum
++
+ from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap
+ from ipaserver.secrets.client import CustodiaClient
+ from ipaplatform.paths import paths
+@@ -21,12 +25,84 @@ import time
+ import pwd
+ 
+ 
++class CustodiaModes(enum.Enum):
++    # peer must have a CA
++    CA_PEER = 'Custodia CA peer'
++    # peer must have a CA, KRA preferred
++    KRA_PEER = 'Custodia KRA peer'
++    # any master will do
++    MASTER_PEER = 'Custodia master peer'
++    # standalone / local instance
++    STANDALONE = 'Custodia standalone'
++
++
++def get_custodia_instance(config, mode):
++    """Create Custodia instance
++
++    :param config: configuration/installer object
++    :param mode: CustodiaModes member
++    :return: CustodiaInstance object
++
++    The config object must have the following attribute
++
++    *host_name*
++      FQDN of the new replica/master
++    *realm_name*
++      Kerberos realm
++    *promote*
++      True, when instance will be promoted from client to replica
++    *master_host_name* (for *CustodiaModes.MASTER_PEER*)
++      hostname of a master (may not have a CA)
++    *ca_host_name* (for *CustodiaModes.CA_PEER*)
++      hostname of a master with CA
++    *kra_host_name* (for *CustodiaModes.KRA_PEER*)
++      hostname of a master with KRA or CA
++
++    For promotion, the instance will upload new keys and retrieve secrets
++    from the same host. Therefore it uses *ca_host_name* instead of
++    *master_host_name* to create a replica with CA.
++    """
++    assert isinstance(mode, CustodiaModes)
++    root_logger.info(
++        "Custodia client for '%r' with promotion %s.",
++        mode, 'yes' if config.promote else 'no'
++    )
++    if config.promote:
++        if mode == CustodiaModes.CA_PEER:
++            # In case we install replica with CA, prefer CA host as source for
++            # all Custodia secret material.
++            custodia_master = config.ca_host_name
++        elif mode == CustodiaModes.KRA_PEER:
++            custodia_master = config.kra_host_name
++        elif mode == CustodiaModes.MASTER_PEER:
++            custodia_master = config.master_host_name
++        elif mode == CustodiaModes.STANDALONE:
++            custodia_master = None
++    else:
++        custodia_master = None
++
++    if custodia_master is None:
++        # use ldapi with local dirsrv instance
++        root_logger.info("Custodia uses LDAPI.")
++        ldap_uri = None
++    else:
++        root_logger.info("Custodia uses '%s' as master peer.",
++                         custodia_master)
++        ldap_uri = 'ldap://{}'.format(custodia_master)
++
++    return CustodiaInstance(
++        host_name=config.host_name,
++        realm=config.realm_name,
++        ldap_uri=ldap_uri
++    )
++
++
+ class CustodiaInstance(SimpleServiceInstance):
+-    def __init__(self, host_name=None, realm=None):
++    def __init__(self, host_name=None, realm=None, ldap_uri=None):
+         super(CustodiaInstance, self).__init__("ipa-custodia")
+         self.config_file = paths.IPA_CUSTODIA_CONF
+         self.server_keys = paths.IPA_CUSTODIA_KEYS
+-        self.ldap_uri = None
++        self.ldap_uri = ldap_uri
+         self.fqdn = host_name
+         self.realm = realm
+ 
+@@ -49,14 +125,19 @@ class CustodiaInstance(SimpleServiceInstance):
+             ipautil.flush_sync(f)
+ 
+     def create_instance(self):
+-        suffix = ipautil.realm_to_suffix(self.realm)
++        if self.ldap_uri is None or self.ldap_uri.startswith('ldapi://'):
++            # local case, ensure container exists
++            self.step("Making sure custodia container exists",
++                      self.__create_container)
++
+         self.step("Generating ipa-custodia config file", self.__config_file)
+-        self.step("Making sure custodia container exists", self.__create_container)
+         self.step("Generating ipa-custodia keys", self.__gen_keys)
+-        super(CustodiaInstance, self).create_instance(gensvc_name='KEYS',
+-                                                      fqdn=self.fqdn,
+-                                                      ldap_suffix=suffix,
+-                                                      realm=self.realm)
++        super(CustodiaInstance, self).create_instance(
++            gensvc_name='KEYS',
++            fqdn=self.fqdn,
++            ldap_suffix=ipautil.realm_to_suffix(self.realm),
++            realm=self.realm
++        )
+         sysupgrade.set_upgrade_state('custodia', 'installed', True)
+ 
+     def __gen_keys(self):
+@@ -81,18 +162,6 @@ class CustodiaInstance(SimpleServiceInstance):
+             root_logger.info("Secure server.keys mode")
+             os.chmod(self.server_keys, 0o600)
+ 
+-    def create_replica(self, master_host_name):
+-        suffix = ipautil.realm_to_suffix(self.realm)
+-        self.ldap_uri = 'ldap://%s' % master_host_name
+-        self.master_host_name = master_host_name
+-
+-        self.step("Generating ipa-custodia config file", self.__config_file)
+-        self.step("Generating ipa-custodia keys", self.__gen_keys)
+-        super(CustodiaInstance, self).create_instance(gensvc_name='KEYS',
+-                                                      fqdn=self.fqdn,
+-                                                      ldap_suffix=suffix,
+-                                                      realm=self.realm)
+-
+     def __create_container(self):
+         """
+         Runs the custodia update file to ensure custodia container is present.
+@@ -106,7 +175,7 @@ class CustodiaInstance(SimpleServiceInstance):
+         updater.update([os.path.join(paths.UPDATES_DIR, '73-custodia.update')])
+ 
+     def import_ra_key(self, master_host_name):
+-        cli = self.__CustodiaClient(server=master_host_name)
++        cli = self._get_custodia_client(server=master_host_name)
+         # please note that ipaCert part has to stay here for historical
+         # reasons (old servers expect you to ask for ra/ipaCert during
+         # replication as they store the RA agent cert in an NSS database
+@@ -114,14 +183,14 @@ class CustodiaInstance(SimpleServiceInstance):
+         cli.fetch_key('ra/ipaCert')
+ 
+     def import_dm_password(self, master_host_name):
+-        cli = self.__CustodiaClient(server=master_host_name)
++        cli = self._get_custodia_client(server=master_host_name)
+         cli.fetch_key('dm/DMHash')
+ 
+-    def __wait_keys(self, host, timeout=300):
++    def _wait_keys(self, host, timeout=300):
+         ldap_uri = 'ldap://%s' % host
+         deadline = int(time.time()) + timeout
+-        root_logger.info("Waiting up to {} seconds to see our keys "
+-                         "appear on host: {}".format(timeout, host))
++        root_logger.info("Waiting up to %s seconds to see our keys "
++                         "appear on host: %s", timeout, host)
+ 
+         konn = KEMLdap(ldap_uri)
+         saved_e = None
+@@ -129,6 +198,12 @@ class CustodiaInstance(SimpleServiceInstance):
+             try:
+                 return konn.check_host_keys(self.fqdn)
+             except Exception as e:
++                # Print message to console only once for first error.
++                if saved_e is None:
++                    # FIXME: Change once there's better way to show this
++                    # message in installer output,
++                    print("  Waiting for keys to appear on host: {}, please "
++                          "wait until this has completed.".format(host))
+                 # log only once for the same error
+                 if not isinstance(e, type(saved_e)):
+                     root_logger.debug(
+@@ -138,22 +213,23 @@ class CustodiaInstance(SimpleServiceInstance):
+                     raise RuntimeError("Timed out trying to obtain keys.")
+                 time.sleep(1)
+ 
+-    def __CustodiaClient(self, server):
++    def _get_custodia_client(self, server):
+         # Before we attempt to fetch keys from this host, make sure our public
+         # keys have been replicated there.
+-        self.__wait_keys(server)
+-
+-        return CustodiaClient('host@%s' % self.fqdn, self.server_keys,
+-                              paths.KRB5_KEYTAB, server, realm=self.realm)
++        self._wait_keys(server)
+ 
+-    def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
+-        # Fecth all needed certs one by one, then combine them in a single
+-        # p12 file
++        return CustodiaClient(
++            client_service='host@{}'.format(self.fqdn),
++            keyfile=self.server_keys, keytab=paths.KRB5_KEYTAB,
++            server=server, realm=self.realm
++        )
+ 
++    def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
++        # Fetch all needed certs one by one, then combine them in a single
++        # PKCS12 file
+         prefix = data['prefix']
+         certlist = data['list']
+-
+-        cli = self.__CustodiaClient(server=ca_host)
++        cli = self._get_custodia_client(server=ca_host)
+ 
+         # Temporary nssdb
+         tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
+@@ -203,7 +279,7 @@ class CustodiaInstance(SimpleServiceInstance):
+                     'subsystemCert cert-pki-ca']
+         data = {'prefix': 'ca',
+                 'list': certlist}
+-        self.__get_keys(ca_host, cacerts_file, cacerts_pwd, data)
++        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
+ 
+     def get_kra_keys(self, ca_host, cacerts_file, cacerts_pwd):
+         certlist = ['auditSigningCert cert-pki-kra',
+@@ -212,7 +288,7 @@ class CustodiaInstance(SimpleServiceInstance):
+                     'transportCert cert-pki-kra']
+         data = {'prefix': 'ca',
+                 'list': certlist}
+-        self.__get_keys(ca_host, cacerts_file, cacerts_pwd, data)
++        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
+ 
+     def __start(self):
+         super(CustodiaInstance, self).__start()
+diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py
+index 3e08f4da94651b49876e1427daddbd957f0027ae..9ebabe057513141ee76d238a3f20e76a27dd932e 100644
+--- a/ipaserver/install/ipa_kra_install.py
++++ b/ipaserver/install/ipa_kra_install.py
+@@ -32,6 +32,7 @@ from ipapython import admintool
+ from ipapython import ipautil
+ from ipaserver.install import service
+ from ipaserver.install import cainstance
++from ipaserver.install import custodiainstance
+ from ipaserver.install import krainstance
+ from ipaserver.install import dsinstance
+ from ipaserver.install import installutils
+@@ -176,7 +177,6 @@ class KRAInstaller(KRAInstall):
+ 
+         api.Backend.ldap2.connect()
+ 
+-        config = None
+         if self.installing_replica:
+             if self.options.promote:
+                 config = ReplicaConfig()
+@@ -196,6 +196,7 @@ class KRAInstaller(KRAInstall):
+                 config.kra_host_name = config.master_host_name
+ 
+             config.setup_kra = True
++            config.promote = self.options.promote
+ 
+             if config.subject_base is None:
+                 attrs = api.Backend.ldap2.get_ipa_config()
+@@ -204,6 +205,11 @@ class KRAInstaller(KRAInstall):
+             if config.kra_host_name is None:
+                 config.kra_host_name = service.find_providing_server(
+                     'KRA', api.Backend.ldap2, api.env.ca_host)
++            custodia = custodiainstance.get_custodia_instance(
++                config, custodiainstance.CustodiaModes.KRA_PEER)
++        else:
++            config = None
++            custodia = None
+ 
+         try:
+             kra.install_check(api, config, self.options)
+@@ -213,7 +219,7 @@ class KRAInstaller(KRAInstall):
+         print(dedent(self.INSTALLER_START_MESSAGE))
+ 
+         try:
+-            kra.install(api, config, self.options)
++            kra.install(api, config, self.options, custodia=custodia)
+         except:
+             self.log.error(dedent(self.FAIL_MESSAGE))
+             raise
+diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
+index 3545b301a977f4b7e7801ca1ef87d594bb3ba54f..3333970e8af9e36d6b7614286cc1e774f6eb9b25 100644
+--- a/ipaserver/install/kra.py
++++ b/ipaserver/install/kra.py
+@@ -16,7 +16,6 @@ from ipaplatform.paths import paths
+ from ipapython import certdb
+ from ipapython import ipautil
+ from ipapython.install.core import group
+-from ipaserver.install import custodiainstance
+ from ipaserver.install import cainstance
+ from ipaserver.install import krainstance
+ from ipaserver.install import dsinstance
+@@ -68,7 +67,7 @@ def install_check(api, replica_config, options):
+                                    "new replica file.")
+ 
+ 
+-def install(api, replica_config, options):
++def install(api, replica_config, options, custodia):
+     if replica_config is None:
+         if not options.setup_kra:
+             return
+@@ -91,9 +90,6 @@ def install(api, replica_config, options):
+                     'host/{env.host}@{env.realm}'.format(env=api.env),
+                     paths.KRB5_KEYTAB,
+                     ccache)
+-                custodia = custodiainstance.CustodiaInstance(
+-                    replica_config.host_name,
+-                    replica_config.realm_name)
+                 custodia.get_kra_keys(
+                     replica_config.kra_host_name,
+                     krafile,
+diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
+index 422474fa915b4876530f304ef9424f6b31cf26cc..f4338ed0428f7f44decd004f6a183258bef7f795 100644
+--- a/ipaserver/install/server/install.py
++++ b/ipaserver/install/server/install.py
+@@ -709,6 +709,7 @@ def install(installer):
+     host_name = options.host_name
+     ip_addresses = options.ip_addresses
+     setup_ca = options.setup_ca
++    options.promote = False  # first master, no promotion
+ 
+     # Installation has started. No IPA sysrestore items are restored in case of
+     # failure to enable root cause investigation
+@@ -789,6 +790,10 @@ def install(installer):
+                       setup_pkinit=not options.no_pkinit,
+                       subject_base=options.subject_base)
+ 
++    custodia = custodiainstance.get_custodia_instance(
++        options, custodiainstance.CustodiaModes.MASTER_PEER)
++    custodia.create_instance()
++
+     if setup_ca:
+         if not options.external_cert_files and options.external_ca:
+             # stage 1 of external CA installation
+@@ -803,7 +808,7 @@ def install(installer):
+                           if n in options.__dict__}
+             write_cache(cache_vars)
+ 
+-        ca.install_step_0(False, None, options)
++        ca.install_step_0(False, None, options, custodia=custodia)
+     else:
+         # Put the CA cert where other instances expect it
+         x509.write_certificate(http_ca_cert, paths.IPA_CA_CRT)
+@@ -823,15 +828,12 @@ def install(installer):
+     ds.enable_ssl()
+ 
+     if setup_ca:
+-        ca.install_step_1(False, None, options)
++        ca.install_step_1(False, None, options, custodia=custodia)
+ 
+     otpd = otpdinstance.OtpdInstance()
+     otpd.create_instance('OTPD', host_name,
+                          ipautil.realm_to_suffix(realm_name))
+ 
+-    custodia = custodiainstance.CustodiaInstance(host_name, realm_name)
+-    custodia.create_instance()
+-
+     # Create a HTTP instance
+     http = httpinstance.HTTPInstance(fstore)
+     if options.http_cert_files:
+@@ -863,7 +865,7 @@ def install(installer):
+     krb.restart()
+ 
+     if options.setup_kra:
+-        kra.install(api, None, options)
++        kra.install(api, None, options, custodia=custodia)
+ 
+     if options.setup_dns:
+         dns.install(False, False, options)
+diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
+index 42e4615ad2dc1f604f5d8d14f8e57e3e4674bcb9..2ecc0abe0c5918cf5aefccc1bd6f09e70503baab 100644
+--- a/ipaserver/install/server/replicainstall.py
++++ b/ipaserver/install/server/replicainstall.py
+@@ -1357,6 +1357,7 @@ def install(installer):
+     fstore = installer._fstore
+     sstore = installer._sstore
+     config = installer._config
++    config.promote = installer.promote
+     promote = installer.promote
+     cafile = installer._ca_file
+     dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
+@@ -1483,19 +1484,19 @@ def install(installer):
+     otpd.create_instance('OTPD', config.host_name,
+                          ipautil.realm_to_suffix(config.realm_name))
+ 
+-    custodia = custodiainstance.CustodiaInstance(config.host_name,
+-                                                 config.realm_name)
+-    if promote:
+-        custodia.create_replica(config.master_host_name)
++    if ca_enabled:
++        mode = custodiainstance.CustodiaModes.CA_PEER
+     else:
+-        custodia.create_instance()
++        mode = custodiainstance.CustodiaModes.MASTER_PEER
++    custodia = custodiainstance.get_custodia_instance(config, mode)
++    custodia.create_instance()
+ 
+     if ca_enabled:
+         options.realm_name = config.realm_name
+         options.domain_name = config.domain_name
+         options.host_name = config.host_name
+         options.dm_password = config.dirman_password
+-        ca.install(False, config, options)
++        ca.install(False, config, options, custodia=custodia)
+ 
+     # configure PKINIT now that all required services are in place
+     krb.enable_ssl()
+@@ -1505,7 +1506,7 @@ def install(installer):
+     ds.apply_updates()
+ 
+     if kra_enabled:
+-        kra.install(api, config, options)
++        kra.install(api, config, options, custodia=custodia)
+ 
+     service.print_msg("Restarting the KDC")
+     krb.restart()
+-- 
+2.14.3
+
diff --git a/SOURCES/0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch b/SOURCES/0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch
new file mode 100644
index 0000000..cd44943
--- /dev/null
+++ b/SOURCES/0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch
@@ -0,0 +1,33 @@
+From 56326828c7ccf75bd867330606c83a621affab9a Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 26 Feb 2018 16:13:58 -0500
+Subject: [PATCH] Don't try to backup CS.cfg during upgrade if CA is not
+ configured
+
+https://pagure.io/freeipa/issue/7409
+
+Signed-off-by: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
+---
+ ipaserver/install/server/upgrade.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
+index c55242a4af990c3218d8451fac7b082066a23be3..bf603acb5f931a4194320795874859f5bdc94647 100644
+--- a/ipaserver/install/server/upgrade.py
++++ b/ipaserver/install/server/upgrade.py
+@@ -1630,7 +1630,8 @@ def upgrade_configuration():
+ 
+     with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'):
+         # Dogtag must be stopped to be able to backup CS.cfg config
+-        ca.backup_config()
++        if ca.is_configured():
++            ca.backup_config()
+ 
+         # migrate CRL publish dir before the location in ipa.conf is updated
+         ca_restart = migrate_crl_publish_dir(ca)
+-- 
+2.14.3
+
diff --git a/SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch b/SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch
new file mode 100644
index 0000000..44a243a
--- /dev/null
+++ b/SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch
@@ -0,0 +1,270 @@
+From d3c09a6de06d8ae19d05c0b96cb9c2a5b789b472 Mon Sep 17 00:00:00 2001
+From: Christian Heimes <cheimes@redhat.com>
+Date: Thu, 7 Jun 2018 18:17:20 +0200
+Subject: [PATCH] Use one Custodia peer to retrieve all secrets
+
+Fix 994f71ac8a1bb7ba6bc9caf0f6e4f59af44ad9c4 was incomplete. Under some
+circumstancs the DM hash and CA keys were still retrieved from two different
+machines.
+
+Custodia client now uses a single remote to upload keys and download all
+secrets.
+
+Fixes: https://pagure.io/freeipa/issue/7518
+Signed-off-by: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Simo Sorce <ssorce@redhat.com>
+---
+ ipaserver/install/ca.py                    |  1 -
+ ipaserver/install/cainstance.py            |  2 +-
+ ipaserver/install/custodiainstance.py      | 74 +++++++++++++++++-------------
+ ipaserver/install/kra.py                   |  1 -
+ ipaserver/install/server/install.py        |  4 +-
+ ipaserver/install/server/replicainstall.py |  2 +-
+ 6 files changed, 46 insertions(+), 38 deletions(-)
+
+diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
+index 2ac4382..1c7d375 100644
+--- a/ipaserver/install/ca.py
++++ b/ipaserver/install/ca.py
+@@ -235,7 +235,6 @@ def install_step_0(standalone, replica_config, options, custodia):
+         cafile = os.path.join(replica_config.dir, 'cacert.p12')
+         if options.promote:
+             custodia.get_ca_keys(
+-                replica_config.ca_host_name,
+                 cafile,
+                 replica_config.dirman_password)
+ 
+diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
+index eefc30b..cc0dbf3 100644
+--- a/ipaserver/install/cainstance.py
++++ b/ipaserver/install/cainstance.py
+@@ -712,7 +712,7 @@ class CAInstance(DogtagInstance):
+         self.configure_agent_renewal()
+ 
+     def __import_ra_key(self):
+-        self._custodia.import_ra_key(self.master_host)
++        self._custodia.import_ra_key()
+         self.__set_ra_cert_perms()
+ 
+         self.configure_agent_renewal()
+diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
+index 262ae58..ada8d03 100644
+--- a/ipaserver/install/custodiainstance.py
++++ b/ipaserver/install/custodiainstance.py
+@@ -71,41 +71,45 @@ def get_custodia_instance(config, mode):
+         if mode == CustodiaModes.CA_PEER:
+             # In case we install replica with CA, prefer CA host as source for
+             # all Custodia secret material.
+-            custodia_master = config.ca_host_name
++            custodia_peer = config.ca_host_name
+         elif mode == CustodiaModes.KRA_PEER:
+-            custodia_master = config.kra_host_name
++            custodia_peer = config.kra_host_name
+         elif mode == CustodiaModes.MASTER_PEER:
+-            custodia_master = config.master_host_name
++            custodia_peer = config.master_host_name
+         elif mode == CustodiaModes.STANDALONE:
+-            custodia_master = None
++            custodia_peer = None
+     else:
+-        custodia_master = None
++        custodia_peer = None
+ 
+-    if custodia_master is None:
++    if custodia_peer is None:
+         # use ldapi with local dirsrv instance
+         root_logger.info("Custodia uses LDAPI.")
+-        ldap_uri = None
+     else:
+-        root_logger.info("Custodia uses '%s' as master peer.",
+-                         custodia_master)
+-        ldap_uri = 'ldap://{}'.format(custodia_master)
++        root_logger.info("Custodia uses '%s' as master peer.", custodia_peer)
+ 
+     return CustodiaInstance(
+         host_name=config.host_name,
+         realm=config.realm_name,
+-        ldap_uri=ldap_uri
++        custodia_peer=custodia_peer
+     )
+ 
+ 
+ class CustodiaInstance(SimpleServiceInstance):
+-    def __init__(self, host_name=None, realm=None, ldap_uri=None):
++    def __init__(self, host_name=None, realm=None, custodia_peer=None):
+         super(CustodiaInstance, self).__init__("ipa-custodia")
+         self.config_file = paths.IPA_CUSTODIA_CONF
+         self.server_keys = paths.IPA_CUSTODIA_KEYS
+-        self.ldap_uri = ldap_uri
++        self.custodia_peer = custodia_peer
+         self.fqdn = host_name
+         self.realm = realm
+ 
++    @property
++    def ldap_uri(self):
++        if self.custodia_peer is None:
++            return installutils.realm_to_ldapi_uri(self.realm)
++        else:
++            return "ldap://{}".format(self.custodia_peer)
++
+     def __config_file(self):
+         template_file = os.path.basename(self.config_file) + '.template'
+         template = os.path.join(paths.USR_SHARE_IPA_DIR, template_file)
+@@ -125,7 +129,7 @@ class CustodiaInstance(SimpleServiceInstance):
+             ipautil.flush_sync(f)
+ 
+     def create_instance(self):
+-        if self.ldap_uri is None or self.ldap_uri.startswith('ldapi://'):
++        if self.ldap_uri.startswith('ldapi://'):
+             # local case, ensure container exists
+             self.step("Making sure custodia container exists",
+                       self.__create_container)
+@@ -174,25 +178,24 @@ class CustodiaInstance(SimpleServiceInstance):
+         updater = ldapupdate.LDAPUpdate(sub_dict=sub_dict)
+         updater.update([os.path.join(paths.UPDATES_DIR, '73-custodia.update')])
+ 
+-    def import_ra_key(self, master_host_name):
+-        cli = self._get_custodia_client(server=master_host_name)
++    def import_ra_key(self):
++        cli = self._get_custodia_client()
+         # please note that ipaCert part has to stay here for historical
+         # reasons (old servers expect you to ask for ra/ipaCert during
+         # replication as they store the RA agent cert in an NSS database
+         # with this nickname)
+         cli.fetch_key('ra/ipaCert')
+ 
+-    def import_dm_password(self, master_host_name):
+-        cli = self._get_custodia_client(server=master_host_name)
++    def import_dm_password(self):
++        cli = self._get_custodia_client()
+         cli.fetch_key('dm/DMHash')
+ 
+-    def _wait_keys(self, host, timeout=300):
+-        ldap_uri = 'ldap://%s' % host
++    def _wait_keys(self, timeout=300):
+         deadline = int(time.time()) + timeout
+         root_logger.info("Waiting up to %s seconds to see our keys "
+-                         "appear on host: %s", timeout, host)
++                         "appear on host %s", timeout, self.ldap_uri)
+ 
+-        konn = KEMLdap(ldap_uri)
++        konn = KEMLdap(self.ldap_uri)
+         saved_e = None
+         while True:
+             try:
+@@ -202,8 +205,11 @@ class CustodiaInstance(SimpleServiceInstance):
+                 if saved_e is None:
+                     # FIXME: Change once there's better way to show this
+                     # message in installer output,
+-                    print("  Waiting for keys to appear on host: {}, please "
+-                          "wait until this has completed.".format(host))
++                    print(
++                        "  Waiting for keys to appear on host: {}, please "
++                        "wait until this has completed.".format(
++                            self.ldap_uri)
++                    )
+                 # log only once for the same error
+                 if not isinstance(e, type(saved_e)):
+                     root_logger.debug(
+@@ -213,23 +219,25 @@ class CustodiaInstance(SimpleServiceInstance):
+                     raise RuntimeError("Timed out trying to obtain keys.")
+                 time.sleep(1)
+ 
+-    def _get_custodia_client(self, server):
++    def _get_custodia_client(self):
++        if self.custodia_peer is None:
++            raise ValueError("Can't replicate secrets without Custodia peer")
+         # Before we attempt to fetch keys from this host, make sure our public
+         # keys have been replicated there.
+-        self._wait_keys(server)
++        self._wait_keys()
+ 
+         return CustodiaClient(
+             client_service='host@{}'.format(self.fqdn),
+             keyfile=self.server_keys, keytab=paths.KRB5_KEYTAB,
+-            server=server, realm=self.realm
++            server=self.custodia_peer, realm=self.realm
+         )
+ 
+-    def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
++    def _get_keys(self, cacerts_file, cacerts_pwd, data):
+         # Fetch all needed certs one by one, then combine them in a single
+         # PKCS12 file
+         prefix = data['prefix']
+         certlist = data['list']
+-        cli = self._get_custodia_client(server=ca_host)
++        cli = self._get_custodia_client()
+ 
+         # Temporary nssdb
+         tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
+@@ -272,23 +280,23 @@ class CustodiaInstance(SimpleServiceInstance):
+         finally:
+             shutil.rmtree(tmpnssdir)
+ 
+-    def get_ca_keys(self, ca_host, cacerts_file, cacerts_pwd):
++    def get_ca_keys(self, cacerts_file, cacerts_pwd):
+         certlist = ['caSigningCert cert-pki-ca',
+                     'ocspSigningCert cert-pki-ca',
+                     'auditSigningCert cert-pki-ca',
+                     'subsystemCert cert-pki-ca']
+         data = {'prefix': 'ca',
+                 'list': certlist}
+-        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
++        self._get_keys(cacerts_file, cacerts_pwd, data)
+ 
+-    def get_kra_keys(self, ca_host, cacerts_file, cacerts_pwd):
++    def get_kra_keys(self, cacerts_file, cacerts_pwd):
+         certlist = ['auditSigningCert cert-pki-kra',
+                     'storageCert cert-pki-kra',
+                     'subsystemCert cert-pki-ca',
+                     'transportCert cert-pki-kra']
+         data = {'prefix': 'ca',
+                 'list': certlist}
+-        self._get_keys(ca_host, cacerts_file, cacerts_pwd, data)
++        self._get_keys(cacerts_file, cacerts_pwd, data)
+ 
+     def __start(self):
+         super(CustodiaInstance, self).__start()
+diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
+index 3333970..d8773b9 100644
+--- a/ipaserver/install/kra.py
++++ b/ipaserver/install/kra.py
+@@ -91,7 +91,6 @@ def install(api, replica_config, options, custodia):
+                     paths.KRB5_KEYTAB,
+                     ccache)
+                 custodia.get_kra_keys(
+-                    replica_config.kra_host_name,
+                     krafile,
+                     replica_config.dirman_password)
+         else:
+diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
+index f4338ed..3651cde 100644
+--- a/ipaserver/install/server/install.py
++++ b/ipaserver/install/server/install.py
+@@ -1085,7 +1085,9 @@ def uninstall(installer):
+     dsinstance.DsInstance(fstore=fstore).uninstall()
+     if _server_trust_ad_installed:
+         adtrustinstance.ADTRUSTInstance(fstore).uninstall()
+-    custodiainstance.CustodiaInstance().uninstall()
++    # realm isn't used, but IPAKEMKeys parses /etc/ipa/default.conf
++    # otherwise, see https://pagure.io/freeipa/issue/7474 .
++    custodiainstance.CustodiaInstance(realm='REALM.INVALID').uninstall()
+     otpdinstance.OtpdInstance().uninstall()
+     tasks.restore_hostname(fstore, sstore)
+     fstore.restore_all_files()
+diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
+index ef61590..b9cd518 100644
+--- a/ipaserver/install/server/replicainstall.py
++++ b/ipaserver/install/server/replicainstall.py
+@@ -1512,7 +1512,7 @@ def install(installer):
+     krb.restart()
+ 
+     if promote:
+-        custodia.import_dm_password(config.master_host_name)
++        custodia.import_dm_password()
+         promote_sssd(config.host_name)
+         promote_openldap_conf(config.host_name, config.master_host_name)
+ 
+-- 
+2.9.3
+
diff --git a/SOURCES/ipa-centos-branding.patch b/SOURCES/ipa-centos-branding.patch
deleted file mode 100644
index 673cd2f..0000000
--- a/SOURCES/ipa-centos-branding.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 99efecaf87dc1fc9517efaff441a6a7ce46444eb Mon Sep 17 00:00:00 2001
-From: Jim Perrin <jperrin@centos.org>
-Date: Wed, 11 Mar 2015 10:37:03 -0500
-Subject: [PATCH] update for new ntp server method
-
----
- ipaplatform/base/paths.py        | 1 +
- ipaserver/install/ntpinstance.py | 2 ++
- 2 files changed, 3 insertions(+)
-
-diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
-index af50262..5090062 100644
---- a/ipaplatform/base/paths.py
-+++ b/ipaplatform/base/paths.py
-@@ -99,6 +99,7 @@ class BasePathNamespace(object):
-     PKI_TOMCAT_ALIAS_DIR = "/etc/pki/pki-tomcat/alias/"
-     PKI_TOMCAT_PASSWORD_CONF = "/etc/pki/pki-tomcat/password.conf"
-     ETC_REDHAT_RELEASE = "/etc/redhat-release"
-+    ETC_CENTOS_RELEASE = "/etc/centos-release"
-     RESOLV_CONF = "/etc/resolv.conf"
-     SAMBA_KEYTAB = "/etc/samba/samba.keytab"
-     SMB_CONF = "/etc/samba/smb.conf"
-diff --git a/ipaserver/install/ntpinstance.py b/ipaserver/install/ntpinstance.py
-index c653525..4b0578b 100644
---- a/ipaserver/install/ntpinstance.py
-+++ b/ipaserver/install/ntpinstance.py
-@@ -44,6 +44,8 @@ class NTPInstance(service.Service):
-         os = ""
-         if ipautil.file_exists(paths.ETC_FEDORA_RELEASE):
-             os = "fedora"
-+        elif ipautil.file_exists(paths.ETC_CENTOS_RELEASE):
-+            os = "centos"
-         elif ipautil.file_exists(paths.ETC_REDHAT_RELEASE):
-             os = "rhel"
- 
--- 
-1.8.3.1
-
diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec
index 800060d..dbbe5e9 100644
--- a/SPECS/ipa.spec
+++ b/SPECS/ipa.spec
@@ -72,7 +72,7 @@
 
 Name:           ipa
 Version:        %{IPA_VERSION}
-Release:        10%{?dist}.1
+Release:        10%{?dist}.3
 Summary:        The Identity, Policy and Audit system
 
 Group:          System Environment/Base
@@ -80,10 +80,10 @@ License:        GPLv3+
 URL:            http://www.freeipa.org/
 Source0:        https://releases.pagure.org/freeipa/freeipa-%{version}.tar.gz
 # RHEL spec file only: START: Change branding to IPA and Identity Management
-#Source1:        header-logo.png
-#Source2:        login-screen-background.jpg
-#Source3:        login-screen-logo.png
-#Source4:        product-name.png
+Source1:        header-logo.png
+Source2:        login-screen-background.jpg
+Source3:        login-screen-logo.png
+Source4:        product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity Management
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -132,7 +132,11 @@ Patch0041:	0041-Revert-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch
 Patch0042:	0042-Log-errors-from-NSS-during-FIPS-OTP-key-import.patch
 Patch0043:	0043-ipa-replica-install-make-sure-that-certmonger-picks-.patch
 Patch0044:	0044-replica-install-pass-ip-address-to-client-install.patch
-
+Patch0045:	0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch
+Patch0046:	0046-Fix-upgrade-update_replica_config-in-single-master-m.patch
+Patch0047:	0047-Use-single-Custodia-instance-in-installers.patch
+Patch0048:	0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch
+Patch0049:	0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch
 Patch1001:      1001-Change-branding-to-IPA-and-Identity-Management.patch
 Patch1002:      1002-Package-copy-schema-to-ca.py.patch
 Patch1003:      1003-Revert-Increased-mod_wsgi-socket-timeout.patch
@@ -938,10 +942,10 @@ cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3
 %endif # with_python3
 
 # RHEL spec file only: START: Change branding to IPA and Identity Management
-#cp %SOURCE1 install/ui/images/header-logo.png
-#cp %SOURCE2 install/ui/images/login-screen-background.jpg
-#cp %SOURCE3 install/ui/images/login-screen-logo.png
-#cp %SOURCE4 install/ui/images/product-name.png
+cp %SOURCE1 install/ui/images/header-logo.png
+cp %SOURCE2 install/ui/images/login-screen-background.jpg
+cp %SOURCE3 install/ui/images/login-screen-logo.png
+cp %SOURCE4 install/ui/images/product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity Management
 
 
@@ -965,8 +969,7 @@ find \
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
-           %{linter_options} \
-           --with-ipaplatform=rhel
+           %{linter_options}
 
 %make_build
 
@@ -987,8 +990,7 @@ find \
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
-           %{linter_options} \
-           --with-ipaplatform=rhel
+           %{linter_options}
 popd
 %endif # with_python3
 
@@ -1696,10 +1698,20 @@ fi
 
 
 %changelog
-* Mon May 14 2018 CentOS Sources <bugs@centos.org> - 4.5.4-10.el7.centos.1
-- Roll in CentOS Branding
-
-* Tue Apr 10 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-11.el7
+* Mon Jun 11 2018 Rob Crittenden <rcritten@redhat.com> - 4.5.4-10.el7.3
+- Resolves: #1579190 Improve Custodia client and key distribution handling
+  - Use single Custodia instance in installers
+
+* Tue May 15 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.2
+- Resolves: #1579189 nsds5ReplicaReleaseTimeout should be set by default
+  - Add nsds5ReplicaReleaseTimeout to replica config
+  - Fix upgrade (update_replica_config) in single master mode
+- Resolves: #1579190 Improve Custodia client and key distribution handling
+  - Use single Custodia instance in installers
+- Resolves: #1579203 4.5.0 -> 4.5.4 upgrade breaks in ipa-server-upgrade: No such file or directory: '/var/lib/pki/pki-tomcat/conf/ca/CS.cfg'
+  - Don't try to backup CS.cfg during upgrade if CA is not configured
+
+* Tue Apr 10 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.1
 - Resolves: #1565519 Clarify the need to restart services in ipa-server-certinstall(1)
   - Add a notice to restart ipa services after certs are installed
 - Resolves: #1564390 OTP and Radius Authentication does not work in FIPS mode