diff --git a/roles/ipaserver/README.md b/roles/ipaserver/README.md index 05d8b583b8b2eb6bef3d0f8c405a5ce9dda85f56..40dc58b6e26bfb64ada58b0175baab427538fa07 100644 --- a/roles/ipaserver/README.md +++ b/roles/ipaserver/README.md @@ -42,11 +42,11 @@ Requirements Limitations ----------- -External CA +External signed CA -External CA support is not supported or working. The currently needed two step process is an issue for the processing in the role. The configuration of the server is partly done already and needs to be continued after the CSR has been handled. This is for example breaking the deployment of a server with replicas or clients in one playbook. +External signed CA is now supported. But the currently needed two step process is an issue for the processing in a simple playbook. -Work is planned to have a new method to handle CSR for external CAs in a separate step before starting the server installation. +Work is planned to have a new method to handle CSR for external signed CAs in a separate step before starting the server installation. Usage @@ -106,6 +106,56 @@ Example playbook to setup the IPA server using admin and dirman passwords from i - role: ipaserver state: present +Example playbook to setup the IPA primary with external signed CA using the previous inventory file: + +Server installation step 1: Generate CSR, copy to controller as `<ipaserver hostname>-ipa.csr` + +```yaml +--- +- name: Playbook to configure IPA server step1 + hosts: ipaserver + become: true + vars: + ipaserver_external_ca: yes + + roles: + - role: ipaserver + state: present + + post_tasks: + - name: Copy CSR /root/ipa.csr from node to "{{ groups.ipaserver[0] + '-ipa.csr' }}" + fetch: + src: /root/ipa.csr + dest: "{{ groups.ipaserver[0] + '-ipa.csr' }}" + flat: yes +``` + +Sign with CA: This is up to you + +Server installatin step 2: Copy `<ipaserver hostname>-chain.crt` to the IPA server and continue with installation of the primary. + +```yaml +- name: Playbook to configure IPA server step3 + hosts: ipaserver + become: true + vars: + ipaserver_external_cert_files: "/root/chain.crt" + + pre_tasks: + - name: Copy "{{ groups.ipaserver[0] + '-chain.crt' }}" to /root/chain.crt on node + copy: + src: "{{ groups.ipaserver[0] + '-chain.crt' }}" + dest: "/root/chain.crt" + force: yes + + roles: + - role: ipaserver + state: present +``` + +The files can also be copied automatically: Set `ipaserver_copy_csr_to_controller` to true in the server installation step 1 and set `ipaserver_external_cert_files_from_controller` to point to the `chain.crt` file in the server installatin step 2. + + Playbooks ========= @@ -192,13 +242,13 @@ Certificate system Variables Variable | Description | Required -------- | ----------- | -------- -~~`ipaserver_external_ca`~~ | ~~Generate a CSR for the IPA CA certificate to be signed by an external CA. (bool, default: false)~~ | ~~no~~ -~~`ipaserver_external_ca_type`~~ | ~~Type of the external CA. (choice: generic,ms-cs)~~ | ~~no~~ -~~`ipaserver_external_ca_profile`~~ | ~~Specify the certificate profile/template to use at the external CA. (string)~~ | ~~no~~ -~~`ipaserver_external_cert_files`~~ | ~~Files containing the IPA CA certificates and the external CA certificate chains (list of string)~~ | ~~no~~ +`ipaserver_external_ca` | Generate a CSR for the IPA CA certificate to be signed by an external CA. (bool, default: false) | no +`ipaserver_external_ca_type` | Type of the external CA. (choice: generic,ms-cs) | no +`ipaserver_external_ca_profile` | Specify the certificate profile/template to use at the external CA. (string) | no +`ipaserver_external_cert_files` | Files containing the IPA CA certificates and the external CA certificate chains (list of string) | no `ipaserver_subject_base` | The certificate subject base (default O=<realm-name>). RDNs are in LDAP order (most specific RDN first). (string) | no `ipaserver_ca_subject` | The CA certificate subject DN (default CN=Certificate Authority,O=<realm-name>). RDNs are in LDAP order (most specific RDN first). (string) | no -~~`ipaserver_ca_signing_algorithm`~~ | ~~Signing algorithm of the IPA CA certificate. (choice: SHA1withRSA,SHA256withRSA,SHA512withRSA)~~ | ~~no~~ +`ipaserver_ca_signing_algorithm` | Signing algorithm of the IPA CA certificate. (choice: SHA1withRSA,SHA256withRSA,SHA512withRSA) | no DNS Variables ------------- @@ -233,7 +283,8 @@ Variable | Description | Required -------- | ----------- | -------- `ipaserver_install_packages` | The bool value defines if the needed packages are installed on the node. (bool, default: true) | no `ipaserver_setup_firewalld` | The value defines if the needed services will automatically be openen in the firewall managed by firewalld. (bool, default: true) | no - +`ipaserver_external_cert_files_from_controller` | Files containing the IPA CA certificates and the external CA certificate chains on the controller that will be copied to the ipaserver host to `/root` folder. (list of string) | no +`ipaserver_copy_csr_to_controller` | Copy the generated CSR from the ipaserver to the controller as `"{{ inventory_hostname }}-ipa.csr"`. (bool) | no Authors ======= diff --git a/roles/ipaserver/defaults/main.yml b/roles/ipaserver/defaults/main.yml index 57d611e04619637c4c73be92506afe85d40b6a9d..ed1364b7d30007e5a7a5df52cfbc1240412bf279 100644 --- a/roles/ipaserver/defaults/main.yml +++ b/roles/ipaserver/defaults/main.yml @@ -36,7 +36,7 @@ ipaserver_install_packages: yes ipaserver_setup_firewalld: yes ### additional ### -ipaserver_allow_missing: [ ] +ipaserver_copy_csr_to_controller: no ### uninstall ### ipaserver_ignore_topology_disconnect: no diff --git a/roles/ipaserver/library/ipaserver_prepare.py b/roles/ipaserver/library/ipaserver_prepare.py index 62f46331512d6e30e331e839687447720bb6324e..83e10c1e53b15ec657a65c52eda249694545095a 100644 --- a/roles/ipaserver/library/ipaserver_prepare.py +++ b/roles/ipaserver/library/ipaserver_prepare.py @@ -97,7 +97,9 @@ def main(): ### ssl certificate ### ### client ### ### certificate system ### - external_ca=dict(required=False), + external_ca=dict(required=False, type='bool'), + external_ca_type=dict(required=False), + external_ca_profile=dict(required=False), external_cert_files=dict(required=False, type='list', default=[]), subject_base=dict(required=False), ca_subject=dict(required=False), @@ -152,6 +154,9 @@ def main(): #options.no_ntp = ansible_module.params.get('no_ntp') ### certificate system ### options.external_ca = ansible_module.params.get('external_ca') + options.external_ca_type = ansible_module.params.get('external_ca_type') + options.external_ca_profile = ansible_module.params.get( + 'external_ca_profile') options.external_cert_files = ansible_module.params.get( 'external_cert_files') options.subject_base = ansible_module.params.get('subject_base') diff --git a/roles/ipaserver/library/ipaserver_setup_ca.py b/roles/ipaserver/library/ipaserver_setup_ca.py index 50ca0e3e111ae9cafd5bbbb59404d2c578e75ebe..14b8bae03c7bcf6ec1001be8233ecad660b6fa52 100644 --- a/roles/ipaserver/library/ipaserver_setup_ca.py +++ b/roles/ipaserver/library/ipaserver_setup_ca.py @@ -106,7 +106,9 @@ def main(): _dirsrv_pkcs12_info=dict(required=False), ### certificate system ### external_ca=dict(required=False, type='bool', default=False), - external_cert_files=dict(required=False, type='list', default=[]), + external_ca_type=dict(required=False), + external_ca_profile=dict(required=False), + external_cert_files=dict(required=False, type='list', default=None), subject_base=dict(required=False), _subject_base=dict(required=False), ca_subject=dict(required=False), @@ -154,6 +156,9 @@ def main(): '_dirsrv_pkcs12_info') ### certificate system ### options.external_ca = ansible_module.params.get('external_ca') + options.external_ca_type = ansible_module.params.get('external_ca_type') + options.external_ca_profile = ansible_module.params.get( + 'external_ca_profile') options.external_cert_files = ansible_module.params.get( 'external_cert_files') options.subject_base = ansible_module.params.get('subject_base') @@ -175,6 +180,13 @@ def main(): options.promote = False # first master, no promotion + # Repeat from ca.install_check + # ca.external_cert_file and ca.external_ca_file need to be set + if options.external_cert_files: + ca.external_cert_file, ca.external_ca_file = \ + installutils.load_external_cert( + options.external_cert_files, options._ca_subject) + fstore = sysrestore.FileStore(paths.SYSRESTORE) api_Backend_ldap2(options.host_name, options.setup_ca, connect=True) @@ -190,53 +202,61 @@ def main(): # setup CA ############################################################## - with redirect_stdout(ansible_log): - if hasattr(custodiainstance, "get_custodia_instance"): - if hasattr(custodiainstance.CustodiaModes, "FIRST_MASTER"): - mode = custodiainstance.CustodiaModes.FIRST_MASTER - else: - mode = custodiainstance.CustodiaModes.MASTER_PEER - custodia = custodiainstance.get_custodia_instance(options, mode) + if hasattr(custodiainstance, "get_custodia_instance"): + if hasattr(custodiainstance.CustodiaModes, "FIRST_MASTER"): + mode = custodiainstance.CustodiaModes.FIRST_MASTER + else: + mode = custodiainstance.CustodiaModes.MASTER_PEER + custodia = custodiainstance.get_custodia_instance(options, mode) + custodia.set_output(ansible_log) + with redirect_stdout(ansible_log): custodia.create_instance() - if options.setup_ca: - if not options.external_cert_files and options.external_ca: - # stage 1 of external CA installation - cache_vars = {n: options.__dict__[n] for o, n in options.knobs() - if n in options.__dict__} - write_cache(cache_vars) + if options.setup_ca: + if not options.external_cert_files and options.external_ca: + # stage 1 of external CA installation + cache_vars = {n: options.__dict__[n] for o, n in options.knobs() + if n in options.__dict__} + write_cache(cache_vars) - if hasattr(custodiainstance, "get_custodia_instance"): - ca.install_step_0(False, None, options, custodia=custodia) - else: - ca.install_step_0(False, None, options) - else: - # Put the CA cert where other instances expect it - x509.write_certificate(options._http_ca_cert, paths.IPA_CA_CRT) - os.chmod(paths.IPA_CA_CRT, 0o444) + try: + with redirect_stdout(ansible_log): + if hasattr(custodiainstance, "get_custodia_instance"): + ca.install_step_0(False, None, options, custodia=custodia) + else: + ca.install_step_0(False, None, options) + except SystemExit: + ansible_module.exit_json(changed=True, + csr_generated=True) + else: + # Put the CA cert where other instances expect it + x509.write_certificate(options._http_ca_cert, paths.IPA_CA_CRT) + os.chmod(paths.IPA_CA_CRT, 0o444) - if not options.no_pkinit: - x509.write_certificate(options._http_ca_cert, - paths.KDC_CA_BUNDLE_PEM) - else: - with open(paths.KDC_CA_BUNDLE_PEM, 'w'): - pass - os.chmod(paths.KDC_CA_BUNDLE_PEM, 0o444) + if not options.no_pkinit: + x509.write_certificate(options._http_ca_cert, + paths.KDC_CA_BUNDLE_PEM) + else: + with open(paths.KDC_CA_BUNDLE_PEM, 'w'): + pass + os.chmod(paths.KDC_CA_BUNDLE_PEM, 0o444) - x509.write_certificate(options._http_ca_cert, paths.CA_BUNDLE_PEM) - os.chmod(paths.CA_BUNDLE_PEM, 0o444) + x509.write_certificate(options._http_ca_cert, paths.CA_BUNDLE_PEM) + os.chmod(paths.CA_BUNDLE_PEM, 0o444) + with redirect_stdout(ansible_log): # we now need to enable ssl on the ds ds.enable_ssl() - if options.setup_ca: - with redirect_stdout(ansible_log): - if hasattr(custodiainstance, "get_custodia_instance"): - ca.install_step_1(False, None, options, custodia=custodia) - else: - ca.install_step_1(False, None, options) + if options.setup_ca: + with redirect_stdout(ansible_log): + if hasattr(custodiainstance, "get_custodia_instance"): + ca.install_step_1(False, None, options, custodia=custodia) + else: + ca.install_step_1(False, None, options) - ansible_module.exit_json(changed=True) + ansible_module.exit_json(changed=True, + csr_generated=False) if __name__ == '__main__': main() diff --git a/roles/ipaserver/library/ipaserver_test.py b/roles/ipaserver/library/ipaserver_test.py index caf462141e9b9a319f3501628906eb7ab08dc309..65d0a9296d2a362ab63eeed5f127cb292af08c1e 100644 --- a/roles/ipaserver/library/ipaserver_test.py +++ b/roles/ipaserver/library/ipaserver_test.py @@ -77,15 +77,15 @@ def main(): # no_ui_redirect dirsrv_config_file=dict(required=False), ### ssl certificate ### - dirsrv_cert_files=dict(required=False, type='list', default=[]), - http_cert_files=dict(required=False, type='list', default=[]), - pkinit_cert_files=dict(required=False, type='list', default=[]), - # dirsrv_pin - # http_pin - # pkinit_pin - # dirsrv_name - # http_name - # pkinit_name + dirsrv_cert_files=dict(required=False, type='list', default=None), + http_cert_files=dict(required=False, type='list', defaullt=None), + pkinit_cert_files=dict(required=False, type='list', default=None), + dirsrv_pin=dict(required=False), + http_pin=dict(required=False), + pkinit_pin=dict(required=False), + dirsrv_cert_name=dict(required=False), + http_cert_name=dict(required=False), + pkinit_cert_name=dict(required=False), ### client ### # mkhomedir no_ntp=dict(required=False, type='bool', default=False), @@ -96,7 +96,8 @@ def main(): ### certificate system ### external_ca=dict(required=False, type='bool', default=False), external_ca_type=dict(required=False), - external_cert_files=dict(required=False, type='list', default=[]), + external_ca_profile=dict(required=False), + external_cert_files=dict(required=False, type='list', default=None), subject_base=dict(required=False), ca_subject=dict(required=False), # ca_signing_algorithm @@ -155,12 +156,12 @@ def main(): options.dirsrv_cert_files = ansible_module.params.get('dirsrv_cert_files') options.http_cert_files = ansible_module.params.get('http_cert_files') options.pkinit_cert_files = ansible_module.params.get('pkinit_cert_files') - # dirsrv_pin - # http_pin - # pkinit_pin - # dirsrv_name - # http_name - # pkinit_name + options.dirsrv_pin = ansible_module.params.get('dirsrv_pin'), + options.http_pin = ansible_module.params.get('http_pin'), + options.pkinit_pin = ansible_module.params.get('pkinit_pin'), + options.dirsrv_cert_name = ansible_module.params.get('dirsrv_cert_name'), + options.http_cert_name = ansible_module.params.get('http_cert_name'), + options.pkinit_cert_name = ansible_module.params.get('pkinit_cert_name'), ### client ### # mkhomedir options.no_ntp = ansible_module.params.get('no_ntp') @@ -171,6 +172,8 @@ def main(): ### certificate system ### options.external_ca = ansible_module.params.get('external_ca') options.external_ca_type = ansible_module.params.get('external_ca_type') + options.external_ca_profile = ansible_module.params.get( + 'external_ca_profile') options.external_cert_files = ansible_module.params.get( 'external_cert_files') options.subject_base = ansible_module.params.get('subject_base') @@ -226,25 +229,6 @@ def main(): ansible_module.fail_json( msg="pki_config_override: %s" % str(e)) - # validation ############################################################# - - if options.dm_password is None: - ansible_module.fail_json(msg="Directory Manager password required") - - if options.admin_password is None: - ansible_module.fail_json(msg="IPA admin password required") - - # This will override any settings passed in on the cmdline - if os.path.isfile(paths.ROOT_IPA_CACHE): - # dm_password check removed, checked already - try: - cache_vars = read_cache(options.dm_password) - options.__dict__.update(cache_vars) - if cache_vars.get('external_ca', False): - options.external_ca = False - options.interactive = False - except Exception as e: - ansible_module.fail_json(msg="Cannot process the cache file: %s" % str(e)) # default values ######################################################## # idstart and idmax @@ -253,50 +237,190 @@ def main(): if options.idmax is None or options.idmax == 0: options.idmax = options.idstart + 199999 - # validation ############################################################ + #class ServerInstallInterface(ServerCertificateInstallInterface, + # client.ClientInstallInterface, + # ca.CAInstallInterface, + # kra.KRAInstallInterface, + # dns.DNSInstallInterface, + # adtrust.ADTrustInstallInterface, + # conncheck.ConnCheckInterface, + # ServerUninstallInterface): + + # ServerInstallInterface.__init__ ####################################### + try: + self = options + + # If any of the key file options are selected, all are required. + cert_file_req = (self.dirsrv_cert_files, self.http_cert_files) + cert_file_opt = (self.pkinit_cert_files,) + if not self.no_pkinit: + cert_file_req += cert_file_opt + if self.no_pkinit and self.pkinit_cert_files: + raise RuntimeError( + "--no-pkinit and --pkinit-cert-file cannot be specified " + "together" + ) + if any(cert_file_req + cert_file_opt) and not all(cert_file_req): + raise RuntimeError( + "--dirsrv-cert-file, --http-cert-file, and --pkinit-cert-file " + "or --no-pkinit are required if any key file options are used." + ) + + if not self.interactive: + if self.dirsrv_cert_files and self.dirsrv_pin is None: + raise RuntimeError( + "You must specify --dirsrv-pin with --dirsrv-cert-file") + if self.http_cert_files and self.http_pin is None: + raise RuntimeError( + "You must specify --http-pin with --http-cert-file") + if self.pkinit_cert_files and self.pkinit_pin is None: + raise RuntimeError( + "You must specify --pkinit-pin with --pkinit-cert-file") + + if not self.setup_dns: + if self.forwarders: + raise RuntimeError( + "You cannot specify a --forwarder option without the " + "--setup-dns option") + if self.auto_forwarders: + raise RuntimeError( + "You cannot specify a --auto-forwarders option without " + "the --setup-dns option") + if self.no_forwarders: + raise RuntimeError( + "You cannot specify a --no-forwarders option without the " + "--setup-dns option") + if self.forward_policy: + raise RuntimeError( + "You cannot specify a --forward-policy option without the " + "--setup-dns option") + if self.reverse_zones: + raise RuntimeError( + "You cannot specify a --reverse-zone option without the " + "--setup-dns option") + if self.auto_reverse: + raise RuntimeError( + "You cannot specify a --auto-reverse option without the " + "--setup-dns option") + if self.no_reverse: + raise RuntimeError( + "You cannot specify a --no-reverse option without the " + "--setup-dns option") + if self.no_dnssec_validation: + raise RuntimeError( + "You cannot specify a --no-dnssec-validation option " + "without the --setup-dns option") + elif self.forwarders and self.no_forwarders: + raise RuntimeError( + "You cannot specify a --forwarder option together with " + "--no-forwarders") + elif self.auto_forwarders and self.no_forwarders: + raise RuntimeError( + "You cannot specify a --auto-forwarders option together with " + "--no-forwarders") + elif self.reverse_zones and self.no_reverse: + raise RuntimeError( + "You cannot specify a --reverse-zone option together with " + "--no-reverse") + elif self.auto_reverse and self.no_reverse: + raise RuntimeError( + "You cannot specify a --auto-reverse option together with " + "--no-reverse") + + if not self.setup_adtrust: + if self.add_agents: + raise RuntimeError( + "You cannot specify an --add-agents option without the " + "--setup-adtrust option") + + if self.enable_compat: + raise RuntimeError( + "You cannot specify an --enable-compat option without the " + "--setup-adtrust option") + + if self.netbios_name: + raise RuntimeError( + "You cannot specify a --netbios-name option without the " + "--setup-adtrust option") + + if self.no_msdcs: + raise RuntimeError( + "You cannot specify a --no-msdcs option without the " + "--setup-adtrust option") + + if not hasattr(self, 'replica_install'): + if self.external_cert_files and self.dirsrv_cert_files: + raise RuntimeError( + "Service certificate file options cannot be used with the " + "external CA options.") + + if self.external_ca_type and not self.external_ca: + raise RuntimeError( + "You cannot specify --external-ca-type without " + "--external-ca") + + if self.external_ca_profile and not self.external_ca: + raise RuntimeError( + "You cannot specify --external-ca-profile without " + "--external-ca") + + if self.uninstalling: + if (self.realm_name or self.admin_password or + self.master_password): + raise RuntimeError( + "In uninstall mode, -a, -r and -P options are not " + "allowed") + elif not self.interactive: + if (not self.realm_name or not self.dm_password or + not self.admin_password): + raise RuntimeError( + "In unattended mode you need to provide at least -r, " + "-p and -a options") + if self.setup_dns: + if (not self.forwarders and + not self.no_forwarders and + not self.auto_forwarders): + raise RuntimeError( + "You must specify at least one of --forwarder, " + "--auto-forwarders, or --no-forwarders options") + + any_ignore_option_true = any( + [self.ignore_topology_disconnect, self.ignore_last_of_role]) + if any_ignore_option_true and not self.uninstalling: + raise RuntimeError( + "'--ignore-topology-disconnect/--ignore-last-of-role' " + "options can be used only during uninstallation") + + if self.idmax < self.idstart: + raise RuntimeError( + "idmax (%s) cannot be smaller than idstart (%s)" % + (self.idmax, self.idstart)) + else: + # replica installers + if self.servers and not self.domain_name: + raise RuntimeError( + "The --server option cannot be used without providing " + "domain via the --domain option") + + if self.setup_dns: + if (not self.forwarders and + not self.no_forwarders and + not self.auto_forwarders): + raise RuntimeError( + "You must specify at least one of --forwarder, " + "--auto-forwarders, or --no-forwarders options") + + except RuntimeError as e: + ansible_module.fail_json(msg=e) - # domain_level - if options.domain_level < MIN_DOMAIN_LEVEL: - ansible_module.fail_json( - msg="Domain Level cannot be lower than %d" % MIN_DOMAIN_LEVEL) - elif options.domain_level > MAX_DOMAIN_LEVEL: - ansible_module.fail_json( - msg="Domain Level cannot be higher than %d" % MAX_DOMAIN_LEVEL) - # dirsrv_config_file - if options.dirsrv_config_file is not None: - if not os.path.exists(options.dirsrv_config_file): - ansible_module.fail_json( - msg="File %s does not exist." % options.dirsrv_config_file) - # domain_name - if (options.setup_dns and not options.allow_zone_overlap and \ - options.domain_name is not None): - try: - check_zone_overlap(options.domain_name, False) - except ValueError as e: - ansible_module.fail_json(msg=str(e)) - # dm_password - with redirect_stdout(ansible_log): - validate_dm_password(options.dm_password) - # admin_password - with redirect_stdout(ansible_log): - validate_admin_password(options.admin_password) - # pkinit is not supported on DL0, don't allow related options - # replica install: if not self.replica_file is None: - if (not options._replica_install and \ - not options.domain_level > DOMAIN_LEVEL_0) or \ - (options._replica_install and self.replica_file is not None): - if (options.no_pkinit or options.pkinit_cert_files is not None or - options.pkinit_pin is not None): - ansible_module.fail_json( - msg="pkinit on domain level 0 is not supported. Please " - "don't use any pkinit-related options.") - options.no_pkinit = True + + # ####################################################################### # If any of the key file options are selected, all are required. cert_file_req = (options.dirsrv_cert_files, options.http_cert_files) @@ -351,7 +475,7 @@ def main(): ansible_module.fail_json( msg="You cannot specify auto-reverse together with no-reverse") - if not options._replica_install: + if not hasattr(self, 'replica_install'): if options.external_cert_files and options.dirsrv_cert_files: ansible_module.fail_json( msg="Service certificate file options cannot be used with the " @@ -403,34 +527,63 @@ def main(): ansible_module.fail_json( msg="idmax (%s) cannot be smaller than idstart (%s)" % (options.idmax, options.idstart)) - else: - # replica install - if options.replica_file is None: - if options.servers and not options.domain_name: - ansible_module.fail_json( - msg="servers cannot be used without providing domain") - else: - if not os.path.isfile(options.replica_file): - ansible_module.fail_json( - msg="Replica file %s does not exist" % options.replica_file) + # validation ############################################################# + + if options.dm_password is None: + ansible_module.fail_json(msg="Directory Manager password required") + + if options.admin_password is None: + ansible_module.fail_json(msg="IPA admin password required") + + # validation ############################################################ + + # domain_level + if options.domain_level < MIN_DOMAIN_LEVEL: + ansible_module.fail_json( + msg="Domain Level cannot be lower than %d" % MIN_DOMAIN_LEVEL) + elif options.domain_level > MAX_DOMAIN_LEVEL: + ansible_module.fail_json( + msg="Domain Level cannot be higher than %d" % MAX_DOMAIN_LEVEL) + + # dirsrv_config_file + if options.dirsrv_config_file is not None: + if not os.path.exists(options.dirsrv_config_file): + ansible_module.fail_json( + msg="File %s does not exist." % options.dirsrv_config_file) + + # domain_name + if (options.setup_dns and not options.allow_zone_overlap and \ + options.domain_name is not None): + try: + check_zone_overlap(options.domain_name, False) + except ValueError as e: + ansible_module.fail_json(str(e)) + + # dm_password + with redirect_stdout(ansible_log): + validate_dm_password(options.dm_password) + + # admin_password + with redirect_stdout(ansible_log): + validate_admin_password(options.admin_password) + + # pkinit is not supported on DL0, don't allow related options + + """ + # replica install: if not options.replica_file is None: + if (not options._replica_install and \ + not options.domain_level > DOMAIN_LEVEL_0) or \ + (options._replica_install and options.replica_file is not None): + if (options.no_pkinit or options.pkinit_cert_files is not None or + options.pkinit_pin is not None): + ansible_module.fail_json( + msg="pkinit on domain level 0 is not supported. Please " + "don't use any pkinit-related options.") + options.no_pkinit = True + """ + - if any(cert_file_req + cert_file_opt): - ansible_module.fail_json( - msg="You cannot specify dirsrv-cert-file, http-cert-file, " - "or pkinit-cert-file together with replica file") - - conflicting = { "realm": options.realm_name, - "domain": options.domain_name, - "hostname": options.host_name, - "servers": options.servers, - "principal": options.principal } - conflicting_names = [ name for name in conflicting - if conflicting[name] is not None ] - if len(conflicting_names) > 0: - ansible_module.fail_json( - msg="You cannot specify %s option(s) with replica file." % \ - ", ".join(conflicting_names)) if options.setup_dns: if len(options.forwarders) < 1 and not options.no_forwarders and \ @@ -439,11 +592,12 @@ def main(): msg="You must specify at least one of forwarders, " "auto-forwarders or no-forwarders") - if NUM_VERSION >= 40200 and options.master_password: - ansible_module.warn("Specifying master-password is deprecated") + if NUM_VERSION >= 40200 and options.master_password and \ + not options.external_cert_files: + ansible_module.warn("Specifying kerberos master-password is deprecated") options._installation_cleanup = True - if not options.external_ca and len(options.external_cert_files) < 1 and \ + if not options.external_ca and not options.external_cert_files and \ is_ipa_configured(): options._installation_cleanup = False ansible_module.log( @@ -495,10 +649,11 @@ def main(): ansible_module.fail_json(msg=error) # external cert file paths are absolute - for path in options.external_cert_files: - if not os.path.isabs(path): - ansible_module.fail_json( - msg="External cert file '%s' must use an absolute path" % path) + if options.external_cert_files: + for path in options.external_cert_files: + if not os.path.isabs(path): + ansible_module.fail_json( + msg="External cert file '%s' must use an absolute path" % path) options.setup_ca = True # We only set up the CA if the PKCS#12 options are not given. @@ -517,6 +672,18 @@ def main(): ansible_module.fail_json(msg= "--setup-kra cannot be used with CA-less installation") + # This will override any settings passed in on the cmdline + if os.path.isfile(paths.ROOT_IPA_CACHE): + # dm_password check removed, checked already + try: + cache_vars = read_cache(options.dm_password) + options.__dict__.update(cache_vars) + if cache_vars.get('external_ca', False): + options.external_ca = False + options.interactive = False + except Exception as e: + ansible_module.fail_json(msg="Cannot process the cache file: %s" % str(e)) + # ca_subject if options.ca_subject: ca.subject_validator(ca.VALID_SUBJECT_ATTRS, options.ca_subject) @@ -697,6 +864,10 @@ def main(): _pkinit_pkcs12_file=pkinit_pkcs12_file, _pkinit_pkcs12_info=pkinit_pkcs12_info, _pkinit_ca_cert=pkinit_ca_cert, + ### certificate system ### + external_ca=options.external_ca, + external_ca_type=options.external_ca_type, + external_ca_profile=options.external_ca_profile, ### ad trust ### rid_base=options.rid_base, secondary_rid_base=options.secondary_rid_base, diff --git a/roles/ipaserver/module_utils/ansible_ipa_server.py b/roles/ipaserver/module_utils/ansible_ipa_server.py index 8523545283b9181679717ab02558b926b468c4e4..e19eb2ec5b636dcea8003aa472321e0040545103 100644 --- a/roles/ipaserver/module_utils/ansible_ipa_server.py +++ b/roles/ipaserver/module_utils/ansible_ipa_server.py @@ -100,7 +100,7 @@ if NUM_VERSION >= 40500: update_hosts_file) from ipaserver.install.server.install import ( check_dirsrv, validate_admin_password, validate_dm_password, - write_cache) + read_cache, write_cache) try: from ipaserver.install.dogtaginstance import PKIIniLoader except ImportError: @@ -218,6 +218,39 @@ options.add_sids = True options.add_agents = False +# Installable +options.uninstalling = False + +# ServerInstallInterface +options.description = "Server" + +options.kinit_attempts = 1 +options.fixed_primary = True +options.permit = False +options.enable_dns_updates = False +options.no_krb5_offline_passwords = False +options.preserve_sssd = False +options.no_sssd = False + +# ServerMasterInstall +options.force_join = False +options.servers = None +options.no_wait_for_dns = True +options.host_password = None +options.keytab = None +options.setup_ca = True +# always run sidgen task and do not allow adding agents on first master +options.add_sids = True +options.add_agents = False + +# ADTrustInstallInterface +# no_msdcs is deprecated +options.no_msdcs = False + +# Uninstall +options.ignore_topology_disconnect = False +options.ignore_last_of_role = False + def api_Backend_ldap2(host_name, setup_ca, connect=False): # we are sure we have the configuration file ready. cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True, diff --git a/roles/ipaserver/tasks/copy_external_cert.yml b/roles/ipaserver/tasks/copy_external_cert.yml new file mode 100644 index 0000000000000000000000000000000000000000..aaebd2b2cb318d80bf938bcbe6c18e2a79e2adac --- /dev/null +++ b/roles/ipaserver/tasks/copy_external_cert.yml @@ -0,0 +1,12 @@ +- name: Install - Initialize ipaserver_external_cert_files + set_fact: + ipaserver_external_cert_files: [] + when: ipaserver_external_cert_files is undefined +- name: Install - Copy "{{ item }}" "{{ inventory_hostname }}':/root/'{{ item }}" + copy: + src: "{{ item }}" + dest: "/root/{{ item }}" + force: yes +- name: Install - Extend ipaserver_external_cert_files with "/root/{{ item }}" + set_fact: + ipaserver_external_cert_files: "{{ ipaserver_external_cert_files }} + [ '/root/{{ item }}' ]" diff --git a/roles/ipaserver/tasks/install.yml b/roles/ipaserver/tasks/install.yml index a36ccb9f10ed21f29b7bcdac07c36484abeae163..9b25e0d1bdc1f4900807a1860c8f29ecd0949096 100644 --- a/roles/ipaserver/tasks/install.yml +++ b/roles/ipaserver/tasks/install.yml @@ -24,6 +24,12 @@ #- name: Install - Include Python2/3 import test # import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml" +- include_tasks: "{{ role_path }}/tasks/copy_external_cert.yml" + with_items: "{{ ipaserver_external_cert_files_from_controller }}" + when: ipaserver_external_cert_files_from_controller is defined and + ipaserver_external_cert_files_from_controller|length > 0 and + not ipaserver_external_cert_files is defined + - name: Install - Server installation test ipaserver_test: ### basic ### @@ -47,9 +53,9 @@ # no_ui_redirect: "{{ ipaserver_no_ui_redirect }}" dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" ### ssl certificate ### - dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}" - http_cert_files: "{{ ipaserver_http_cert_files | default([]) }}" - pkinit_cert_files: "{{ ipaserver_pkinit_cert_files | default([]) }}" + dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default(omit) }}" + http_cert_files: "{{ ipaserver_http_cert_files | default(omit) }}" + pkinit_cert_files: "{{ ipaserver_pkinit_cert_files | default(omit) }}" # dirsrv_pin # http_pin # pkinit_pin @@ -66,7 +72,8 @@ ### certificate system ### external_ca: "{{ ipaserver_external_ca }}" external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}" - external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}" + external_ca_profile: "{{ ipaserver_external_ca_profile | default(omit) }}" + external_cert_files: "{{ ipaserver_external_cert_files | default(omit) }}" subject_base: "{{ ipaserver_subject_base | default(omit) }}" ca_subject: "{{ ipaserver_ca_subject | default(omit) }}" # ca_signing_algorithm @@ -128,8 +135,12 @@ setup_kra: "{{ ipaserver_setup_kra }}" setup_dns: "{{ ipaserver_setup_dns }}" ### certificate system ### - # external_ca - # external_cert_files + external_ca: "{{ ipaserver_external_ca }}" + external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}" + external_ca_profile: + "{{ ipaserver_external_ca_profile | default(omit) }}" + external_cert_files: + "{{ ipaserver_external_cert_files | default(omit) }}" subject_base: "{{ ipaserver_subject_base | default(omit) }}" ca_subject: "{{ ipaserver_ca_subject | default(omit) }}" ### dns ### @@ -174,8 +185,9 @@ setup_ca: "{{ result_ipaserver_test.setup_ca }}" # no_host_dns: "{{ result_ipaserver_test.no_host_dns }}" dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" - dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}" - external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}" + dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default(omit) }}" + external_cert_files: + "{{ ipaserver_external_cert_files | default(omit) }}" subject_base: "{{ result_ipaserver_prepare.subject_base }}" ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" # no_reverse: "{{ ipaserver_no_reverse }}" @@ -200,7 +212,8 @@ setup_dns: "{{ ipaserver_setup_dns }}" setup_ca: "{{ result_ipaserver_test.setup_ca }}" no_host_dns: "{{ result_ipaserver_test.no_host_dns }}" - external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}" + external_cert_files: + "{{ ipaserver_external_cert_files | default(omit) }}" subject_base: "{{ result_ipaserver_prepare.subject_base }}" ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" no_reverse: "{{ ipaserver_no_reverse }}" @@ -241,7 +254,11 @@ dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}" _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}" external_ca: "{{ ipaserver_external_ca }}" - external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}" + external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}" + external_ca_profile: + "{{ ipaserver_external_ca_profile | default(omit) }}" + external_cert_files: + "{{ ipaserver_external_cert_files | default(omit) }}" subject_base: "{{ result_ipaserver_prepare.subject_base }}" _subject_base: "{{ result_ipaserver_prepare._subject_base }}" ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" @@ -251,150 +268,163 @@ reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}" no_reverse: "{{ ipaserver_no_reverse }}" auto_forwarders: "{{ ipaserver_auto_forwarders }}" + register: result_ipaserver_setup_ca - - name: Install - Setup otpd - ipaserver_setup_otpd: - realm: "{{ result_ipaserver_test.realm }}" - hostname: "{{ result_ipaserver_test.hostname }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" + - name: Copy /root/ipa.csr to "{{ inventory_hostname }}-ipa.csr" + fetch: + src: /root/ipa.csr + dest: "{{ inventory_hostname }}-ipa.csr" + flat: yes + when: result_ipaserver_setup_ca.csr_generated | bool and + ipaserver_copy_csr_to_controller | bool - - name: Install - Setup HTTP - ipaserver_setup_http: - dm_password: "{{ ipadm_password }}" - password: "{{ ipaadmin_password }}" - master_password: "{{ ipaserver_master_password }}" - domain: "{{ result_ipaserver_test.domain }}" - realm: "{{ result_ipaserver_test.realm }}" - hostname: "{{ result_ipaserver_test.hostname }}" - # ip_addresses: "{{ result_ipaserver_prepare.ip_addresses }}" - reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}" - setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}" - setup_kra: "{{ result_ipaserver_test.setup_kra }}" - setup_dns: "{{ ipaserver_setup_dns }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" - no_host_dns: "{{ result_ipaserver_test.no_host_dns }}" - dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}" - external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}" - subject_base: "{{ result_ipaserver_prepare.subject_base }}" - _subject_base: "{{ result_ipaserver_prepare._subject_base }}" - ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" - _ca_subject: "{{ result_ipaserver_prepare._ca_subject }}" - no_reverse: "{{ ipaserver_no_reverse }}" - auto_forwarders: "{{ ipaserver_auto_forwarders }}" - no_pkinit: "{{ result_ipaserver_test.no_pkinit }}" - no_hbac_allow: "{{ ipaserver_no_hbac_allow }}" - idstart: "{{ result_ipaserver_test.idstart }}" - idmax: "{{ result_ipaserver_test.idmax }}" - http_cert_files: "{{ ipaserver_http_cert_files | default([]) }}" - no_ui_redirect: "{{ ipaserver_no_ui_redirect }}" + - block: + - name: Install - Setup otpd + ipaserver_setup_otpd: + realm: "{{ result_ipaserver_test.realm }}" + hostname: "{{ result_ipaserver_test.hostname }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" - - name: Install - Setup KRA - ipaserver_setup_kra: - hostname: "{{ result_ipaserver_test.hostname }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" - dm_password: "{{ ipadm_password }}" - setup_kra: "{{ result_ipaserver_test.setup_kra }}" - realm: "{{ result_ipaserver_test.realm }}" - pki_config_override: "{{ ipaserver_pki_config_override | - default(omit) }}" - when: result_ipaserver_test.setup_kra | bool + - name: Install - Setup HTTP + ipaserver_setup_http: + dm_password: "{{ ipadm_password }}" + password: "{{ ipaadmin_password }}" + master_password: "{{ ipaserver_master_password }}" + domain: "{{ result_ipaserver_test.domain }}" + realm: "{{ result_ipaserver_test.realm }}" + hostname: "{{ result_ipaserver_test.hostname }}" + # ip_addresses: "{{ result_ipaserver_prepare.ip_addresses }}" + reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}" + setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}" + setup_kra: "{{ result_ipaserver_test.setup_kra }}" + setup_dns: "{{ ipaserver_setup_dns }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" + no_host_dns: "{{ result_ipaserver_test.no_host_dns }}" + dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}" + external_cert_files: + "{{ ipaserver_external_cert_files | default(omit) }}" + subject_base: "{{ result_ipaserver_prepare.subject_base }}" + _subject_base: "{{ result_ipaserver_prepare._subject_base }}" + ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" + _ca_subject: "{{ result_ipaserver_prepare._ca_subject }}" + no_reverse: "{{ ipaserver_no_reverse }}" + auto_forwarders: "{{ ipaserver_auto_forwarders }}" + no_pkinit: "{{ result_ipaserver_test.no_pkinit }}" + no_hbac_allow: "{{ ipaserver_no_hbac_allow }}" + idstart: "{{ result_ipaserver_test.idstart }}" + idmax: "{{ result_ipaserver_test.idmax }}" + http_cert_files: "{{ ipaserver_http_cert_files | default([]) }}" + no_ui_redirect: "{{ ipaserver_no_ui_redirect }}" - - name: Install - Setup DNS - ipaserver_setup_dns: - hostname: "{{ result_ipaserver_test.hostname }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" - setup_dns: "{{ ipaserver_setup_dns }}" - forwarders: "{{ result_ipaserver_prepare.forwarders }}" - forward_policy: "{{ result_ipaserver_prepare.forward_policy }}" - zonemgr: "{{ ipaserver_zonemgr | default(omit) }}" - no_dnssec_validation: "{{ result_ipaserver_prepare.no_dnssec_validation }}" - ### additional ### - dns_ip_addresses: "{{ result_ipaserver_prepare.dns_ip_addresses }}" - dns_reverse_zones: "{{ result_ipaserver_prepare.dns_reverse_zones }}" - when: ipaserver_setup_dns | bool + - name: Install - Setup KRA + ipaserver_setup_kra: + hostname: "{{ result_ipaserver_test.hostname }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" + dm_password: "{{ ipadm_password }}" + setup_kra: "{{ result_ipaserver_test.setup_kra }}" + realm: "{{ result_ipaserver_test.realm }}" + pki_config_override: "{{ ipaserver_pki_config_override | + default(omit) }}" + when: result_ipaserver_test.setup_kra | bool - - name: Install - Setup ADTRUST - ipaserver_setup_adtrust: - hostname: "{{ result_ipaserver_test.hostname }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" - setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}" - ### ad trust ### - enable_compat: "{{ ipaserver_enable_compat }}" - rid_base: "{{ result_ipaserver_test.rid_base }}" - secondary_rid_base: "{{ result_ipaserver_test.secondary_rid_base }}" - ### additional ### - adtrust_netbios_name: "{{ result_ipaserver_prepare.adtrust_netbios_name }}" - adtrust_reset_netbios_name: - "{{ result_ipaserver_prepare.adtrust_reset_netbios_name }}" - when: result_ipaserver_test.setup_adtrust + - name: Install - Setup DNS + ipaserver_setup_dns: + hostname: "{{ result_ipaserver_test.hostname }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" + setup_dns: "{{ ipaserver_setup_dns }}" + forwarders: "{{ result_ipaserver_prepare.forwarders }}" + forward_policy: "{{ result_ipaserver_prepare.forward_policy }}" + zonemgr: "{{ ipaserver_zonemgr | default(omit) }}" + no_dnssec_validation: "{{ result_ipaserver_prepare.no_dnssec_validation }}" + ### additional ### + dns_ip_addresses: "{{ result_ipaserver_prepare.dns_ip_addresses }}" + dns_reverse_zones: "{{ result_ipaserver_prepare.dns_reverse_zones }}" + when: ipaserver_setup_dns | bool - - name: Install - Set DS password - ipaserver_set_ds_password: - dm_password: "{{ ipadm_password }}" - password: "{{ ipaadmin_password }}" - domain: "{{ result_ipaserver_test.domain }}" - realm: "{{ result_ipaserver_test.realm }}" - hostname: "{{ result_ipaserver_test.hostname }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" - subject_base: "{{ result_ipaserver_prepare.subject_base }}" - ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" - no_pkinit: "{{ result_ipaserver_test.no_pkinit }}" - no_hbac_allow: "{{ ipaserver_no_hbac_allow }}" - idstart: "{{ result_ipaserver_test.idstart }}" - idmax: "{{ result_ipaserver_test.idmax }}" - dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" - _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}" + - name: Install - Setup ADTRUST + ipaserver_setup_adtrust: + hostname: "{{ result_ipaserver_test.hostname }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" + setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}" + ### ad trust ### + enable_compat: "{{ ipaserver_enable_compat }}" + rid_base: "{{ result_ipaserver_test.rid_base }}" + secondary_rid_base: "{{ result_ipaserver_test.secondary_rid_base }}" + ### additional ### + adtrust_netbios_name: "{{ result_ipaserver_prepare.adtrust_netbios_name }}" + adtrust_reset_netbios_name: + "{{ result_ipaserver_prepare.adtrust_reset_netbios_name }}" + when: result_ipaserver_test.setup_adtrust - - name: Install - Setup client - include_role: - name: ipaclient - vars: - state: present - ipaclient_on_master: yes - ipaclient_domain: "{{ result_ipaserver_test.domain }}" - ipaclient_realm: "{{ result_ipaserver_test.realm }}" - ipaclient_servers: ["{{ result_ipaserver_test.hostname }}"] - ipaclient_hostname: "{{ result_ipaserver_test.hostname }}" - ipaclient_no_ntp: - "{{ 'true' if result_ipaserver_test.ipa_python_version >= 40690 - else 'false' }}" - ipaclient_install_packages: "{{ ipaserver_install_packages }}" - - - name: Install - Enable IPA - ipaserver_enable_ipa: - hostname: "{{ result_ipaserver_test.hostname }}" - setup_dns: "{{ ipaserver_setup_dns }}" - setup_ca: "{{ result_ipaserver_test.setup_ca }}" - register: result_ipaserver_enable_ipa - - - name: Install - Cleanup root IPA cache - file: - path: "/root/.ipa_cache" - state: absent - when: result_ipaserver_enable_ipa.changed - - - name: Install - Configure firewalld - command: > - firewall-cmd - --permanent - --add-service=freeipa-ldap - --add-service=freeipa-ldaps - {{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool - else "" }} - {{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }} - {{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }} - when: ipaserver_setup_firewalld | bool - - - name: Install - Configure firewalld runtime - command: > - firewall-cmd - --add-service=freeipa-ldap - --add-service=freeipa-ldaps - {{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool - else "" }} - {{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }} - {{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }} - when: ipaserver_setup_firewalld | bool + - name: Install - Set DS password + ipaserver_set_ds_password: + dm_password: "{{ ipadm_password }}" + password: "{{ ipaadmin_password }}" + domain: "{{ result_ipaserver_test.domain }}" + realm: "{{ result_ipaserver_test.realm }}" + hostname: "{{ result_ipaserver_test.hostname }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" + subject_base: "{{ result_ipaserver_prepare.subject_base }}" + ca_subject: "{{ result_ipaserver_prepare.ca_subject }}" + no_pkinit: "{{ result_ipaserver_test.no_pkinit }}" + no_hbac_allow: "{{ ipaserver_no_hbac_allow }}" + idstart: "{{ result_ipaserver_test.idstart }}" + idmax: "{{ result_ipaserver_test.idmax }}" + dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" + _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}" + + - name: Install - Setup client + include_role: + name: ipaclient + vars: + state: present + ipaclient_on_master: yes + ipaclient_domain: "{{ result_ipaserver_test.domain }}" + ipaclient_realm: "{{ result_ipaserver_test.realm }}" + ipaclient_servers: ["{{ result_ipaserver_test.hostname }}"] + ipaclient_hostname: "{{ result_ipaserver_test.hostname }}" + ipaclient_no_ntp: + "{{ 'true' if result_ipaserver_test.ipa_python_version >= 40690 + else 'false' }}" + ipaclient_install_packages: "{{ ipaserver_install_packages }}" + + - name: Install - Enable IPA + ipaserver_enable_ipa: + hostname: "{{ result_ipaserver_test.hostname }}" + setup_dns: "{{ ipaserver_setup_dns }}" + setup_ca: "{{ result_ipaserver_test.setup_ca }}" + register: result_ipaserver_enable_ipa + + - name: Install - Cleanup root IPA cache + file: + path: "/root/.ipa_cache" + state: absent + when: result_ipaserver_enable_ipa.changed + + - name: Install - Configure firewalld + command: > + firewall-cmd + --permanent + --add-service=freeipa-ldap + --add-service=freeipa-ldaps + {{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool + else "" }} + {{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }} + {{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }} + when: ipaserver_setup_firewalld | bool + + - name: Install - Configure firewalld runtime + command: > + firewall-cmd + --add-service=freeipa-ldap + --add-service=freeipa-ldaps + {{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool + else "" }} + {{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }} + {{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }} + when: ipaserver_setup_firewalld | bool + + when: not result_ipaserver_setup_ca.csr_generated | bool when: not ansible_check_mode and not (not result_ipaserver_test.changed and