Blame SOURCES/ansible-freeipa-1.9.2-ipaclient-Defer-creating-the-final-krb5.conf-on-clients_RHBZ#2189232.patch

fca774
From 6b5acd9b0c8de965d9b815f8033a2bace9dd737d Mon Sep 17 00:00:00 2001
fca774
From: Thomas Woerner <twoerner@redhat.com>
fca774
Date: Wed, 22 Feb 2023 13:35:18 +0100
fca774
Subject: [PATCH] ipaclient: Defer creating the final krb5.conf on clients
fca774
fca774
A temporary krb5 configuration was used to join the domain in
fca774
ipaclient_join. After that the final krkb5 configuration was created
fca774
with enabled DNS discovery and used for the remainaing tasks, where also
fca774
a connection to the IPA API was done.
fca774
fca774
With several servers the DNS discovery could have picked up a different
fca774
server. If the client deployment was faster than the replication this
fca774
could have lead to an unknown host error.
fca774
fca774
The issue was seen in performance testing where many simultaneous client
fca774
enrollments have been done..
fca774
fca774
The goal is to keep server affinity as long as possible within the
fca774
deployment process:
fca774
fca774
The temporary krb5.conf that was used before in ipaclient_join was
fca774
pulled out into an own module. The generated temporary krb5.conf is now
fca774
used in ipaclient_join and also ipaclient_api.
fca774
fca774
The generation of the final krb5.conf is moved to the end of the
fca774
deployment process.
fca774
fca774
Same as: https://pagure.io/freeipa/issue/9228
fca774
fca774
The setup of certmonger has been pulled out of ipaclient_setup_nss and moved
fca774
to the end of the process after generating the final krb5.conf as it will
fca774
use t will only use /etc/krb5.conf.
fca774
fca774
Certificate issuance may fail during deployment due to using the final
fca774
krb5.conf, but certmonger will re-try the request in this case.
fca774
fca774
Same as: https://pagure.io/freeipa/issue/9246
fca774
---
fca774
 roles/ipaclient/library/ipaclient_api.py      |   8 +
fca774
 roles/ipaclient/library/ipaclient_join.py     |  55 ++----
fca774
 .../library/ipaclient_setup_certmonger.py     | 123 +++++++++++++
fca774
 .../ipaclient/library/ipaclient_setup_nss.py  |   4 +-
fca774
 .../ipaclient/library/ipaclient_temp_krb5.py  | 163 ++++++++++++++++++
fca774
 .../library/ipaclient_test_keytab.py          |   6 +
fca774
 roles/ipaclient/tasks/install.yml             |  69 ++++++--
fca774
 7 files changed, 365 insertions(+), 63 deletions(-)
fca774
 create mode 100644 roles/ipaclient/library/ipaclient_setup_certmonger.py
fca774
 create mode 100644 roles/ipaclient/library/ipaclient_temp_krb5.py
fca774
fca774
diff --git a/roles/ipaclient/library/ipaclient_api.py b/roles/ipaclient/library/ipaclient_api.py
fca774
index 7d4b829..9193f60 100644
fca774
--- a/roles/ipaclient/library/ipaclient_api.py
fca774
+++ b/roles/ipaclient/library/ipaclient_api.py
fca774
@@ -55,6 +55,10 @@ options:
fca774
     type: bool
fca774
     required: no
fca774
     default: no
fca774
+  krb_name:
fca774
+    description: The krb5 config file name
fca774
+    type: str
fca774
+    required: yes
fca774
 author:
fca774
     - Thomas Woerner (@t-woerner)
fca774
 '''
fca774
@@ -65,6 +69,7 @@ EXAMPLES = '''
fca774
     servers: ["server1.example.com","server2.example.com"]
fca774
     domain: example.com
fca774
     hostname: client1.example.com
fca774
+    krb_name: /tmp/tmpkrb5.conf
fca774
   register: result_ipaclient_api
