From 2092220634ffac8235abe2de5b3ad34c71a617f2 Mon Sep 17 00:00:00 2001
From: Thomas Woerner <twoerner@redhat.com>
Date: Fri, 21 Jun 2019 12:24:10 +0200
Subject: [PATCH] ipareplica: Make sure that certmonger picks the right master

This is related to freeipa#0f31564b35aac250456233f98730811560eda664

  During ipa-replica-install, http installation first creates a service
  principal for http/hostname (locally on the soon-to-be-replica), then
  waits for this entry to be replicated on the master picked for the
  install.
  In a later step, the installer requests a certificate for HTTPd. The local
  certmonger first tries the master defined in xmlrpc_uri (which is
  pointing to the soon-to-be-replica), but fails because the service is not
  up yet. Then certmonger tries to find a master by using the DNS and looking
  for a ldap service. This step can pick a different master, where the
  principal entry has not always be replicated yet.
  As the certificate request adds the principal if it does not exist, we can
  end by re-creating the principal and have a replication conflict.

  The replication conflict later causes kerberos issues, preventing
  from installing a new replica.

  The proposed fix forces xmlrpc_uri to point to the same master as the one
  picked for the installation, in order to make sure that the master already
  contains the principal entry.

  https://pagure.io/freeipa/issue/7041
---
 .../library/ipareplica_create_ipa_conf.py     |  7 +-
 roles/ipareplica/library/ipareplica_test.py   | 34 ++++---
 roles/ipareplica/tasks/install.yml            | 93 +++++++++++++++++++
 3 files changed, 121 insertions(+), 13 deletions(-)

diff --git a/roles/ipareplica/library/ipareplica_create_ipa_conf.py b/roles/ipareplica/library/ipareplica_create_ipa_conf.py
index 26a9a070..e46421a5 100644
--- a/roles/ipareplica/library/ipareplica_create_ipa_conf.py
+++ b/roles/ipareplica/library/ipareplica_create_ipa_conf.py
@@ -172,6 +172,7 @@ def main():
             ### additional ###
             server=dict(required=True),
             config_master_host_name=dict(required=True),
+            config_ca_host_name=dict(required=True),
             ccache=dict(required=True),
             installer_ccache=dict(required=True),
             _ca_enabled=dict(required=False, type='bool'),
@@ -183,6 +184,7 @@ def main():
             _add_to_ipaservers = dict(required=True, type='bool'),
             _ca_subject=dict(required=True),
             _subject_base=dict(required=True),
+            master=dict(required=False, default=None),
 
             dirman_password=dict(required=True, no_log=True),
         ),
@@ -227,6 +229,7 @@ def main():
     #    '_hostname_overridden')
     options.server = ansible_module.params.get('server')
     master_host_name = ansible_module.params.get('config_master_host_name')
+    ca_host_name = ansible_module.params.get('config_ca_host_name')
     ccache = ansible_module.params.get('ccache')
     os.environ['KRB5CCNAME'] = ccache
     #os.environ['KRB5CCNAME'] = ansible_module.params.get('installer_ccache')
@@ -246,6 +249,7 @@ def main():
 
     options._ca_subject = ansible_module.params.get('_ca_subject')
     options._subject_base = ansible_module.params.get('_subject_base')
+    master = ansible_module.params.get('master')
 
     dirman_password = ansible_module.params.get('dirman_password')
 
@@ -267,6 +271,7 @@ def main():
     config = gen_ReplicaConfig()
     config.subject_base = options.subject_base
     config.dirman_password = dirman_password
+    config.ca_host_name = ca_host_name
 
     remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
     installer._remote_api = remote_api
@@ -284,7 +289,7 @@ def main():
         # successful uninstallation
         # The configuration creation has to be here otherwise previous call
         # To config certmonger would try to connect to local server
-        create_ipa_conf(fstore, config, ca_enabled)
+        create_ipa_conf(fstore, config, ca_enabled, master)
 
     # done #
 
diff --git a/roles/ipareplica/library/ipareplica_test.py b/roles/ipareplica/library/ipareplica_test.py
index 41975c05..7c6f6e90 100644
--- a/roles/ipareplica/library/ipareplica_test.py
+++ b/roles/ipareplica/library/ipareplica_test.py
@@ -179,6 +179,14 @@ def main():
         ansible_module.fail_json(
             msg="Hidden replica is not supported in this version.")
 
+    # We need to point to the master in ipa default conf when certmonger
+    # asks for HTTP certificate in newer ipa versions. In these versions
+    # create_ipa_conf has the additional master argument.
+    change_master_for_certmonger = False
+    argspec = inspect.getargspec(create_ipa_conf)
+    if "master" in argspec.args:
+        change_master_for_certmonger = True
+
     # From ipa installer classes
 
     # pkinit is not supported on DL0, don't allow related options
@@ -332,18 +340,20 @@ def main():
 
     # done #
 
-    ansible_module.exit_json(changed=False,
-                             ipa_python_version=IPA_PYTHON_VERSION,
-                             ### basic ###
-                             domain=options.domain_name,
-                             realm=options.realm_name,
-                             hostname=options.host_name,
-                             ### server ###
-                             setup_adtrust=options.setup_adtrust,
-                             setup_kra=options.setup_kra,
-                             server=options.server,
-                             ### additional ###
-                             client_enrolled=client_enrolled,
+    ansible_module.exit_json(
+        changed=False,
+        ipa_python_version=IPA_PYTHON_VERSION,
+        ### basic ###
+        domain=options.domain_name,
+        realm=options.realm_name,
+        hostname=options.host_name,
+        ### server ###
+        setup_adtrust=options.setup_adtrust,
+        setup_kra=options.setup_kra,
+        server=options.server,
+        ### additional ###
+        client_enrolled=client_enrolled,
+        change_master_for_certmonger=change_master_for_certmonger,
     )
 
 if __name__ == '__main__':
diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml
index 3f8bc6d1..1bb89dcb 100644
--- a/roles/ipareplica/tasks/install.yml
+++ b/roles/ipareplica/tasks/install.yml
@@ -314,6 +314,7 @@
       server: "{{ result_ipareplica_test.server }}"
       config_master_host_name:
         "{{ result_ipareplica_install_ca_certs.config_master_host_name }}"
+      config_ca_host_name: "{{ result_ipareplica_prepare.config_ca_host_name }}"
       ccache: "{{ result_ipareplica_prepare.ccache }}"
       installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}"
       _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
