mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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>
This commit is contained in:
parent
b720aa94e9
commit
0078e7a919
@ -62,6 +62,24 @@ if six.PY3:
|
|||||||
unicode = str
|
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
|
@contextlib.contextmanager
|
||||||
def ldap_connect():
|
def ldap_connect():
|
||||||
conn = None
|
conn = None
|
||||||
@ -210,6 +228,11 @@ def store_cert():
|
|||||||
if not cert:
|
if not cert:
|
||||||
return (REJECTED, "New certificate requests not supported")
|
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)
|
dercert = x509.normalize_certificate(cert)
|
||||||
|
|
||||||
dn = DN(('cn', nickname), ('cn', 'ca_renewal'),
|
dn = DN(('cn', nickname), ('cn', 'ca_renewal'),
|
||||||
@ -338,6 +361,12 @@ def retrieve_cert_continuous():
|
|||||||
if old_cert:
|
if old_cert:
|
||||||
old_cert = x509.normalize_certificate(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)
|
result = call_handler(retrieve_or_reuse_cert)
|
||||||
if result[0] != ISSUED:
|
if result[0] != ISSUED:
|
||||||
return result
|
return result
|
||||||
@ -393,13 +422,12 @@ def renew_ca_cert():
|
|||||||
cert = os.environ.get('CERTMONGER_CERTIFICATE')
|
cert = os.environ.get('CERTMONGER_CERTIFICATE')
|
||||||
if not cert:
|
if not cert:
|
||||||
return (REJECTED, "New certificate requests not supported")
|
return (REJECTED, "New certificate requests not supported")
|
||||||
is_self_signed = x509.is_self_signed(cert)
|
|
||||||
|
|
||||||
operation = os.environ.get('CERTMONGER_OPERATION')
|
operation = os.environ.get('CERTMONGER_OPERATION')
|
||||||
if operation == 'SUBMIT':
|
if operation == 'SUBMIT':
|
||||||
state = 'retrieve'
|
state = 'retrieve'
|
||||||
|
|
||||||
if is_self_signed:
|
if is_renewable():
|
||||||
ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False)
|
ca = cainstance.CAInstance(host_name=api.env.host, ldapi=False)
|
||||||
if ca.is_renewal_master():
|
if ca.is_renewal_master():
|
||||||
state = 'request'
|
state = 'request'
|
||||||
@ -419,10 +447,11 @@ def renew_ca_cert():
|
|||||||
|
|
||||||
if state == 'retrieve':
|
if state == 'retrieve':
|
||||||
result = call_handler(retrieve_cert)
|
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,
|
syslog.syslog(syslog.LOG_ALERT,
|
||||||
"IPA CA certificate is about to expire, "
|
"Certificate with subject '%s' is about to expire, "
|
||||||
"use ipa-cacert-manage to renew it")
|
"use ipa-cacert-manage to renew it"
|
||||||
|
% (os.environ.get("CERTMONGER_REQ_SUBJECT"),))
|
||||||
elif state == 'request':
|
elif state == 'request':
|
||||||
profile = os.environ['CERTMONGER_CA_PROFILE']
|
profile = os.environ['CERTMONGER_CA_PROFILE']
|
||||||
os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert'
|
os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert'
|
||||||
|
@ -29,7 +29,10 @@ from ipaplatform import services
|
|||||||
from ipaplatform.paths import paths
|
from ipaplatform.paths import paths
|
||||||
from ipaplatform.tasks import tasks
|
from ipaplatform.tasks import tasks
|
||||||
from ipalib import api, errors, x509, certstore
|
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):
|
class CertUpdate(admintool.AdminTool):
|
||||||
command_name = 'ipa-certupdate'
|
command_name = 'ipa-certupdate'
|
||||||
@ -76,18 +79,27 @@ class CertUpdate(admintool.AdminTool):
|
|||||||
version=u'2.0',
|
version=u'2.0',
|
||||||
)
|
)
|
||||||
ca_enabled = result['result']['enable_ra']
|
ca_enabled = result['result']['enable_ra']
|
||||||
api.Backend.rpcclient.disconnect()
|
|
||||||
|
|
||||||
ldap.do_sasl_gssapi_bind()
|
ldap.do_sasl_gssapi_bind()
|
||||||
|
|
||||||
certs = certstore.get_ca_certs(ldap, api.env.basedn,
|
certs = certstore.get_ca_certs(ldap, api.env.basedn,
|
||||||
api.env.realm, ca_enabled)
|
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:
|
finally:
|
||||||
shutil.rmtree(tmpdir)
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
server_fstore = sysrestore.FileStore(paths.SYSRESTORE)
|
server_fstore = sysrestore.FileStore(paths.SYSRESTORE)
|
||||||
if server_fstore.has_files():
|
if server_fstore.has_files():
|
||||||
self.update_server(certs)
|
self.update_server(certs)
|
||||||
|
for entry in lwcas:
|
||||||
|
self.server_track_lightweight_ca(entry)
|
||||||
|
|
||||||
self.update_client(certs)
|
self.update_client(certs)
|
||||||
|
|
||||||
@ -122,11 +134,10 @@ class CertUpdate(admintool.AdminTool):
|
|||||||
if services.knownservices.httpd.is_running():
|
if services.knownservices.httpd.is_running():
|
||||||
services.knownservices.httpd.restart()
|
services.knownservices.httpd.restart()
|
||||||
|
|
||||||
nickname = 'caSigningCert cert-pki-ca'
|
|
||||||
criteria = {
|
criteria = {
|
||||||
'cert-database': paths.PKI_TOMCAT_ALIAS_DIR,
|
'cert-database': paths.PKI_TOMCAT_ALIAS_DIR,
|
||||||
'cert-nickname': nickname,
|
'cert-nickname': IPA_CA_NICKNAME,
|
||||||
'ca-name': 'dogtag-ipa-ca-renew-agent',
|
'ca-name': RENEWAL_CA_NAME
|
||||||
}
|
}
|
||||||
request_id = certmonger.get_request_id(criteria)
|
request_id = certmonger.get_request_id(criteria)
|
||||||
if request_id is not None:
|
if request_id is not None:
|
||||||
@ -152,6 +163,39 @@ class CertUpdate(admintool.AdminTool):
|
|||||||
|
|
||||||
self.update_file(paths.CA_CRT, certs)
|
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):
|
def update_file(self, filename, certs, mode=0o444):
|
||||||
certs = (c[0] for c in certs if c[2] is not False)
|
certs = (c[0] for c in certs if c[2] is not False)
|
||||||
try:
|
try:
|
||||||
|
Loading…
Reference in New Issue
Block a user