fca774
 '''
fca774
 
fca774
@@ -99,6 +104,7 @@ def main():
fca774
             realm=dict(required=True, type='str'),
fca774
             hostname=dict(required=True, type='str'),
fca774
             debug=dict(required=False, type='bool', default="false"),
fca774
+            krb_name=dict(required=True, type='str'),
fca774
         ),
fca774
         supports_check_mode=False,
fca774
     )
fca774
@@ -110,9 +116,11 @@ def main():
fca774
     realm = module.params.get('realm')
fca774
     hostname = module.params.get('hostname')
fca774
     debug = module.params.get('debug')
fca774
+    krb_name = module.params.get('krb_name')
fca774
 
fca774
     host_principal = 'host/%s@%s' % (hostname, realm)
fca774
     os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE
fca774
+    os.environ['KRB5_CONFIG'] = krb_name
fca774
 
fca774
     ca_certs = x509.load_certificate_list_from_file(paths.IPA_CA_CRT)
fca774
     if 40500 <= NUM_VERSION < 40590:
fca774
diff --git a/roles/ipaclient/library/ipaclient_join.py b/roles/ipaclient/library/ipaclient_join.py
fca774
index 5d41a54..68379ea 100644
fca774
--- a/roles/ipaclient/library/ipaclient_join.py
fca774
+++ b/roles/ipaclient/library/ipaclient_join.py
fca774
@@ -46,10 +46,6 @@ options:
fca774
     type: list
fca774
     elements: str
fca774
     required: yes
fca774
-  domain:
fca774
-    description: Primary DNS domain of the IPA deployment
fca774
-    type: str
fca774
-    required: yes
fca774
   realm:
fca774
     description: Kerberos realm name of the IPA deployment
fca774
     type: str
fca774
@@ -58,10 +54,6 @@ options:
fca774
     description: Fully qualified name of this host
fca774
     type: str
fca774
     required: yes
fca774
-  kdc:
fca774
-    description: The name or address of the host running the KDC
fca774
-    type: str
fca774
-    required: yes
fca774
   basedn:
fca774
     description: The basedn of the IPA server (of the form dc=example,dc=com)
fca774
     type: str
fca774
@@ -102,6 +94,10 @@ options:
fca774
     description: Turn on extra debugging
fca774
     type: bool
fca774
     required: no
fca774
+  krb_name:
fca774
+    description: The krb5 config file name
fca774
+    type: str
fca774
+    required: yes
fca774
 author:
fca774
     - Thomas Woerner (@t-woerner)
fca774
 '''
fca774
@@ -111,27 +107,25 @@ EXAMPLES = '''
fca774
 - name: Join IPA in force mode with maximum 5 kinit attempts
fca774
   ipaclient_join:
fca774
     servers: ["server1.example.com","server2.example.com"]
fca774
-    domain: example.com
fca774
     realm: EXAMPLE.COM
fca774
-    kdc: server1.example.com
fca774
     basedn: dc=example,dc=com
fca774
     hostname: client1.example.com
fca774
     principal: admin
fca774
     password: MySecretPassword
fca774
     force_join: yes
fca774
     kinit_attempts: 5
fca774
+    krb_name: /tmp/tmpkrb5.conf
fca774
 
fca774
 # Join IPA to get the keytab using ipadiscovery return values
fca774
 - name: Join IPA
fca774
   ipaclient_join:
fca774
     servers: "{{ ipadiscovery.servers }}"
fca774
-    domain: "{{ ipadiscovery.domain }}"
fca774
     realm: "{{ ipadiscovery.realm }}"
fca774
-    kdc: "{{ ipadiscovery.kdc }}"
fca774
     basedn: "{{ ipadiscovery.basedn }}"
fca774
     hostname: "{{ ipadiscovery.hostname }}"
fca774
     principal: admin
fca774
     password: MySecretPassword
fca774
+    krb_name: /tmp/tmpkrb5.conf
fca774
 '''
fca774
 
