def execute(self, **options): ca_enabled = self.api.Command.ca_is_enabled()['result'] if not ca_enabled: return False, [] olddb = certdb.NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR) if not olddb.has_nickname('ipaCert'): # Nothign to do return False, [] newdb = certdb.NSSDatabase(nssdir=paths.IPA_RADB_DIR) if os.path.exists(paths.IPA_RADB_DIR): if newdb.has_nickname('ipaCert'): self.log.warning( "An 'ipaCert' nickname exists in both the old {} and the " "new {} NSS Databases!".format(paths.HTTPD_ALIAS_DIR, paths.IPA_RADB_DIR)) return False, [] else: # Create the DB newdb.create_db(user=IPAAPI_USER, group=IPAAPI_GROUP, backup=True) # Import cert chain (ignore errors, as certs may already be imported) certlist = olddb.list_certs() certflags = {} for name, flags in certlist: certflags[name] = flags for name in olddb.get_trust_chain('ipaCert'): if name == 'ipaCert': continue try: cert = olddb.get_cert(name, pem=True) newdb.add_cert(cert, name, certflags[name], pem=True) except Exception as e: # pylint disable=broad-except self.log.warning("Failed to import '{}' from trust " "chain: {}".format(name, str(e))) # As the last step export/import/delete the RA Cert pw = binascii.hexlify(os.urandom(10)) p12file = os.path.join(paths.IPA_RADB_DIR, 'ipaCert.p12') olddb.export_pkcs12('ipaCert', p12file, pw) newdb.import_pkcs12(p12file, pw) certmonger.stop_tracking(secdir=olddb.secdir, nickname='ipaCert') certmonger.start_tracking(secdir=newdb.secdir, nickname='ipaCert', password_file=newdb.pwd_file) olddb.delete_cert('ipaCert') return False, []
def update_client(self, certs): self.update_file(paths.IPA_CA_CRT, certs) ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR) # Remove IPA certs from /etc/pki/nssdb for nickname, trust_flags in ipa_db.list_certs(): while sys_db.has_nickname(nickname): try: sys_db.delete_cert(nickname) except ipautil.CalledProcessError, e: self.log.error("Failed to remove %s from %s: %s", nickname, sys_db.secdir, e) break
def makecert(reqdir, subject, principal): """ Generate a certificate that can be used during unit testing. """ ra = rabase.rabase(api) if (not os.path.exists(ra.client_certfile) and api.env.xmlrpc_uri == 'http://localhost:8888/ipa/xml'): raise AssertionError('The self-signed CA is not configured, ' 'see ipatests/test_xmlrpc/test_cert.py') nssdb = certdb.NSSDatabase(nssdir=reqdir) with open(nssdb.pwd_file, "w") as f: # Create an empty password file f.write("\n") # create db nssdb.create_db() # create CSR csr_file = os.path.join(reqdir, 'req') nssdb.run_certutil( ["-R", "-s", str(subject), "-o", csr_file, "-z", paths.GROUP, "-a"]) with open(csr_file, "rb") as f: csr = f.read().decode('ascii') res = api.Command['cert_request'](csr, principal=principal, add=True) cert = x509.load_der_x509_certificate( base64.b64decode(res['result']['certificate'])) return cert.public_bytes(x509.Encoding.PEM)
def update_db(path, certs): db = certdb.NSSDatabase(path) for cert, nickname, trusted, eku in certs: trust_flags = certstore.key_policy_to_trust_flags(trusted, True, eku) try: db.add_cert(cert, nickname, trust_flags) except ipautil.CalledProcessError as e: logger.error("failed to update %s in %s: %s", nickname, path, e)
def cert_restore(self): if not os.path.exists(os.path.join(paths.IPA_NSSDB_DIR, 'cert8.db')): certdb.create_ipa_nssdb() ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR) for nickname, trust_flags in (('IPA CA', 'CT,C,C'), ('External CA cert', 'C,,')): try: cert = sys_db.get_cert(nickname) except RuntimeError: pass else: try: ipa_db.add_cert(cert, nickname, trust_flags) except ipautil.CalledProcessError as e: self.log.error("Failed to add %s to %s: %s" % (nickname, paths.IPA_NSSDB_DIR, e)) tasks.reload_systemwide_ca_store() services.knownservices.certmonger.restart()
def update_db(path, certs): """Drop all CA certs from db then add certs from list provided This may result in some churn as existing certs are dropped and re-added but this also provides the ability to change the trust flags. """ db = certdb.NSSDatabase(path) for name, flags in db.list_certs(): if flags.ca: db.delete_cert(name) for cert, nickname, trusted, eku in certs: trust_flags = certstore.key_policy_to_trust_flags(trusted, True, eku) try: db.add_cert(cert, nickname, trust_flags) except ipautil.CalledProcessError as e: logger.error("failed to update %s in %s: %s", nickname, path, e)
def __create_kra_agent(self): """ Create KRA agent, assign a certificate, and add the user to the appropriate groups for accessing KRA services. """ # get ipaCert certificate with certdb.NSSDatabase(paths.HTTPD_ALIAS_DIR) as ipa_nssdb: cert_data = ipa_nssdb.get_cert("ipaCert") cert = x509.load_certificate(cert_data, x509.DER) # connect to KRA database server_id = installutils.realm_to_serverid(api.env.realm) dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id conn = ldap2.ldap2(api, ldap_uri=dogtag_uri) conn.connect(autobind=True) # create ipakra user with ipaCert certificate user_dn = DN(('uid', "ipakra"), ('ou', 'people'), self.basedn) entry = conn.make_entry( user_dn, objectClass=[ 'top', 'person', 'organizationalPerson', 'inetOrgPerson', 'cmsuser' ], uid=["ipakra"], sn=["IPA KRA User"], cn=["IPA KRA User"], usertype=["undefined"], userCertificate=[cert_data], description=[ '2;%s;%s;%s' % (cert.serial_number, DN(('CN', 'Certificate Authority'), self.subject_base), DN( ('CN', 'IPA RA'), self.subject_base)) ]) conn.add_entry(entry) # add ipakra user to Data Recovery Manager Agents group group_dn = DN(('cn', 'Data Recovery Manager Agents'), ('ou', 'groups'), self.basedn) conn.add_entry_to_group(user_dn, group_dn, 'uniqueMember') conn.disconnect()
def update_client(self, certs): self.update_file(paths.IPA_CA_CRT, certs) ipa_db = certdb.NSSDatabase(api.env.nss_dir) # Remove old IPA certs from /etc/ipa/nssdb for nickname in ('IPA CA', 'External CA cert'): while ipa_db.has_nickname(nickname): try: ipa_db.delete_cert(nickname) except ipautil.CalledProcessError as e: self.log.error("Failed to remove %s from %s: %s", nickname, ipa_db.secdir, e) break self.update_db(ipa_db.secdir, certs) tasks.remove_ca_certs_from_systemwide_ca_store() tasks.insert_ca_certs_into_systemwide_ca_store(certs)
def install_check(api, replica_config, options): if replica_config is not None and not replica_config.setup_kra: return kra = krainstance.KRAInstance(api.env.realm) if kra.is_installed(): raise RuntimeError("KRA is already installed.") if not options.setup_ca: if cainstance.is_ca_installed_locally(): if api.env.dogtag_version >= 10: # correct dogtag version of CA installed pass else: raise RuntimeError( "Dogtag must be version 10.2 or above to install KRA") else: raise RuntimeError( "Dogtag CA is not installed. Please install the CA first") if replica_config is not None: if not api.Command.kra_is_enabled()['result']: raise RuntimeError( "KRA is not installed on the master system. Please use " "'ipa-kra-install' command to install the first instance.") if options.promote: return with certdb.NSSDatabase() as tmpdb: pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db(pw.name) tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12", pw.name, replica_config.dirman_password) kra_cert_nicknames = [ "storageCert cert-pki-kra", "transportCert cert-pki-kra", "auditSigningCert cert-pki-kra" ] if not all( tmpdb.has_nickname(nickname) for nickname in kra_cert_nicknames): raise RuntimeError("Missing KRA certificates, please create a " "new replica file.")
def check(self): # For simplicity use the expected certmonger tracking for the # list of certificates to check because it already filters out # based on whether the CA system is configure and whether the # certificates were issued by IPA. if not self.ca.is_configured(): logger.debug('CA is not configured, skipping revocation check') return requests = get_expected_requests(self.ca, self.ds, self.serverid) for request in requests: id = certmonger.get_request_id(request) if request.get('cert-file') is not None: certfile = request.get('cert-file') try: cert = x509.load_certificate_from_file(certfile) except Exception as e: yield Result(self, constants.ERROR, key=id, certfile=certfile, error=str(e), msg='Unable to open cert file {certfile}: ' '{error}') continue elif request.get('cert-database') is not None: nickname = request.get('cert-nickname') dbdir = request.get('cert-database') try: db = certdb.NSSDatabase(dbdir) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, error=str(e), msg='Unable to open NSS database {dbdir}: ' '{error}') continue try: cert = db.get_cert(nickname) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, nickname=nickname, error=str(e), msg='Unable to retrieve certificate ' '\'{nickname}\' from {dbdir}: {error}') continue else: yield Result(self, constants.ERROR, key=id, msg='Unable to to identify certificate storage ' 'type for request {key}') continue issued = is_ipa_issued_cert(api, cert) if issued is False: logger.debug('\'%s\' was not issued by IPA, skipping', DN(cert.subject)) continue if issued is None: logger.debug('LDAP is down, skipping \'%s\'', DN(cert.subject)) continue # Now we have the cert either way, check the recovation try: result = api.Command.cert_show(cert.serial_number, all=True) except Exception as e: yield Result(self, constants.ERROR, key=id, serial=cert.serial_number, error=str(e), msg='Request for certificate serial number ' '{serial} in request {key} failed: {error}') continue try: if result['result']['revoked']: reason = result['result']['revocation_reason'] reason_txt = self.revocation_reason[reason] yield Result(self, constants.ERROR, revocation_reason=reason_txt, key=id, msg='Certificate tracked by {key} is revoked ' '{revocation_reason}') else: yield Result(self, constants.SUCCESS, key=id) except Exception as e: yield Result(self, constants.ERROR, key=id, error=str(e), msg='Unable to determine revocation ' 'status for {key}: {error}')
def check(self): validate = [] ca_pw_fname = None if self.ca.is_configured(): try: ca_passwd = get_dogtag_cert_password() except IOError as e: yield Result( self, constants.ERROR, error=str(e), msg='Unable to read CA NSSDB token password: {error}') return else: with tempfile.NamedTemporaryFile(mode='w', delete=False) as ca_pw_file: ca_pw_file.write(ca_passwd) ca_pw_fname = ca_pw_file.name validate.append(( paths.PKI_TOMCAT_ALIAS_DIR, 'Server-Cert cert-pki-ca', ca_pw_fname, ), ) validate.append(( dsinstance.config_dirname(self.serverid), self.ds.get_server_cert_nickname(self.serverid), os.path.join(dsinstance.config_dirname(self.serverid), 'pwdfile.txt'), )) # Wrap in try/except to ensure the temporary password file is # removed try: for (dbdir, nickname, pinfile) in validate: # detect the database type so we have the right prefix db = certdb.NSSDatabase(dbdir) key = os.path.normpath(dbdir) + ':' + nickname try: response = self.validate_nss(dbdir, db.dbtype, pinfile, nickname) except ipautil.CalledProcessError as e: logger.debug('Validation of NSS certificate failed %s', e) yield Result( self, constants.ERROR, key=key, dbdir=dbdir, nickname=nickname, reason=response.output_error, msg='Validation of {nickname} in {dbdir} failed: ' '{reason}') else: if 'certificate is valid' not in \ response.raw_output.decode('utf-8'): yield Result( self, constants.ERROR, key=key, dbdir=dbdir, nickname=nickname, reason="%s: %s" % (response.raw_output.decode('utf-8'), response.error_log), msg='Validation of {nickname} in {dbdir} failed: ' '{reason}') else: yield Result(self, constants.SUCCESS, dbdir=dbdir, nickname=nickname, key=key) finally: if ca_pw_fname: ipautil.remove_file(ca_pw_fname)
def check(self): fqdn = socket.getfqdn() requests = get_expected_requests(self.ca, self.ds, self.serverid) for request in requests: request_id = certmonger.get_request_id(request) if request_id is None: yield Result(self, constants.ERROR, key=request_id, msg='Found request id {key} but it is not tracked' 'by certmonger!?') continue ca_name = certmonger.get_request_value(request_id, 'ca-name') if ca_name != 'IPA': logger.debug('Skipping request %s with CA %s', request_id, ca_name) continue profile = certmonger.get_request_value(request_id, 'template_profile') if profile != 'caIPAserviceCert': logger.debug('Skipping request %s with profile %s', request_id, profile) continue certfile = None if request.get('cert-file') is not None: certfile = request.get('cert-file') try: cert = x509.load_certificate_from_file(certfile) except Exception as e: yield Result(self, constants.ERROR, key=request_id, certfile=certfile, error=str(e), msg='Unable to open cert file {certfile}: ' '{error}') continue elif request.get('cert-database') is not None: nickname = request.get('cert-nickname') dbdir = request.get('cert-database') try: db = certdb.NSSDatabase(dbdir) except Exception as e: yield Result(self, constants.ERROR, key=request_id, dbdir=dbdir, error=str(e), msg='Unable to open NSS database {dbdir}: ' '{error}') continue try: cert = db.get_cert(nickname) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, nickname=nickname, error=str(e), msg='Unable to retrieve certificate ' '\'{nickname}\' from {dbdir}: {error}') continue hostlist = [fqdn] if self.ca.is_configured() and certfile == paths.HTTPD_CERT_FILE: hostlist.append(f'{IPA_CA_RECORD}.{api.env.domain}') error = False for host in hostlist: if host not in cert.san_a_label_dns_names: error = True yield Result(self, constants.ERROR, key=request_id, hostname=host, san=cert.san_a_label_dns_names, ca=ca_name, profile=profile, msg='Certificate request id {key} with ' 'profile {profile} for CA {ca} does not ' 'have a DNS SAN {san} matching name ' '{hostname}') if not error: yield Result(self, constants.SUCCESS, key=request_id, hostname=hostlist, san=cert.san_a_label_dns_names, ca=ca_name, profile=profile)
def check(self): cm = certmonger._certmonger() all_requests = cm.obj_if.get_requests() for req in all_requests: request = certmonger._cm_dbus_object(cm.bus, cm, req, certmonger.DBUS_CM_REQUEST_IF, certmonger.DBUS_CM_IF, True) id = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'nickname') store = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'cert-storage') if store == 'FILE': certfile = str( request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'cert-file')) try: cert = x509.load_certificate_from_file(certfile) except Exception as e: yield Result(self, constants.ERROR, key=id, certfile=certfile, error=str(e), msg='Request id {key}: Unable to open cert ' 'file \'{certfile}\': {error}') continue elif store == 'NSSDB': nickname = str( request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'key_nickname')) dbdir = str( request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'cert_database')) try: db = certdb.NSSDatabase(dbdir) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, error=str(e), msg='Request id {key}: Unable to open NSS ' 'database \'{dbdir}\': {error}') continue try: cert = db.get_cert(nickname) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, nickname=nickname, error=str(e), msg='Request id {key}: Unable to retrieve ' 'cert \'{nickname}\' from \'{dbdir}\': ' '{error}') continue else: yield Result(self, constants.ERROR, key=id, store=store, msg='Request id {key}: Unknown certmonger ' 'storage type: {store}') continue now = datetime.utcnow() notafter = cert.not_valid_after if now > notafter: yield Result(self, constants.ERROR, key=id, expiration_date=generalized_time(notafter), msg='Request id {key} expired on ' '{expiration_date}') continue delta = notafter - now diff = int(delta.total_seconds() / DAY) if diff < int(self.config.cert_expiration_days): yield Result(self, constants.WARNING, key=id, expiration_date=generalized_time(notafter), days=diff, msg='Request id {key} expires in {days} ' 'days. certmonger should renew this ' 'automatically. Watch the status with' 'getcert list -i {key}.') else: yield Result(self, constants.SUCCESS, key=id)
def CreateSelfSignedCerts(self): """ Creates NSS DB on the Directory Instance Directory and creates self signed certificates using certutil command. :param: None :return bool: True if certs are created else Raises DirSrvException. Note: This method uses certdb function from ipapython to create NSS DB directory """ DSCertDBOjb = certdb.NSSDatabase(nssdir=self.DSInstPath) DSNSSPassPhrase = 'Secret123' (pwdfile_fd, pwd_file_path) = tempfile.mkstemp() os.write(pwdfile_fd, DSNSSPassPhrase) os.close(pwdfile_fd) #setup NSS DB with the password created DSCertDBOjb.create_db(pwd_file_path) #since there is no exception handling , we need to verify #if the nssdb is created properly, we check if cert8.db, #secmod.db and key3.db exists nss_db_file = ['cert8.db', 'key3.db', 'secmod.db'] for files in nss_db_file: if not exists(os.path.join(self.DSInstPath, files)): raise DirSrvException('Could not setup NSS DB on %s' % self.DSInstPath) # create Noise File noise = array.array('B', os.urandom(128)) (noise_fd, noise_name) = tempfile.mkstemp() os.write(noise_fd, noise) os.close(noise_fd) ca_args = ["-f", pwd_file_path, "-S", "-n", "Example CA", "-s", "CN=Example CA,O=Example,L=Raleigh,C=US", "-t", "CT,,", "-x", "-z", noise_name] stdin, stdout, return_code = DSCertDBOjb.run_certutil(ca_args) if return_code != 0: raise DirSrvException('Could not create Self signed CA Cert') server_dn = "CN=%s" % (self.DSInstHost) server_args = ["-f", pwd_file_path, "-S", "-n", "Server-Cert", "-s", server_dn, "-c", "Example CA", "-t", "u,u,u", "-v", "720", "-m", "1001", "-z", noise_name] stdin, stdout, return_code = DSCertDBOjb.run_certutil(server_args) if return_code != 0: raise DirSrvException('Could not create Server-Cert') os.remove(pwd_file_path) os.remove(noise_name) ##write password to pin.txt pin_file = os.path.join(self.DSInstPath, 'pin.txt') pin_fd = open(pin_file, "w") pin_fd.write('Internal (Software) Token:%s' % DSNSSPassPhrase) pin_fd.close() #all these files are to be owned by #dirsrv a/c DSUID = pwd.getpwnam(DS_USER) DSGID = grp.getgrnam(DS_GROUP) for files in nss_db_file: os.chown((os.path.join(self.DSInstPath, files)), DSUID.pw_uid, DSGID.gr_gid) os.chown(pin_file, DSUID.pw_uid, DSGID.gr_gid) os.chmod(pin_file, 0400) return True
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 realm = module.params.get('realm') hostname = module.params.get('hostname') servers = module.params.get('servers') debug = module.params.get('debug') fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) 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 NUM_VERSION >= 40500 and 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 argspec = inspect.getargspec(tmp_db.create_db) try: if NUM_VERSION > 40404: tmp_db.create_db() for i, cert in enumerate(ca_certs): tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), certdb.EXTERNAL_CA_TRUST_FLAGS) else: pwd_file = write_tmp_file(ipa_generate_password()) tmp_db.create_db(pwd_file.name) for i, cert in enumerate(ca_certs): tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), 'C,,') except CalledProcessError as e: 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 as e: module.fail_json(msg="Cannot get subject base from server: %s" % e) module.exit_json(changed=True, ca_enabled=ca_enabled, subject_base=subject_base)
def get_expected_requests(ca, ds, serverid): """Provide the expected certmonger tracking request data This list is based in part on certificate_renewal_update() in ipaserver/install/server/upgrade.py and various start_tracking_certificates() methods in *instance.py. The list is filtered depending on whether a CA is running and the certificates have been issued by IPA. :param ca: the CAInstance :param ds: the DSInstance :param serverid: the DS serverid name """ template = paths.CERTMONGER_COMMAND_TEMPLATE if api.Command.ca_is_enabled()['result']: requests = [ { 'cert-file': paths.RA_AGENT_PEM, 'key-file': paths.RA_AGENT_KEY, 'ca-name': RENEWAL_CA_NAME, 'cert-presave-command': template % 'renew_ra_cert_pre', 'cert-postsave-command': template % 'renew_ra_cert', }, ] else: requests = [] if ca.is_configured(): dogtag_reqs = ca.tracking_reqs.items() kra = krainstance.KRAInstance(api.env.realm) if kra.is_installed(): dogtag_reqs = itertools.chain(dogtag_reqs, kra.tracking_reqs.items()) for nick, profile in dogtag_reqs: req = { 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, 'cert-nickname': nick, 'ca-name': RENEWAL_CA_NAME, 'cert-presave-command': template % 'stop_pkicad', 'cert-postsave-command': (template % 'renew_ca_cert "{}"'.format(nick)), 'template-profile': profile, } requests.append(req) else: logger.debug('CA is not configured, skipping CA tracking') cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE) issued = is_ipa_issued_cert(api, cert) if issued is None: logger.debug('Unable to determine if \'%s\' was issued by IPA ' 'because no LDAP connection, assuming yes.') if issued or issued is None: requests.append({ 'cert-file': paths.HTTPD_CERT_FILE, 'key-file': paths.HTTPD_KEY_FILE, 'ca-name': 'IPA', 'cert-postsave-command': template % 'restart_httpd', }) else: logger.debug( 'HTTP cert not issued by IPA, \'%s\', skip tracking ' 'check', DN(cert.issuer)) # Check the ldap server cert if issued by IPA ds_nickname = ds.get_server_cert_nickname(serverid) ds_db_dirname = dsinstance.config_dirname(serverid) ds_db = certs.CertDB(api.env.realm, nssdir=ds_db_dirname) connected = api.Backend.ldap2.isconnected() if not connected: logger.debug('Unable to determine if \'%s\' was issued by IPA ' 'because no LDAP connection, assuming yes.') if not connected or ds_db.is_ipa_issued_cert(api, ds_nickname): requests.append({ 'cert-database': ds_db_dirname[:-1], 'cert-nickname': ds_nickname, 'ca-name': 'IPA', 'cert-postsave-command': '%s %s' % (template % 'restart_dirsrv', serverid), }) else: logger.debug('DS cert is not issued by IPA, skip tracking check') # Check if pkinit is enabled if os.path.exists(paths.KDC_CERT): pkinit_request_ca = krbinstance.get_pkinit_request_ca() requests.append({ 'cert-file': paths.KDC_CERT, 'key-file': paths.KDC_KEY, 'ca-name': pkinit_request_ca, 'cert-postsave-command': template % 'renew_kdc_cert', }) else: logger.debug('No KDC pkinit certificate') # See if a host certificate was issued. This is only to # prevent a false-positive if one is indeed installed. local = { paths.IPA_NSSDB_DIR: 'Local IPA host', paths.NSS_DB_DIR: 'IPA Machine Certificate - %s' % socket.getfqdn(), } for db, nickname in local.items(): nssdb = certdb.NSSDatabase(db) if nssdb.has_nickname(nickname): requests.append({ 'cert-database': db, 'cert-nickname': nickname, 'ca-name': 'IPA', }) return requests
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'), ), supports_check_mode = True, ) module._ansible_debug = True servers = module.params.get('servers') realm = module.params.get('realm') hostname = module.params.get('hostname') basedn = module.params.get('basedn') domain = module.params.get('domain') principal = module.params.get('principal') subject_base = module.params.get('subject_base') ca_enabled = module.params.get('ca_enabled') mkhomedir = module.params.get('mkhomedir') on_master = module.params.get('on_master') fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) ########################################################################### os.environ['KRB5CCNAME'] = CCACHE_FILE class Object(object): pass options = Object() options.dns_updates = False options.all_ip_addresses = False options.ip_addresses = None options.request_cert = False options.hostname = hostname options.preserve_sssd = False options.on_master = False options.conf_ssh = True options.conf_sshd = True options.conf_sudo = True options.primary = False options.permit = False options.krb5_offline_passwords = False options.create_sshfp = True ########################################################################## # Create IPA NSS database try: create_ipa_nssdb() except ipautil.CalledProcessError as e: module.fail_json(msg="Failed to create IPA NSS database: %s" % e) # Get CA certificates from the certificate store try: ca_certs = get_certs_from_ldap(servers[0], basedn, 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, 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) 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) # Add the CA certificates to the IPA NSS database module.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 as e: module.fail_json(msg="Failed to add %s to the IPA NSS database." % nickname) # Add the CA certificates to the platform-dependant systemwide CA store tasks.insert_ca_certs_into_systemwide_ca_store(ca_certs) if not on_master: client_dns(servers[0], hostname, options) configure_certmonger(fstore, subject_base, 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 ########################################################################## # Name Server Caching Daemon. Disable for SSSD, use otherwise # (if installed) nscd = services.knownservices.nscd if nscd.is_installed(): save_state(nscd, statestore) try: nscd_service_action = 'stop' nscd.stop() except Exception: module.warn("Failed to %s the %s daemon" % (nscd_service_action, nscd.service_name)) try: nscd.disable() except Exception: module.warn("Failed to disable %s daemon. Disable it manually." % nscd.service_name) nslcd = services.knownservices.nslcd if nslcd.is_installed(): save_state(nslcd, statestore) retcode, conf = (0, None) ########################################################################## # Modify nsswitch/pam stack tasks.modify_nsswitch_pam_stack(sssd=True, mkhomedir=mkhomedir, statestore=statestore) module.log("SSSD enabled") argspec = inspect.getargspec(services.service) if len(argspec.args) > 1: sssd = services.service('sssd', api) else: sssd = services.service('sssd') try: sssd.restart() except CalledProcessError: module.warn("SSSD service restart was unsuccessful.") try: sssd.enable() except CalledProcessError as e: module.warn( "Failed to enable automatic startup of the SSSD daemon: " "%s", e) if configure_openldap_conf(fstore, basedn, servers): module.log("Configured /etc/openldap/ldap.conf") else: module.log("Failed to configure /etc/openldap/ldap.conf") # Check that nss is working properly if not on_master: user = principal if user is None or user == "": user = "******" % domain module.log("Principal is not set when enrolling with OTP" "; using principal '%s' for 'getent passwd'" % user) elif '@' not in user: user = "******" % (user, 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. while n < 10 and not found: try: ipautil.run(["getent", "passwd", user]) found = True except Exception as e: time.sleep(1) n = n + 1 if not found: module.fail_json(msg="Unable to find '%s' user with 'getent " "passwd %s'!" % (user.split("@")[0], user)) if conf: module.log("Recognized configuration: %s" % conf) else: module.fail_json(msg= "Unable to reliably detect " "configuration. Check NSS setup manually.") try: hardcode_ldap_server(servers) except Exception as e: module.fail_json(msg="Adding hardcoded server name to " "/etc/ldap.conf failed: %s" % str(e)) ########################################################################## module.exit_json(changed=True, ca_enabled_ra=ca_enabled)
def check(self): cm = certmonger._certmonger() all_requests = cm.obj_if.get_requests() for req in all_requests: request = certmonger._cm_dbus_object(cm.bus, cm, req, certmonger.DBUS_CM_REQUEST_IF, certmonger.DBUS_CM_IF, True) id = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'nickname') store = request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'cert-storage') if store == 'FILE': certfile = str( request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'cert-file')) try: cert = x509.load_certificate_from_file(certfile) except Exception as e: yield Result(self, constants.ERROR, key=id, certfile=certfile, error=str(e), msg='Unable to open cert file \'%s\': %s' % (certfile, e)) continue elif store == 'NSSDB': nickname = str( request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'key_nickname')) dbdir = str( request.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF, 'cert_database')) try: db = certdb.NSSDatabase(dbdir) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, error=str(e), msg='Unable to open NSS database \'%s\': %s' % (dbdir, e)) continue try: cert = db.get_cert(nickname) except Exception as e: yield Result(self, constants.ERROR, key=id, dbdir=dbdir, nickname=nickname, error=str(e), msg='Unable to retrieve cert \'%s\' from ' '\'%s\': %s' % (nickname, dbdir, e)) continue else: yield Result(self, constants.ERROR, key=id, store=store, msg='Unknown certmonger storage type: %s' % store) continue now = datetime.utcnow() notafter = cert.not_valid_after if now > notafter: yield Result(self, constants.ERROR, key=id, expiration_date=generalized_time(notafter), msg='Request id %s expired on %s' % (id, generalized_time(notafter))) continue delta = notafter - now diff = int(delta.total_seconds() / DAY) if diff < self.config.cert_expiration_days: yield Result(self, constants.WARNING, key=id, expiration_date=generalized_time(notafter), days=diff, msg='Request id %s expires in %s days' % (id, diff)) else: yield Result(self, constants.SUCCESS, key=id)