def main(): module = AnsibleModule( argument_spec=dict( servers=dict(required=True, type='list'), domain=dict(required=True), realm=dict(required=True), hostname=dict(required=True), basedn=dict(required=True), principal=dict(required=False), subject_base=dict(required=True), ca_enabled=dict(required=True, type='bool'), mkhomedir=dict(required=False, type='bool'), on_master=dict(required=False, type='bool'), dnsok=dict(required=False, type='bool', default=False), enable_dns_updates=dict(required=False, type='bool'), all_ip_addresses=dict(required=False, type='bool', default=False), ip_addresses=dict(required=False, type='list', default=None), request_cert=dict(required=False, type='bool', default=False), preserve_sssd=dict(required=False, type='bool'), no_ssh=dict(required=False, type='bool'), no_sshd=dict(required=False, type='bool'), no_sudo=dict(required=False, type='bool'), fixed_primary=dict(required=False, type='bool'), permit=dict(required=False, type='bool'), no_krb5_offline_passwords=dict(required=False, type='bool'), no_dns_sshfp=dict(required=False, type='bool', default=False), ), supports_check_mode=True, ) module._ansible_debug = True cli_server = module.params.get('servers') cli_realm = module.params.get('realm') hostname = module.params.get('hostname') cli_basedn = module.params.get('basedn') cli_domain = module.params.get('domain') options.principal = module.params.get('principal') subject_base = module.params.get('subject_base') ca_enabled = module.params.get('ca_enabled') options.mkhomedir = module.params.get('mkhomedir') options.on_master = module.params.get('on_master') dnsok = module.params.get('dnsok') fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE options.dns_updates = module.params.get('enable_dns_updates') options.all_ip_addresses = module.params.get('all_ip_addresses') options.ip_addresses = ansible_module_get_parsed_ip_addresses(module) options.request_cert = module.params.get('request_cert') options.hostname = hostname options.host_name = hostname options.preserve_sssd = module.params.get('preserve_sssd') options.no_ssh = module.params.get('no_ssh') options.conf_ssh = not options.no_ssh options.no_sshd = module.params.get('no_sshd') options.conf_sshd = not options.no_sshd options.no_sudo = module.params.get('no_sudo') options.conf_sudo = not options.no_sudo options.primary = module.params.get('fixed_primary') options.permit = module.params.get('permit') options.no_krb5_offline_passwords = module.params.get( 'no_krb5_offline_passwords') options.krb5_offline_passwords = not options.no_krb5_offline_passwords options.no_dns_sshfp = module.params.get('no_dns_sshfp') options.create_sshfp = not options.no_dns_sshfp options.no_sssd = False options.sssd = not options.no_sssd options.no_ac = False CCACHE_FILE = paths.IPA_DNS_CCACHE api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA, debug=False, delegate=False) api.finalize() api.Backend.rpcclient.connect() try: api.Backend.rpcclient.forward('ping') except errors.KerberosError: # Cannot connect to the server due to Kerberos error, trying with # delegate=True api.Backend.rpcclient.disconnect() api.Backend.rpcclient.connect(delegate=True) api.Backend.rpcclient.forward('ping') ########################################################################## try: # Create IPA NSS database try: create_ipa_nssdb() except ipautil.CalledProcessError as e: raise ScriptError("Failed to create IPA NSS database: %s" % e, rval=CLIENT_INSTALL_ERROR) # Get CA certificates from the certificate store try: ca_certs = get_certs_from_ldap(cli_server[0], cli_basedn, cli_realm, ca_enabled) except errors.NoCertificateError: if ca_enabled: ca_subject = DN(('CN', 'Certificate Authority'), subject_base) else: ca_subject = None ca_certs = certstore.make_compat_ca_certs(ca_certs, cli_realm, ca_subject) ca_certs_trust = [(c, n, certstore.key_policy_to_trust_flags(t, True, u)) for (c, n, t, u) in ca_certs] if hasattr(paths, "KDC_CA_BUNDLE_PEM"): x509.write_certificate_list( [c for c, n, t, u in ca_certs if t is not False], paths.KDC_CA_BUNDLE_PEM, # mode=0o644 ) if hasattr(paths, "CA_BUNDLE_PEM"): x509.write_certificate_list( [c for c, n, t, u in ca_certs if t is not False], paths.CA_BUNDLE_PEM, # mode=0o644 ) # Add the CA certificates to the IPA NSS database logger.debug("Adding CA certificates to the IPA NSS database.") ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) for cert, nickname, trust_flags in ca_certs_trust: try: ipa_db.add_cert(cert, nickname, trust_flags) except CalledProcessError: raise ScriptError("Failed to add %s to the IPA NSS database." % nickname, rval=CLIENT_INSTALL_ERROR) # Add the CA certificates to the platform-dependant systemwide CA # store tasks.insert_ca_certs_into_systemwide_ca_store(ca_certs) if not options.on_master: client_dns(cli_server[0], hostname, options) configure_certmonger(fstore, subject_base, cli_realm, hostname, options, ca_enabled) if hasattr(paths, "SSH_CONFIG_DIR"): ssh_config_dir = paths.SSH_CONFIG_DIR else: ssh_config_dir = services.knownservices.sshd.get_config_dir() update_ssh_keys(hostname, ssh_config_dir, options.create_sshfp) try: os.remove(CCACHE_FILE) except Exception: pass argspec_save_state = inspect.getargspec(save_state) # Name Server Caching Daemon. Disable for SSSD, use otherwise # (if installed) nscd = services.knownservices.nscd if nscd.is_installed(): if "statestore" in argspec_save_state.args: save_state(nscd, statestore) else: save_state(nscd) nscd_service_action = None try: if options.sssd: nscd_service_action = 'stop' nscd.stop() else: nscd_service_action = 'restart' nscd.restart() except Exception: logger.warning("Failed to %s the %s daemon", nscd_service_action, nscd.service_name) if not options.sssd: logger.warning( "Caching of users/groups will not be available") try: if options.sssd: nscd.disable() else: nscd.enable() except Exception: if not options.sssd: logger.warning( "Failed to configure automatic startup of the %s " "daemon", nscd.service_name) logger.info("Caching of users/groups will not be " "available after reboot") else: logger.warning( "Failed to disable %s daemon. Disable it manually.", nscd.service_name) else: # this is optional service, just log if not options.sssd: logger.info("%s daemon is not installed, skip configuration", nscd.service_name) nslcd = services.knownservices.nslcd if nslcd.is_installed(): if "statestore" in argspec_save_state.args: save_state(nslcd, statestore) else: save_state(nslcd) retcode, conf = (0, None) if not options.no_ac: # Modify nsswitch/pam stack argspec = inspect.getargspec(tasks.modify_nsswitch_pam_stack) if "sudo" in argspec.args: tasks.modify_nsswitch_pam_stack(sssd=options.sssd, mkhomedir=options.mkhomedir, statestore=statestore, sudo=options.conf_sudo) else: tasks.modify_nsswitch_pam_stack(sssd=options.sssd, mkhomedir=options.mkhomedir, statestore=statestore) if hasattr(paths, "AUTHSELECT") and paths.AUTHSELECT is not None: # authselect is used # if mkhomedir, make sure oddjobd is enabled and started if options.mkhomedir: oddjobd = services.service('oddjobd', api) running = oddjobd.is_running() enabled = oddjobd.is_enabled() statestore.backup_state('oddjobd', 'running', running) statestore.backup_state('oddjobd', 'enabled', enabled) try: if not enabled: oddjobd.enable() if not running: oddjobd.start() except Exception as e: logger.critical("Unable to start oddjobd: %s", str(e)) logger.info("%s enabled", "SSSD" if options.sssd else "LDAP") if options.sssd: sssd = services.service('sssd', api) try: sssd.restart() except CalledProcessError: logger.warning("SSSD service restart was unsuccessful.") try: sssd.enable() except CalledProcessError as e: logger.warning( "Failed to enable automatic startup of the SSSD " "daemon: %s", e) if not options.sssd: tasks.modify_pam_to_use_krb5(statestore) logger.info("Kerberos 5 enabled") # Update non-SSSD LDAP configuration after authconfig calls as it # would change its configuration otherways if not options.sssd: for configurer in [configure_ldap_conf, configure_nslcd_conf]: (retcode, conf, filenames) = configurer( fstore, cli_basedn, cli_realm, cli_domain, cli_server, dnsok, options, nosssd_files[configurer.__name__]) if retcode: raise ScriptError(rval=CLIENT_INSTALL_ERROR) if conf: logger.info( "%s configured using configuration file(s) %s", conf, filenames) if configure_openldap_conf(fstore, cli_basedn, cli_server): logger.info("Configured /etc/openldap/ldap.conf") else: logger.info("Failed to configure /etc/openldap/ldap.conf") # Check that nss is working properly if not options.on_master: user = options.principal if user is None: user = "******" % cli_domain logger.info( "Principal is not set when enrolling with OTP" "; using principal '%s' for 'getent passwd'", user) elif '@' not in user: user = "******" % (user, cli_domain) n = 0 found = False # Loop for up to 10 seconds to see if nss is working properly. # It can sometimes take a few seconds to connect to the remote # provider. # Particulary, SSSD might take longer than 6-8 seconds. if hasattr(paths, "GETENT"): getent_cmd = paths.GETENT else: getent_cmd = '/usr/bin/getent' while n < 10 and not found: try: ipautil.run([getent_cmd, "passwd", user]) found = True except Exception: time.sleep(1) n = n + 1 if not found: logger.error( "Unable to find '%s' user with 'getent " "passwd %s'!", user.split("@")[0], user) if conf: logger.info("Recognized configuration: %s", conf) else: logger.error( "Unable to reliably detect " "configuration. Check NSS setup manually.") try: hardcode_ldap_server(cli_server) except Exception as e: logger.error( "Adding hardcoded server name to " "/etc/ldap.conf failed: %s", str(e)) except ScriptError as e: module.fail_json(msg=str(e)) ########################################################################## module.exit_json(changed=True, ca_enabled_ra=ca_enabled)
def main(): module = AnsibleModule( argument_spec=dict( servers=dict(required=True, type='list'), realm=dict(required=True), hostname=dict(required=True), debug=dict(required=False, type='bool', default="false"), ), supports_check_mode=True, ) module._ansible_debug = True setup_logging() realm = module.params.get('realm') hostname = module.params.get('hostname') debug = module.params.get('debug') host_principal = 'host/%s@%s' % (hostname, realm) os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE ca_certs = x509.load_certificate_list_from_file(paths.IPA_CA_CRT) if 40500 <= NUM_VERSION < 40590: ca_certs = [cert.public_bytes(serialization.Encoding.DER) for cert in ca_certs] elif NUM_VERSION < 40500: ca_certs = [cert.der_data for cert in ca_certs] with certdb.NSSDatabase() as tmp_db: api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA, debug=debug, delegate=False, nss_dir=tmp_db.secdir) if 'config_loaded' not in api.env: module.fail_json(msg="Failed to initialize IPA API.") # Clear out any current session keyring information try: delete_persistent_client_session_data(host_principal) except ValueError: pass # Add CA certs to a temporary NSS database try: argspec = inspect.getargspec(tmp_db.create_db) if "password_filename" not in argspec.args: tmp_db.create_db() else: pwd_file = write_tmp_file(ipa_generate_password()) tmp_db.create_db(pwd_file.name) for i, cert in enumerate(ca_certs): if hasattr(certdb, "EXTERNAL_CA_TRUST_FLAGS"): tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), certdb.EXTERNAL_CA_TRUST_FLAGS) else: tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), 'C,,') except CalledProcessError: module.fail_json(msg="Failed to add CA to temporary NSS database.") api.finalize() # Now, let's try to connect to the server's RPC interface connected = False try: api.Backend.rpcclient.connect() connected = True module.debug("Try RPC connection") api.Backend.rpcclient.forward('ping') except errors.KerberosError as e: if connected: api.Backend.rpcclient.disconnect() module.log( "Cannot connect to the server due to Kerberos error: %s. " "Trying with delegate=True" % e) try: api.Backend.rpcclient.connect(delegate=True) module.debug("Try RPC connection") api.Backend.rpcclient.forward('ping') module.log("Connection with delegate=True successful") # The remote server is not capable of Kerberos S4U2Proxy # delegation. This features is implemented in IPA server # version 2.2 and higher module.warn( "Target IPA server has a lower version than the enrolled " "client") module.warn( "Some capabilities including the ipa command capability " "may not be available") except errors.PublicError as e2: module.fail_json( msg="Cannot connect to the IPA server RPC interface: " "%s" % e2) except errors.PublicError as e: module.fail_json( msg="Cannot connect to the server due to generic error: " "%s" % e) # Use the RPC directly so older servers are supported try: result = api.Backend.rpcclient.forward( 'ca_is_enabled', version=u'2.107', ) ca_enabled = result['result'] except (errors.CommandError, errors.NetworkError): result = api.Backend.rpcclient.forward( 'env', server=True, version=u'2.0', ) ca_enabled = result['result']['enable_ra'] if not ca_enabled: disable_ra() # Get subject base from ipa server try: config = api.Command['config_show']()['result'] subject_base = str(DN(config['ipacertificatesubjectbase'][0])) except errors.PublicError: try: config = api.Backend.rpcclient.forward( 'config_show', raw=True, # so that servroles are not queried version=u'2.0' )['result'] except Exception as e: logger.debug("config_show failed %s", e, exc_info=True) module.fail_json( "Failed to retrieve CA certificate subject base: {}".format(e), rval=CLIENT_INSTALL_ERROR) else: subject_base = str(DN(config['ipacertificatesubjectbase'][0])) module.exit_json(changed=True, ca_enabled=ca_enabled, subject_base=subject_base)