fca774
 RETURN = '''
fca774
@@ -147,9 +141,9 @@ import tempfile
fca774
 from ansible.module_utils.basic import AnsibleModule
fca774
 from ansible.module_utils.ansible_ipa_client import (
fca774
     setup_logging, check_imports,
fca774
-    SECURE_PATH, sysrestore, paths, options, configure_krb5_conf,
fca774
-    realm_to_suffix, kinit_keytab, GSSError, kinit_password, NUM_VERSION,
fca774
-    get_ca_cert, get_ca_certs, errors, run
fca774
+    SECURE_PATH, sysrestore, paths, options, realm_to_suffix, kinit_keytab,
fca774
+    GSSError, kinit_password, NUM_VERSION, get_ca_cert, get_ca_certs, errors,
fca774
+    run
fca774
 )
fca774
 
fca774
 
fca774
@@ -157,10 +151,8 @@ def main():
fca774
     module = AnsibleModule(
fca774
         argument_spec=dict(
fca774
             servers=dict(required=True, type='list', elements='str'),
fca774
-            domain=dict(required=True, type='str'),
fca774
             realm=dict(required=True, type='str'),
fca774
             hostname=dict(required=True, type='str'),
fca774
-            kdc=dict(required=True, type='str'),
fca774
             basedn=dict(required=True, type='str'),
fca774
             principal=dict(required=False, type='str'),
fca774
             password=dict(required=False, type='str', no_log=True),
fca774
@@ -170,6 +162,7 @@ def main():
fca774
             force_join=dict(required=False, type='bool'),
fca774
             kinit_attempts=dict(required=False, type='int', default=5),
fca774
             debug=dict(required=False, type='bool'),
fca774
+            krb_name=dict(required=True, type='str'),
fca774
         ),
fca774
         supports_check_mode=False,
fca774
     )
fca774
@@ -179,11 +172,9 @@ def main():
fca774
     setup_logging()
fca774
 
fca774
     servers = module.params.get('servers')
fca774
-    domain = module.params.get('domain')
fca774
     realm = module.params.get('realm')
fca774
     hostname = module.params.get('hostname')
fca774
     basedn = module.params.get('basedn')
fca774
-    kdc = module.params.get('kdc')
fca774
     force_join = module.params.get('force_join')
fca774
     principal = module.params.get('principal')
fca774
     password = module.params.get('password')
fca774
@@ -192,6 +183,7 @@ def main():
fca774
     ca_cert_file = module.params.get('ca_cert_file')
fca774
     kinit_attempts = module.params.get('kinit_attempts')
fca774
     debug = module.params.get('debug')
fca774
+    krb_name = module.params.get('krb_name')
fca774
 
fca774
     if password is not None and keytab is not None:
fca774
         module.fail_json(msg="Password and keytab cannot be used together")
fca774
@@ -199,12 +191,10 @@ def main():
fca774
     if password is None and admin_keytab is None:
fca774
         module.fail_json(msg="Password or admin_keytab is needed")
fca774
 
fca774
-    client_domain = hostname[hostname.find(".") + 1:]
fca774
     nolog = tuple()
fca774
     env = {'PATH': SECURE_PATH}
fca774
     fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
fca774
     host_principal = 'host/%s@%s' % (hostname, realm)
fca774
-    sssd = True
fca774
 
fca774
     options.ca_cert_file = ca_cert_file
fca774
     options.principal = principal
fca774
@@ -215,19 +205,6 @@ def main():
fca774
     changed = False
fca774
     already_joined = False
fca774
     try:
fca774
-        (krb_fd, krb_name) = tempfile.mkstemp()
fca774
-        os.close(krb_fd)
fca774
-        configure_krb5_conf(
fca774
-            cli_realm=realm,
fca774
-            cli_domain=domain,
fca774
-            cli_server=servers,
fca774
-            cli_kdc=kdc,
fca774
-            dnsok=False,
fca774
-            filename=krb_name,
fca774
-            client_domain=client_domain,
fca774
-            client_hostname=hostname,
fca774
-            configure_sssd=sssd,
fca774
-            force=False)
fca774
         env['KRB5_CONFIG'] = krb_name
fca774
         ccache_dir = tempfile.mkdtemp(prefix='krbcc')
fca774
         ccache_name = os.path.join(ccache_dir, 'ccache')
fca774
@@ -336,27 +313,17 @@ def main():
fca774
                          paths.IPA_DNS_CCACHE,
fca774
                          config=krb_name,
fca774
                          attempts=kinit_attempts)
fca774
-            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE
fca774
         except GSSError as e:
fca774
             # failure to get ticket makes it impossible to login and
fca774
             # bind from sssd to LDAP, abort installation
fca774
             module.fail_json(msg="Failed to obtain host TGT: %s" % e)
fca774
 
fca774
     finally:
fca774
-        try:
fca774
-            os.remove(krb_name)
fca774
-        except OSError:
fca774
-            module.fail_json(msg="Could not remove %s" % krb_name)
fca774
         if ccache_dir is not None:
fca774
             try:
fca774
                 os.rmdir(ccache_dir)
fca774
             except OSError:
fca774
                 pass
fca774
-        if os.path.exists(krb_name + ".ipabkp"):
fca774
-            try:
fca774
-                os.remove(krb_name + ".ipabkp")
fca774
-            except OSError:
fca774
-                module.fail_json(msg="Could not remove %s.ipabkp" % krb_name)
fca774
 
fca774
     module.exit_json(changed=changed,
fca774
                      already_joined=already_joined)
fca774
diff --git a/roles/ipaclient/library/ipaclient_setup_certmonger.py b/roles/ipaclient/library/ipaclient_setup_certmonger.py
fca774
new file mode 100644
fca774
index 0000000..5c81b40
fca774
--- /dev/null
fca774
+++ b/roles/ipaclient/library/ipaclient_setup_certmonger.py
fca774
@@ -0,0 +1,123 @@
fca774
+# -*- coding: utf-8 -*-
fca774
+
fca774
+# Authors:
fca774
+#   Thomas Woerner <twoerner@redhat.com>
fca774
+#
fca774
+# Based on ipa-client-install code
fca774
+#
fca774
+# Copyright (C) 2017-2022  Red Hat
fca774
+# see file 'COPYING' for use and warranty information
fca774
+#
fca774
+# This program is free software; you can redistribute it and/or modify
fca774
+# it under the terms of the GNU General Public License as published by
fca774
+# the Free Software Foundation, either version 3 of the License, or
fca774
+# (at your option) any later version.
fca774
+#
fca774
+# This program is distributed in the hope that it will be useful,
fca774
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
fca774
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
fca774
+# GNU General Public License for more details.
fca774
+#
fca774
+# You should have received a copy of the GNU General Public License
fca774
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
fca774
+
fca774
+from __future__ import (absolute_import, division, print_function)
fca774
+
fca774
+__metaclass__ = type
fca774
+
fca774
+ANSIBLE_METADATA = {
fca774
+    'metadata_version': '1.0',
fca774
+    'supported_by': 'community',
fca774
+    'status': ['preview'],
fca774
+}
fca774
+
fca774
+DOCUMENTATION = '''
fca774
+---
fca774
+module: ipaclient_setup_certmonger
fca774
+short_description: Setup certmonger for IPA client
fca774
+description: Setup certmonger for IPA client
fca774
+options:
fca774
+  realm:
fca774
+    description: Kerberos realm name of the IPA deployment
fca774
+    type: str
fca774
+    required: yes
fca774
+  hostname:
fca774
+    description: Fully qualified name of this host
fca774
+    type: str
fca774
+    required: yes
fca774
+  subject_base:
fca774
+    description: |
fca774
+      The certificate subject base (default O=<realm-name>).
fca774
+      RDNs are in LDAP order (most specific RDN first).
fca774
+    type: str
fca774
+    required: yes
fca774
+  ca_enabled:
fca774
+    description: Whether the Certificate Authority is enabled or not
fca774
+    type: bool
fca774
+    required: yes
fca774
+  request_cert:
fca774
+    description: Request certificate for the machine
fca774
+    type: bool
fca774
+    required: yes
fca774
+author:
fca774
+    - Thomas Woerner (@t-woerner)
fca774
+'''
fca774
+
fca774
+EXAMPLES = '''
fca774
+- name: Setup certmonger for IPA client
fca774
+  ipaclient_setup_certmonger:
fca774
+    realm: EXAMPLE.COM
fca774
+    hostname: client1.example.com
fca774
+    subject_base: O=EXAMPLE.COM
fca774
+    ca_enabled: true
fca774
+    request_cert: false
fca774
+'''
fca774
+
fca774
+RETURN = '''
fca774
+'''
fca774
+
fca774
+from ansible.module_utils.basic import AnsibleModule
fca774
+from ansible.module_utils.ansible_ipa_client import (
fca774
+    setup_logging, check_imports,
fca774
+    options, sysrestore, paths, ScriptError, configure_certmonger
fca774
+)
fca774
+
fca774
+
fca774
+def main():
fca774
+    module = AnsibleModule(
fca774
+        argument_spec=dict(
fca774
+            realm=dict(required=True, type='str'),
fca774
+            hostname=dict(required=True, type='str'),
fca774
+            subject_base=dict(required=True, type='str'),
fca774
+            ca_enabled=dict(required=True, type='bool'),
fca774
+            request_cert=dict(required=True, type='bool'),
fca774
+        ),
fca774
+        supports_check_mode=False,
fca774
+    )
fca774
+
fca774
+    module._ansible_debug = True
fca774
+    check_imports(module)
fca774
+    setup_logging()
fca774
+
fca774
+    cli_realm = module.params.get('realm')
fca774
+    hostname = module.params.get('hostname')
fca774
+    subject_base = module.params.get('subject_base')
fca774
+    ca_enabled = module.params.get('ca_enabled')
fca774
+
fca774
+    fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
fca774
+
fca774
+    options.request_cert = module.params.get('request_cert')
fca774
+    options.hostname = hostname
fca774
+
fca774
+    try:
fca774
+        configure_certmonger(fstore, subject_base, cli_realm, hostname,
fca774
+                             options, ca_enabled)
fca774
+
fca774
+    except ScriptError as e:
fca774
+        module.fail_json(msg=str(e))
fca774
+
fca774
+    module.exit_json(changed=True)
fca774
+
fca774
+
fca774
+if __name__ == '__main__':
fca774
+    main()
fca774
diff --git a/roles/ipaclient/library/ipaclient_setup_nss.py b/roles/ipaclient/library/ipaclient_setup_nss.py
fca774
index 3dc0dcc..240bc76 100644
fca774
--- a/roles/ipaclient/library/ipaclient_setup_nss.py
fca774
+++ b/roles/ipaclient/library/ipaclient_setup_nss.py
fca774
@@ -177,7 +177,7 @@ from ansible.module_utils.ansible_ipa_client import (
fca774
     options, sysrestore, paths, ansible_module_get_parsed_ip_addresses,
fca774
     api, errors, create_ipa_nssdb, ipautil, ScriptError, CLIENT_INSTALL_ERROR,
fca774
     get_certs_from_ldap, DN, certstore, x509, logger, certdb,
fca774
-    CalledProcessError, tasks, client_dns, configure_certmonger, services,
fca774
+    CalledProcessError, tasks, client_dns, services,
fca774
     update_ssh_keys, save_state, configure_ldap_conf, configure_nslcd_conf,
fca774
     configure_openldap_conf, hardcode_ldap_server, getargspec, NUM_VERSION,
fca774
     serialization
fca774
@@ -350,8 +350,6 @@ def main():
fca774
 
fca774
         if not options.on_master:
fca774
             client_dns(cli_server[0], hostname, options)
fca774
-            configure_certmonger(fstore, subject_base, cli_realm, hostname,
fca774
-                                 options, ca_enabled)
fca774
 
fca774
         if hasattr(paths, "SSH_CONFIG_DIR"):
fca774
             ssh_config_dir = paths.SSH_CONFIG_DIR
fca774
diff --git a/roles/ipaclient/library/ipaclient_temp_krb5.py b/roles/ipaclient/library/ipaclient_temp_krb5.py
fca774
new file mode 100644
fca774
index 0000000..cbe652c
fca774
--- /dev/null
fca774
+++ b/roles/ipaclient/library/ipaclient_temp_krb5.py
fca774
@@ -0,0 +1,163 @@
fca774
+# -*- coding: utf-8 -*-
fca774
+
fca774
+# Authors:
fca774
+#   Thomas Woerner <twoerner@redhat.com>
fca774
+#
fca774
+# Based on ipa-client-install code
fca774
+#
fca774
+# Copyright (C) 2017-2022  Red Hat
fca774
+# see file 'COPYING' for use and warranty information
fca774
+#
fca774
+# This program is free software; you can redistribute it and/or modify
fca774
+# it under the terms of the GNU General Public License as published by
fca774
+# the Free Software Foundation, either version 3 of the License, or
fca774
+# (at your option) any later version.
fca774
+#
fca774
+# This program is distributed in the hope that it will be useful,
fca774
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
fca774
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
fca774
+# GNU General Public License for more details.
fca774
+#
fca774
+# You should have received a copy of the GNU General Public License
fca774
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
fca774
+
fca774
+from __future__ import (absolute_import, division, print_function)
fca774
+
fca774
+__metaclass__ = type
fca774
+
fca774
+ANSIBLE_METADATA = {
fca774
+    'metadata_version': '1.0',
fca774
+    'supported_by': 'community',
fca774
+    'status': ['preview'],
fca774
+}
fca774
+
fca774
+DOCUMENTATION = '''
fca774
+---
fca774
+module: ipaclient_temp_krb5
fca774
+short_description:
fca774
+  Create temporary krb5 configuration.
fca774
+description:
fca774
+  Create temporary krb5 configuration for deferring the creation of the final
fca774
+  krb5.conf on clients
fca774
+options:
fca774
+  servers:
fca774
+    description: Fully qualified name of IPA servers to enroll to
fca774
+    type: list
fca774
+    elements: str
fca774
+    required: yes
fca774
+  domain:
fca774
+    description: Primary DNS domain of the IPA deployment
fca774
+    type: str
fca774
+    required: yes
fca774
+  realm:
fca774
+    description: Kerberos realm name of the IPA deployment
fca774
+    type: str
fca774
+    required: yes
fca774
+  hostname:
fca774
+    description: Fully qualified name of this host
fca774
+    type: str
fca774
+    required: yes
fca774
+  kdc:
fca774
+    description: The name or address of the host running the KDC
fca774
+    type: str
fca774
+    required: yes
fca774
+  on_master:
fca774
+    description: Whether the configuration is done on the master or not
fca774
+    type: bool
fca774
+    required: no
fca774
+    default: no
fca774
+author:
fca774
+    - Thomas Woerner (@t-woerner)
fca774
+'''
fca774
+
fca774
+EXAMPLES = '''
fca774
+# Test IPA with local keytab
fca774
+- name: Test IPA in force mode with maximum 5 kinit attempts
fca774
+  ipaclient_test_keytab:
fca774
+    servers: ["server1.example.com","server2.example.com"]
fca774
+    domain: example.com
fca774
+    realm: EXAMPLE.COM
fca774
+    kdc: server1.example.com
fca774
+    hostname: client1.example.com
fca774
+
fca774
+# Test IPA with ipadiscovery return values
fca774
+- name: Join IPA
fca774
+  ipaclient_test_keytab:
fca774
+    servers: "{{ ipadiscovery.servers }}"
fca774
+    domain: "{{ ipadiscovery.domain }}"
fca774
+    realm: "{{ ipadiscovery.realm }}"
fca774
+    kdc: "{{ ipadiscovery.kdc }}"
fca774
+    hostname: "{{ ipadiscovery.hostname }}"
fca774
+'''
fca774
+
fca774
+RETURN = '''
fca774
+krb_name:
fca774
+  description: The krb5 config file name
fca774
+  returned: always
fca774
+  type: str
fca774
+'''
fca774
+
fca774
+import os
fca774
+import tempfile
fca774
+
fca774
+from ansible.module_utils.basic import AnsibleModule
fca774
+from ansible.module_utils.ansible_ipa_client import (
fca774
+    setup_logging, check_imports, configure_krb5_conf
fca774
+)
fca774
+
fca774
+
fca774
+def main():
fca774
+    module = AnsibleModule(
fca774
+        argument_spec=dict(
fca774
+            servers=dict(required=True, type='list', elements='str'),
fca774
+            domain=dict(required=True, type='str'),
fca774
+            realm=dict(required=True, type='str'),
fca774
+            hostname=dict(required=True, type='str'),
fca774
+            kdc=dict(required=True, type='str'),
fca774
+            on_master=dict(required=False, type='bool', default=False),
fca774
+        ),
fca774
+        supports_check_mode=False,
fca774
+    )
fca774
+
fca774
+    module._ansible_debug = True
fca774
+    check_imports(module)
fca774
+    setup_logging()
fca774
+
fca774
+    servers = module.params.get('servers')
fca774
+    domain = module.params.get('domain')
fca774
+    realm = module.params.get('realm')
fca774
+    hostname = module.params.get('hostname')
fca774
+    kdc = module.params.get('kdc')
fca774
+    client_domain = hostname[hostname.find(".") + 1:]
fca774
+
fca774
+    krb_name = None
fca774
+    # Create temporary krb5 configuration
fca774
+    try:
fca774
+        (krb_fd, krb_name) = tempfile.mkstemp()
fca774
+        os.close(krb_fd)
fca774
+        configure_krb5_conf(
fca774
+            cli_realm=realm,
fca774
+            cli_domain=domain,
fca774
+            cli_server=servers,
fca774
+            cli_kdc=kdc,
fca774
+            dnsok=False,
fca774
+            filename=krb_name,
fca774
+            client_domain=client_domain,
fca774
+            client_hostname=hostname,
fca774
+            configure_sssd=True,
fca774
+            force=False)
fca774
+    except Exception as ex:
fca774
+        if krb_name:
fca774
+            try:
fca774
+                os.remove(krb_name)
fca774
+            except OSError:
fca774
+                module.fail_json(msg="Could not remove %s" % krb_name)
fca774
+        module.fail_json(
fca774
+            msg="Failed to create temporary krb5 configuration: %s" % str(ex))
fca774
+
fca774
+    module.exit_json(changed=False,
fca774
+                     krb_name=krb_name)
fca774
+
fca774
+
fca774
+if __name__ == '__main__':
fca774
+    main()
fca774
diff --git a/roles/ipaclient/library/ipaclient_test_keytab.py b/roles/ipaclient/library/ipaclient_test_keytab.py
fca774
index 3f1c69d..3bebeea 100644
fca774
--- a/roles/ipaclient/library/ipaclient_test_keytab.py
fca774
+++ b/roles/ipaclient/library/ipaclient_test_keytab.py
fca774
@@ -244,6 +244,12 @@ def main():
fca774
                 os.remove(krb_name)
fca774
             except OSError:
fca774
                 module.fail_json(msg="Could not remove %s" % krb_name)
fca774
+            if os.path.exists(krb_name + ".ipabkp"):
fca774
+                try:
fca774
+                    os.remove(krb_name + ".ipabkp")
fca774
+                except OSError:
fca774
+                    module.fail_json(
fca774
+                        msg="Could not remove %s.ipabkp" % krb_name)
fca774
 
fca774
     module.exit_json(changed=False,
fca774
                      krb5_keytab_ok=krb5_keytab_ok,
fca774
diff --git a/roles/ipaclient/tasks/install.yml b/roles/ipaclient/tasks/install.yml
fca774
index fa33f89..1b889d0 100644
fca774
--- a/roles/ipaclient/tasks/install.yml
fca774
+++ b/roles/ipaclient/tasks/install.yml
fca774
@@ -239,12 +239,19 @@
fca774
       hostname: "{{ result_ipaclient_test.hostname }}"
fca774
     when: not ipaclient_on_master | bool
fca774
 
fca774
-  - name: Install - Join IPA
fca774
-    ipaclient_join:
fca774
+  - name: Install - Create temporary krb5 configuration
fca774
+    ipaclient_temp_krb5:
fca774
       servers: "{{ result_ipaclient_test.servers }}"
fca774
       domain: "{{ result_ipaclient_test.domain }}"
fca774
       realm: "{{ result_ipaclient_test.realm }}"
fca774
+      hostname: "{{ result_ipaclient_test.hostname }}"
fca774
       kdc: "{{ result_ipaclient_test.kdc }}"
fca774
+    register: result_ipaclient_temp_krb5
fca774
+
fca774
+  - name: Install - Join IPA
fca774
+    ipaclient_join:
fca774
+      servers: "{{ result_ipaclient_test.servers }}"
fca774
+      realm: "{{ result_ipaclient_test.realm }}"
fca774
       basedn: "{{ result_ipaclient_test.basedn }}"
fca774
       hostname: "{{ result_ipaclient_test.hostname }}"
fca774
       force_join: "{{ ipaclient_force_join | default(omit) }}"
fca774
@@ -255,6 +262,7 @@
fca774
       admin_keytab: "{{ ipaadmin_keytab if ipaadmin_keytab is defined and not ipaclient_use_otp | bool else omit }}"
fca774
       # ca_cert_file: "{{ ipaclient_ca_cert_file | default(omit) }}"
fca774
       kinit_attempts: "{{ ipaclient_kinit_attempts | default(omit) }}"
fca774
+      krb_name: "{{ result_ipaclient_temp_krb5.krb_name }}"
fca774
     register: result_ipaclient_join
fca774
     when: not ipaclient_on_master | bool and
fca774
           (not result_ipaclient_test_keytab.krb5_keytab_ok or
fca774
@@ -323,26 +331,13 @@
fca774
           "{{ ipassd_no_krb5_offline_passwords
fca774
               | default(ipasssd_no_krb5_offline_passwords) }}"
fca774
 
fca774
-    - name: Install - Configure krb5 for IPA realm
fca774
-      ipaclient_setup_krb5:
fca774
-        realm: "{{ result_ipaclient_test.realm }}"
fca774
-        domain: "{{ result_ipaclient_test.domain }}"
fca774
-        servers: "{{ result_ipaclient_test.servers }}"
fca774
-        kdc: "{{ result_ipaclient_test.kdc }}"
fca774
-        dnsok: "{{ result_ipaclient_test.dnsok }}"
fca774
-        client_domain: "{{ result_ipaclient_test.client_domain }}"
fca774
-        hostname: "{{ result_ipaclient_test.hostname }}"
fca774
-        sssd: "{{ result_ipaclient_test.sssd }}"
fca774
-        force: "{{ ipaclient_force }}"
fca774
-        # on_master: "{{ ipaclient_on_master }}"
fca774
-      when: not ipaclient_on_master | bool
fca774
-
fca774
     - name: Install - IPA API calls for remaining enrollment parts
fca774
       ipaclient_api:
fca774
         servers: "{{ result_ipaclient_test.servers }}"
fca774
         realm: "{{ result_ipaclient_test.realm }}"
fca774
         hostname: "{{ result_ipaclient_test.hostname }}"
fca774
         # debug: yes
fca774
+        krb_name: "{{ result_ipaclient_temp_krb5.krb_name }}"
fca774
       register: result_ipaclient_api
fca774
 
fca774
     - name: Install - Fix IPA ca
fca774
@@ -412,6 +407,36 @@
fca774
         domain: "{{ result_ipaclient_test.domain }}"
fca774
         nisdomain: "{{ ipaclient_nisdomain | default(omit) }}"
fca774
       when: not ipaclient_no_nisdomain | bool
fca774
+
fca774
+    - name: Remove temporary krb5.conf
fca774
+      ansible.builtin.file:
fca774
+        path: "{{ result_ipaclient_temp_krb5.krb_name }}"
fca774
+        state: absent
fca774
+      when: result_ipaclient_temp_krb5.krb_name is defined
fca774
+
fca774
+    - name: Install - Configure krb5 for IPA realm
fca774
+      ipaclient_setup_krb5:
fca774
+        realm: "{{ result_ipaclient_test.realm }}"
fca774
+        domain: "{{ result_ipaclient_test.domain }}"
fca774
+        servers: "{{ result_ipaclient_test.servers }}"
fca774
+        kdc: "{{ result_ipaclient_test.kdc }}"
fca774
+        dnsok: "{{ result_ipaclient_test.dnsok }}"
fca774
+        client_domain: "{{ result_ipaclient_test.client_domain }}"
fca774
+        hostname: "{{ result_ipaclient_test.hostname }}"
fca774
+        sssd: "{{ result_ipaclient_test.sssd }}"
fca774
+        force: "{{ ipaclient_force }}"
fca774
+        # on_master: "{{ ipaclient_on_master }}"
fca774
+      when: not ipaclient_on_master | bool
fca774
+
fca774
+    - name: Install - Configure certmonger
fca774
+      ipaclient_setup_certmonger:
fca774
+        realm: "{{ result_ipaclient_test.realm }}"
fca774
+        hostname: "{{ result_ipaclient_test.hostname }}"
fca774
+        subject_base: "{{ result_ipaclient_api.subject_base }}"
fca774
+        ca_enabled: "{{ result_ipaclient_api.ca_enabled }}"
fca774
+        request_cert: "{{ ipaclient_request_cert }}"
fca774
+      when: not ipaclient_on_master | bool
fca774
+
fca774
   always:
fca774
   - name: Install - Restore original admin password if overwritten by OTP
fca774
     no_log: yes
fca774
@@ -423,3 +448,15 @@
fca774
     ansible.builtin.file:
fca774
       path: "/etc/ipa/.dns_ccache"
fca774
       state: absent
fca774
+
fca774
+  - name: Remove temporary krb5.conf
fca774
+    ansible.builtin.file:
fca774
+      path: "{{ result_ipaclient_temp_krb5.krb_name }}"
fca774
+      state: absent
fca774
+    when: result_ipaclient_temp_krb5.krb_name is defined
fca774
+
fca774
+  - name: Remove temporary krb5.conf backup
fca774
+    ansible.builtin.file:
fca774
+      path: "{{ result_ipaclient_temp_krb5.krb_name }}.ipabkp"
fca774
+      state: absent
fca774
+    when: result_ipaclient_temp_krb5.krb_name is defined
fca774
-- 
fca774
2.39.2
fca774