def resubmit_request(self, ca=RENEWAL_CA_NAME, profile=None): timeout = api.env.startup_timeout + 60 cm_profile = None if isinstance(profile, cainstance.MSCSTemplateV1): cm_profile = profile.unparsed_input cm_template = None if isinstance(profile, cainstance.MSCSTemplateV2): cm_template = profile.unparsed_input logger.debug("resubmitting certmonger request '%s'", self.request_id) certmonger.resubmit_request(self.request_id, ca=ca, profile=cm_profile, template_v2=cm_template, is_ca=True) try: state = certmonger.wait_for_request(self.request_id, timeout) except RuntimeError: raise admintool.ScriptError( "Resubmitting certmonger request '%s' timed out, " "please check the request manually" % self.request_id) ca_error = certmonger.get_request_value(self.request_id, 'ca-error') if state != 'MONITORING' or ca_error: raise admintool.ScriptError( "Error resubmitting certmonger request '%s', " "please check the request manually" % self.request_id) logger.debug("modifying certmonger request '%s'", self.request_id) certmonger.modify(self.request_id, ca=RENEWAL_CA_NAME, profile='', template_v2='')
def get_csr_from_certmonger(nickname): """ Get the csr for the provided nickname by asking certmonger. Returns the csr in ASCII format without the header/footer in a single line or None if not found. """ criteria = { 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, 'cert-nickname': nickname, } id = certmonger.get_request_id(criteria) if id: csr = certmonger.get_request_value(id, "csr") if csr: try: # Make sure the value can be parsed as valid CSR csr_obj = crypto_x509.load_pem_x509_csr( csr.encode('ascii'), default_backend()) val = base64.b64encode(csr_obj.public_bytes(x509.Encoding.DER)) return val.decode('ascii') except Exception as e: # Fallthrough and return None logger.debug("Unable to get CSR from certmonger: %s", e) return None
def check_dates(self): """Check validity dates""" # TODO: make this configurable threshold = 7 # days requests = self.get_requests() now = datetime.datetime.utcnow() for request in requests: request_id = certmonger.get_request_id(request) if request_id is None: # The missing tracking is reported in check_tracking() continue nickname = request.get('cert-nickname') rawcert = certmonger.get_request_value(request_id, 'cert') cert = load_pem_certificate(str(rawcert)) diff = cert.not_valid_after - now if diff.days < 0: # TODO: this is false-positive generator self.failure("Certificate %s is expired" % nickname) elif diff.days < threshold: self.failure("Certificate %s is expiring soon" % nickname) elif cert.not_valid_before > now: self.failure("Certificate %s is not valid yet" % nickname)
def get_pkinit_request_ca(): """ Return the certmonger CA name which is serving the PKINIT certificate request. If the certificate is not tracked by Certmonger, return None """ pkinit_request_id = certmonger.get_request_id( {'cert-file': paths.KDC_CERT}) if pkinit_request_id is None: return return certmonger.get_request_value(pkinit_request_id, 'ca-name')
def update_server(certs): instance = '-'.join(api.env.realm.split('.')) update_db(paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs) if services.knownservices.dirsrv.is_running(): services.knownservices.dirsrv.restart(instance) if services.knownservices.httpd.is_running(): services.knownservices.httpd.restart() criteria = { 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, 'cert-nickname': IPA_CA_NICKNAME, 'ca-name': RENEWAL_CA_NAME, } request_id = certmonger.get_request_id(criteria) if request_id is not None: timeout = api.env.startup_timeout + 60 # The dogtag-ipa-ca-renew-agent-reuse Certmonger CA never # actually renews the certificate; it only pulls it from the # ca_renewal LDAP cert store. # # Why is this needed? If the CA cert gets renewed long # before its notAfter (expiry) date (e.g. to switch from # self-signed to external, or to switch to new external CA), # then the other (i.e. not caRenewalMaster) CA replicas will # not promptly pick up the new CA cert. So we make # ipa-certupdate always check for an updated CA cert. # logger.debug("resubmitting certmonger request '%s'", request_id) certmonger.resubmit_request( request_id, ca='dogtag-ipa-ca-renew-agent-reuse', profile='') try: state = certmonger.wait_for_request(request_id, timeout) except RuntimeError: raise admintool.ScriptError( "Resubmitting certmonger request '%s' timed out, " "please check the request manually" % request_id) ca_error = certmonger.get_request_value(request_id, 'ca-error') if state != 'MONITORING' or ca_error: raise admintool.ScriptError( "Error resubmitting certmonger request '%s', " "please check the request manually" % request_id) logger.debug("modifying certmonger request '%s'", request_id) certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent') update_file(paths.CA_CRT, certs) update_file(paths.CACERT_PEM, certs)
def resubmit_request(self, ca, profile): timeout = api.env.startup_timeout + 60 self.log.debug("resubmitting certmonger request '%s'", self.request_id) certmonger.resubmit_request(self.request_id, profile=profile) try: state = certmonger.wait_for_request(self.request_id, timeout) except RuntimeError: raise admintool.ScriptError( "Resubmitting certmonger request '%s' timed out, " "please check the request manually" % self.request_id) ca_error = certmonger.get_request_value(self.request_id, 'ca-error') if state != 'MONITORING' or ca_error: raise admintool.ScriptError( "Error resubmitting certmonger request '%s', " "please check the request manually" % self.request_id) self.log.debug("modifying certmonger request '%s'", self.request_id) certmonger.modify(self.request_id, profile='ipaCACertRenewal')
def update_server(self, certs): instance = '-'.join(api.env.realm.split('.')) self.update_db(paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs) if services.knownservices.dirsrv.is_running(): services.knownservices.dirsrv.restart(instance) self.update_db(paths.HTTPD_ALIAS_DIR, certs) if services.knownservices.httpd.is_running(): services.knownservices.httpd.restart() criteria = { 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, 'cert-nickname': IPA_CA_NICKNAME, 'ca-name': RENEWAL_CA_NAME } request_id = certmonger.get_request_id(criteria) if request_id is not None: timeout = api.env.startup_timeout + 60 logger.debug("resubmitting certmonger request '%s'", request_id) certmonger.resubmit_request(request_id, ca='dogtag-ipa-ca-renew-agent-reuse', profile='') try: state = certmonger.wait_for_request(request_id, timeout) except RuntimeError: raise admintool.ScriptError( "Resubmitting certmonger request '%s' timed out, " "please check the request manually" % request_id) ca_error = certmonger.get_request_value(request_id, 'ca-error') if state != 'MONITORING' or ca_error: raise admintool.ScriptError( "Error resubmitting certmonger request '%s', " "please check the request manually" % request_id) logger.debug("modifying certmonger request '%s'", request_id) certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent') self.update_file(paths.CA_CRT, certs) self.update_file(paths.CACERT_PEM, certs)
def update_server(self, certs): instance = '-'.join(api.env.realm.split('.')) self.update_db( paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs) if services.knownservices.dirsrv.is_running(): services.knownservices.dirsrv.restart(instance) self.update_db(paths.HTTPD_ALIAS_DIR, certs) if services.knownservices.httpd.is_running(): services.knownservices.httpd.restart() criteria = { 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, 'cert-nickname': IPA_CA_NICKNAME, 'ca-name': RENEWAL_CA_NAME } request_id = certmonger.get_request_id(criteria) if request_id is not None: timeout = api.env.startup_timeout + 60 logger.debug("resubmitting certmonger request '%s'", request_id) certmonger.resubmit_request( request_id, ca='dogtag-ipa-ca-renew-agent-reuse', profile='') try: state = certmonger.wait_for_request(request_id, timeout) except RuntimeError: raise admintool.ScriptError( "Resubmitting certmonger request '%s' timed out, " "please check the request manually" % request_id) ca_error = certmonger.get_request_value(request_id, 'ca-error') if state != 'MONITORING' or ca_error: raise admintool.ScriptError( "Error resubmitting certmonger request '%s', " "please check the request manually" % request_id) logger.debug("modifying certmonger request '%s'", request_id) certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent') self.update_file(paths.CA_CRT, certs) self.update_file(paths.CACERT_PEM, certs)
def resubmit_request(self, ca='dogtag-ipa-ca-renew-agent', profile=''): timeout = api.env.startup_timeout + 60 logger.debug("resubmitting certmonger request '%s'", self.request_id) certmonger.resubmit_request(self.request_id, ca=ca, profile=profile, is_ca=True) try: state = certmonger.wait_for_request(self.request_id, timeout) except RuntimeError: raise admintool.ScriptError( "Resubmitting certmonger request '%s' timed out, " "please check the request manually" % self.request_id) ca_error = certmonger.get_request_value(self.request_id, 'ca-error') if state != 'MONITORING' or ca_error: raise admintool.ScriptError( "Error resubmitting certmonger request '%s', " "please check the request manually" % self.request_id) logger.debug("modifying certmonger request '%s'", self.request_id) certmonger.modify(self.request_id, ca='dogtag-ipa-ca-renew-agent', profile='')
def execute(self, **options): ca = cainstance.CAInstance(self.api.env.realm, certs.NSS_DIR) if not ca.is_configured(): self.debug("CA is not configured on this host") return False, [] ldap = self.api.Backend.ldap2 base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) dn = DN(('cn', 'CA'), ('cn', self.api.env.host), base_dn) filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))' try: entries = ldap.get_entries(base_dn=base_dn, filter=filter, attrs_list=[]) except errors.NotFound: pass else: self.debug("found CA renewal master %s", entries[0].dn[1].value) master = False updates = [] for entry in entries: if entry.dn == dn: master = True continue updates.append({ 'dn': entry.dn, 'updates': [ dict(action='remove', attr='ipaConfigString', value='caRenewalMaster') ], }) if master: return False, updates else: return False, [] criteria = { 'cert-database': paths.HTTPD_ALIAS_DIR, 'cert-nickname': 'ipaCert', } request_id = certmonger.get_request_id(criteria) if request_id is not None: self.debug("found certmonger request for ipaCert") ca_name = certmonger.get_request_value(request_id, 'ca-name') if ca_name is None: self.warning( "certmonger request for ipaCert is missing ca_name, " "assuming local CA is renewal slave") return False, [] ca_name = ca_name.strip() if ca_name == 'dogtag-ipa-renew-agent': pass elif ca_name == 'dogtag-ipa-retrieve-agent-submit': return False, [] elif ca_name == 'dogtag-ipa-ca-renew-agent': return False, [] else: self.warning( "certmonger request for ipaCert has unknown ca_name '%s', " "assuming local CA is renewal slave", ca_name) return False, [] else: self.debug("certmonger request for ipaCert not found") config = installutils.get_directive(paths.CA_CS_CFG_PATH, 'subsystem.select', '=') if config == 'New': pass elif config == 'Clone': return False, [] else: self.warning( "CS.cfg has unknown subsystem.select value '%s', " "assuming local CA is renewal slave", config) return (False, False, []) update = { 'dn': dn, 'updates': [ dict(action='add', attr='ipaConfigString', value='caRenewalMaster') ], } return False, [update]
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 execute(self, **options): ca = cainstance.CAInstance(self.api.env.realm) if not ca.is_configured(): logger.debug("CA is not configured on this host") return False, [] ldap = self.api.Backend.ldap2 base_dn = DN(self.api.env.container_masters, self.api.env.basedn) dn = DN(('cn', 'CA'), ('cn', self.api.env.host), base_dn) filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))' try: entries = ldap.get_entries(base_dn=base_dn, filter=filter, attrs_list=[]) except errors.NotFound: pass else: logger.debug("found CA renewal master %s", entries[0].dn[1].value) master = False updates = [] for entry in entries: if entry.dn == dn: master = True continue updates.append({ 'dn': entry.dn, 'updates': [ dict(action='remove', attr='ipaConfigString', value='caRenewalMaster') ], }) if master: return False, updates else: return False, [] criteria = { 'cert-file': paths.RA_AGENT_PEM, } request_id = certmonger.get_request_id(criteria) if request_id is not None: logger.debug("found certmonger request for RA cert") ca_name = certmonger.get_request_value(request_id, 'ca-name') if ca_name is None: logger.warning( "certmonger request for RA cert is missing ca_name, " "assuming local CA is renewal slave") return False, [] ca_name = ca_name.strip() if ca_name == 'dogtag-ipa-renew-agent': pass elif ca_name == 'dogtag-ipa-retrieve-agent-submit': return False, [] elif ca_name == 'dogtag-ipa-ca-renew-agent': return False, [] else: logger.warning( "certmonger request for RA cert has unknown ca_name '%s', " "assuming local CA is renewal slave", ca_name) return False, [] else: logger.debug("certmonger request for RA cert not found") config = directivesetter.get_directive( paths.CA_CS_CFG_PATH, 'subsystem.select', '=') if config == 'New': pass elif config == 'Clone': return False, [] else: logger.warning( "CS.cfg has unknown subsystem.select value '%s', " "assuming local CA is renewal slave", config) return (False, False, []) update = { 'dn': dn, 'updates': [ dict(action='add', attr='ipaConfigString', value='caRenewalMaster') ], } return False, [update]