@@ -343,6 +344,54 @@
       _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
       _top_dir: "{{ result_ipareplica_prepare._top_dir }}"
 
+  # We need to point to the master in ipa default conf when certmonger
+  # asks for HTTP certificate in newer ipa versions. In these versions
+  # create_ipa_conf has the additional master argument.
+  - name: Install - Create override IPA conf
+    ipareplica_create_ipa_conf:
+      ### basic ###
+      dm_password: "{{ ipadm_password | default(omit) }}"
+      password: "{{ ipaadmin_password | default(omit) }}"
+      ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}"
+      domain: "{{ result_ipareplica_test.domain }}"
+      realm: "{{ result_ipareplica_test.realm }}"
+      hostname: "{{ result_ipareplica_test.hostname }}"
+      ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}"
+      no_host_dns: "{{ ipareplica_no_host_dns }}"
+      ### replica ###
+      setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}"
+      setup_kra: "{{ result_ipareplica_test.setup_kra }}"
+      setup_dns: "{{ ipareplica_setup_dns }}"
+      ### ssl certificate ###
+      dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}"
+      ### client ###
+      force_join: "{{ ipaclient_force_join }}"
+      ### ad trust ###
+      netbios_name: "{{ ipareplica_netbios_name | default(omit) }}"
+      rid_base: "{{ ipareplica_rid_base | default(omit) }}"
+      secondary_rid_base: "{{ ipareplica_secondary_rid_base | default(omit) }}"
+      ### additional ###
+      server: "{{ result_ipareplica_test.server }}"
+      config_master_host_name:
+        "{{ result_ipareplica_install_ca_certs.config_master_host_name }}"
+      config_ca_host_name: "{{ result_ipareplica_prepare.config_ca_host_name }}"
+      ccache: "{{ result_ipareplica_prepare.ccache }}"
+      installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}"
+      _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
+      _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}"
+      _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}"
+      _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}"
+      _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
+      subject_base: "{{ result_ipareplica_prepare.subject_base }}"
+      _top_dir: "{{ result_ipareplica_prepare._top_dir }}"
+      _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}"
+      _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}"
+      _subject_base: "{{ result_ipareplica_prepare._subject_base }}"
+      dirman_password: "{{ ipareplica_dirman_password }}"
+      master:
+        "{{ result_ipareplica_install_ca_certs.config_master_host_name }}"
+    when: result_ipareplica_test.change_master_for_certmonger
+
   - name: Install - DS enable SSL
     ipareplica_ds_enable_ssl:
       ### server ###
@@ -383,6 +432,50 @@
       _top_dir: "{{ result_ipareplica_prepare._top_dir }}"
       dirman_password: "{{ ipareplica_dirman_password }}"
 
+  # Need to point back to ourself after the cert for HTTP is obtained
+  - name: Install - Create original IPA conf again
+    ipareplica_create_ipa_conf:
+      ### basic ###
+      dm_password: "{{ ipadm_password | default(omit) }}"
+      password: "{{ ipaadmin_password | default(omit) }}"
+      ip_addresses: "{{ ipareplica_ip_addresses | default([]) }}"
+      domain: "{{ result_ipareplica_test.domain }}"
+      realm: "{{ result_ipareplica_test.realm }}"
+      hostname: "{{ result_ipareplica_test.hostname }}"
+      ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}"
+      no_host_dns: "{{ ipareplica_no_host_dns }}"
+      ### replica ###
+      setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}"
+      setup_kra: "{{ result_ipareplica_test.setup_kra }}"
+      setup_dns: "{{ ipareplica_setup_dns }}"
+      ### ssl certificate ###
+      dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}"
+      ### client ###
+      force_join: "{{ ipaclient_force_join }}"
+      ### ad trust ###
+      netbios_name: "{{ ipareplica_netbios_name | default(omit) }}"
+      rid_base: "{{ ipareplica_rid_base | default(omit) }}"
+      secondary_rid_base: "{{ ipareplica_secondary_rid_base | default(omit) }}"
+      ### additional ###
+      server: "{{ result_ipareplica_test.server }}"
+      config_master_host_name:
+        "{{ result_ipareplica_install_ca_certs.config_master_host_name }}"
+      config_ca_host_name: "{{ result_ipareplica_prepare.config_ca_host_name }}"
+      ccache: "{{ result_ipareplica_prepare.ccache }}"
+      installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}"
+      _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
+      _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}"
+      _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}"
+      _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}"
+      _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
+      subject_base: "{{ result_ipareplica_prepare.subject_base }}"
+      _top_dir: "{{ result_ipareplica_prepare._top_dir }}"
+      _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}"
+      _ca_subject: "{{ result_ipareplica_prepare._ca_subject }}"
+      _subject_base: "{{ result_ipareplica_prepare._subject_base }}"
+      dirman_password: "{{ ipareplica_dirman_password }}"
+    when: result_ipareplica_test.change_master_for_certmonger
+
   - name: Install - Setup otpd
     ipareplica_setup_otpd:
       ### server ###
-- 
GitLab