diff options
author | Fraser Tweedale <ftweedal@redhat.com> | 2016-06-21 15:01:41 +1000 |
---|---|---|
committer | Jan Cholasta <jcholast@redhat.com> | 2016-06-29 08:52:29 +0200 |
commit | 0078e7a9192a940104d8f6621b33d24d814c109b (patch) | |
tree | 378d84d9d1e72c0ffa51dbe3a40f62d4f4f91ad5 | |
parent | b720aa94e9317b857734c08a69fe2dcc0d95bf68 (diff) | |
download | freeipa-0078e7a9192a940104d8f6621b33d24d814c109b.tar.gz freeipa-0078e7a9192a940104d8f6621b33d24d814c109b.tar.xz freeipa-0078e7a9192a940104d8f6621b33d24d814c109b.zip |
ipa-certupdate: track lightweight CA certificates
Enhance the ipa-certupdate program to add Certmonger tracking
requests for lightweight CA certificates.
Also update the dogtag-ipa-ca-renew-agent-submit to not store or
retrieve lightweight CA certificates, becaues Dogtag clones observe
renewals and update their NSSDBs on their own, and allow the helper
to request non-self-signed certificates.
Part of: https://fedorahosted.org/freeipa/ticket/4559
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
-rwxr-xr-x | install/certmonger/dogtag-ipa-ca-renew-agent-submit | 39 | ||||
-rw-r--r-- | ipaclient/ipa_certupdate.py | 52 |
2 files changed, 82 insertions, 9 deletions
diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit index 3f7333c0e..7ab3ec15d 100755 --- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit +++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit @@ -62,6 +62,24 @@ if six.PY3: unicode = str +IPA_CA_NICKNAME = 'caSigningCert cert-pki-ca' + +def get_nickname(): + csr = os.environ.get('CERTMONGER_CSR') + return pkcs10.get_friendlyname(csr) if csr else None + +def is_lightweight_ca(): + nickname = get_nickname() or '' + return nickname != IPA_CA_NICKNAME and nickname.startswith(IPA_CA_NICKNAME) + +def is_renewable(): + cert = os.environ.get('CERTMONGER_CERTIFICATE') + if not cert: + return False + else: + return x509.is_self_signed(cert) or is_lightweight_ca() + + @contextlib.contextmanager def ldap_connect(): conn = None @@ -210,6 +228,11 @@ def store_cert(): if not cert: return (REJECTED, "New certificate requests not supported") + if is_lightweight_ca(): + # Lightweight CAs are updated in Dogtag's NSSDB + # by Dogtag itself, so do not store it + return (ISSUED, cert) + dercert = x509.normalize_certificate(cert) dn = DN(('cn', nickname), ('cn', 'ca_renewal'), @@ -338,6 +361,12 @@ def retrieve_cert_continuous(): if old_cert: old_cert = x509.normalize_certificate(old_cert) + if is_lightweight_ca(): + # Lightweight CAs are updated in Dogtag's NSSDB + # by Dogtag itself, so do not try to retrieve it. + # Everything is fine as is. + return (ISSUED, os.environ.get('CERTMONGER_CERTIFICATE')) + result = call_handler(retrieve_or_reuse_cert) if result[0] != ISSUED: return result @@ -393,13 +422,12 @@ def renew_ca_cert(): cert = os.environ.get('CERTMONGER_CERTIFICATE') if not cert: return (REJECTED, "New certificate requests not supported") - is_self_signed = x509.is_self_signed(cert) operation = os.environ.get('CERTMONGER_OPERATION') if operation == 'SUBMIT': state = 'retrieve' - if is_self_signed: + if is_renewable(): ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False) if ca.is_renewal_master(): state = 'request' @@ -419,10 +447,11 @@ def renew_ca_cert(): if state == 'retrieve': result = call_handler(retrieve_cert) - if result[0] == REJECTED and not is_self_signed: + if result[0] == REJECTED and not is_renewable(): syslog.syslog(syslog.LOG_ALERT, - "IPA CA certificate is about to expire, " - "use ipa-cacert-manage to renew it") + "Certificate with subject '%s' is about to expire, " + "use ipa-cacert-manage to renew it" + % (os.environ.get("CERTMONGER_REQ_SUBJECT"),)) elif state == 'request': profile = os.environ['CERTMONGER_CA_PROFILE'] os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert' diff --git a/ipaclient/ipa_certupdate.py b/ipaclient/ipa_certupdate.py index b9572196c..e59047a27 100644 --- a/ipaclient/ipa_certupdate.py +++ b/ipaclient/ipa_certupdate.py @@ -29,7 +29,10 @@ from ipaplatform import services from ipaplatform.paths import paths from ipaplatform.tasks import tasks from ipalib import api, errors, x509, certstore +from ipalib.constants import IPA_CA_CN +IPA_CA_NICKNAME = 'caSigningCert cert-pki-ca' +RENEWAL_CA_NAME = 'dogtag-ipa-ca-renew-agent' class CertUpdate(admintool.AdminTool): command_name = 'ipa-certupdate' @@ -76,18 +79,27 @@ class CertUpdate(admintool.AdminTool): version=u'2.0', ) ca_enabled = result['result']['enable_ra'] - api.Backend.rpcclient.disconnect() ldap.do_sasl_gssapi_bind() certs = certstore.get_ca_certs(ldap, api.env.basedn, api.env.realm, ca_enabled) + + # find lightweight CAs (on renewal master only) + lwcas = [] + for ca_obj in api.Command.ca_find()['result']: + if IPA_CA_CN not in ca_obj['cn']: + lwcas.append(ca_obj) + + api.Backend.rpcclient.disconnect() finally: shutil.rmtree(tmpdir) server_fstore = sysrestore.FileStore(paths.SYSRESTORE) if server_fstore.has_files(): self.update_server(certs) + for entry in lwcas: + self.server_track_lightweight_ca(entry) self.update_client(certs) @@ -122,11 +134,10 @@ class CertUpdate(admintool.AdminTool): if services.knownservices.httpd.is_running(): services.knownservices.httpd.restart() - nickname = 'caSigningCert cert-pki-ca' criteria = { 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, - 'cert-nickname': nickname, - 'ca-name': 'dogtag-ipa-ca-renew-agent', + 'cert-nickname': IPA_CA_NICKNAME, + 'ca-name': RENEWAL_CA_NAME } request_id = certmonger.get_request_id(criteria) if request_id is not None: @@ -152,6 +163,39 @@ class CertUpdate(admintool.AdminTool): self.update_file(paths.CA_CRT, certs) + def server_track_lightweight_ca(self, entry): + nickname = "{} {}".format(IPA_CA_NICKNAME, entry['ipacaid'][0]) + criteria = { + 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, + 'cert-nickname': nickname, + 'ca-name': RENEWAL_CA_NAME, + } + request_id = certmonger.get_request_id(criteria) + if request_id is None: + try: + certmonger.dogtag_start_tracking( + secdir=paths.PKI_TOMCAT_ALIAS_DIR, + pin=certmonger.get_pin('internal'), + pinfile=None, + nickname=nickname, + ca=RENEWAL_CA_NAME, + pre_command='stop_pkicad', + post_command='renew_ca_cert "%s"' % nickname, + ) + request_id = certmonger.get_request_id(criteria) + certmonger.modify(request_id, profile='ipaCACertRenewal') + self.log.debug( + 'Lightweight CA renewal: ' + 'added tracking request for "%s"', nickname) + except RuntimeError as e: + self.log.error( + 'Lightweight CA renewal: Certmonger failed to ' + 'start tracking certificate: %s', e) + else: + self.log.debug( + 'Lightweight CA renewal: ' + 'already tracking certificate "%s"', nickname) + def update_file(self, filename, certs, mode=0o444): certs = (c[0] for c in certs if c[2] is not False) try: |