mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Use new certmonger locking to prevent NSS database corruption.
dogtag opens its NSS database in read/write mode so we need to be very careful during renewal that we don't also open it up read/write. We basically need to serialize access to the database. certmonger does the majority of this work via internal locking from the point where it generates a new key/submits a rewewal through the pre_save and releases the lock after the post_save command. This lock is held per NSS database so we're save from certmonger. dogtag needs to be shutdown in the pre_save state so certmonger can safely add the certificate and we can manipulate trust in the post_save command. Fix a number of bugs in renewal. The CA wasn't actually being restarted at all due to a naming change upstream. In python we need to reference services using python-ish names but the service is pki-cad. We need a translation for non-Fedora systems as well. Update the CA ou=People entry when he CA subsystem certificate is renewed. This certificate is used as an identity certificate to bind to the DS instance. https://fedorahosted.org/freeipa/ticket/3292 https://fedorahosted.org/freeipa/ticket/3322
This commit is contained in:
@@ -35,11 +35,13 @@ import urllib
|
||||
import xml.dom.minidom
|
||||
import stat
|
||||
import socket
|
||||
import syslog
|
||||
import ConfigParser
|
||||
from ipapython import dogtag
|
||||
from ipapython.certdb import get_ca_nickname
|
||||
from ipapython import certmonger
|
||||
from ipalib import pkcs10, x509
|
||||
from ipalib import errors
|
||||
from ipapython.dn import DN
|
||||
import subprocess
|
||||
import traceback
|
||||
@@ -1048,7 +1050,11 @@ class CAInstance(service.Service):
|
||||
|
||||
On upgrades this needs to be called from ipa-upgradeconfig.
|
||||
"""
|
||||
certmonger.dogtag_start_tracking('dogtag-ipa-retrieve-agent-submit', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', 'restart_httpd')
|
||||
try:
|
||||
certmonger.dogtag_start_tracking('dogtag-ipa-retrieve-agent-submit', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', None, 'restart_httpd')
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
root_logger.error(
|
||||
"certmonger failed to start tracking certificate: %s" % str(e))
|
||||
|
||||
def __configure_ra(self):
|
||||
# Create an RA user in the CA LDAP server and add that user to
|
||||
@@ -1534,11 +1540,19 @@ class CAInstance(service.Service):
|
||||
'Unable to determine PIN for CA instance: %s' % str(e))
|
||||
|
||||
def track_servercert(self):
|
||||
"""
|
||||
Specifically do not tell certmonger to restart the CA. This will be
|
||||
done by the renewal script, renew_ca_cert once all the subsystem
|
||||
certificates are renewed.
|
||||
"""
|
||||
pin = self.__get_ca_pin()
|
||||
certmonger.dogtag_start_tracking(
|
||||
'dogtag-ipa-renew-agent', 'Server-Cert cert-pki-ca', pin, None,
|
||||
self.dogtag_constants.ALIAS_DIR,
|
||||
'restart_pkicad "Server-Cert cert-pki-ca"')
|
||||
try:
|
||||
certmonger.dogtag_start_tracking(
|
||||
'dogtag-ipa-renew-agent', 'Server-Cert cert-pki-ca', pin, None,
|
||||
self.dogtag_constants.ALIAS_DIR, None, None)
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
root_logger.error(
|
||||
"certmonger failed to start tracking certificate: %s" % str(e))
|
||||
|
||||
def configure_renewal(self):
|
||||
cmonger = ipaservices.knownservices.certmonger
|
||||
@@ -1552,12 +1566,20 @@ class CAInstance(service.Service):
|
||||
for nickname in ['auditSigningCert cert-pki-ca',
|
||||
'ocspSigningCert cert-pki-ca',
|
||||
'subsystemCert cert-pki-ca']:
|
||||
certmonger.dogtag_start_tracking(
|
||||
'dogtag-ipa-renew-agent', nickname, pin, None,
|
||||
self.dogtag_constants.ALIAS_DIR, 'renew_ca_cert "%s"' % nickname)
|
||||
try:
|
||||
certmonger.dogtag_start_tracking(
|
||||
'dogtag-ipa-renew-agent', nickname, pin, None,
|
||||
self.dogtag_constants.ALIAS_DIR, 'stop_pkicad', 'renew_ca_cert "%s"' % nickname)
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
root_logger.error(
|
||||
"certmonger failed to start tracking certificate: %s" % str(e))
|
||||
|
||||
# Set up the agent cert for renewal
|
||||
certmonger.dogtag_start_tracking('dogtag-ipa-renew-agent', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', 'renew_ra_cert')
|
||||
try:
|
||||
certmonger.dogtag_start_tracking('dogtag-ipa-renew-agent', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', None, 'renew_ra_cert')
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
root_logger.error(
|
||||
"certmonger failed to start tracking certificate: %s" % str(e))
|
||||
|
||||
def configure_certmonger_renewal(self):
|
||||
"""
|
||||
@@ -1595,10 +1617,14 @@ class CAInstance(service.Service):
|
||||
for nickname in ['auditSigningCert cert-pki-ca',
|
||||
'ocspSigningCert cert-pki-ca',
|
||||
'subsystemCert cert-pki-ca']:
|
||||
certmonger.dogtag_start_tracking(
|
||||
'dogtag-ipa-retrieve-agent-submit', nickname, pin, None,
|
||||
self.dogtag_constants.ALIAS_DIR,
|
||||
'restart_pkicad "%s"' % nickname)
|
||||
try:
|
||||
certmonger.dogtag_start_tracking(
|
||||
'dogtag-ipa-retrieve-agent-submit', nickname, pin, None,
|
||||
self.dogtag_constants.ALIAS_DIR, 'stop_pkicad',
|
||||
'restart_pkicad "%s"' % nickname)
|
||||
except (ipautil.CalledProcessError, RuntimeError), e:
|
||||
root_logger.error(
|
||||
"certmonger failed to start tracking certificate: %s" % str(e))
|
||||
|
||||
# The agent renewal is configured in import_ra_cert which is called
|
||||
# after the HTTP instance is created.
|
||||
@@ -1861,6 +1887,67 @@ def update_cert_config(nickname, cert):
|
||||
base64.b64encode(cert),
|
||||
quotes=False, separator='=')
|
||||
|
||||
def update_people_entry(uid, dercert):
|
||||
"""
|
||||
Update the userCerticate for an entry in the dogtag ou=People. This
|
||||
is needed when a certificate is renewed.
|
||||
|
||||
uid: uid of user to update
|
||||
dercert: An X509.3 certificate in DER format
|
||||
|
||||
Logging is done via syslog
|
||||
|
||||
Returns True or False
|
||||
"""
|
||||
dn = DN(('uid',uid),('ou','People'),('o','ipaca'))
|
||||
serial_number = x509.get_serial_number(dercert, datatype=x509.DER)
|
||||
subject = x509.get_subject(dercert, datatype=x509.DER)
|
||||
issuer = x509.get_issuer(dercert, datatype=x509.DER)
|
||||
|
||||
attempts = 0
|
||||
dogtag_uri='ldap://localhost:%d' % DEFAULT_DSPORT
|
||||
updated = False
|
||||
|
||||
try:
|
||||
dm_password = certmonger.get_pin('internaldb')
|
||||
except IOError, e:
|
||||
syslog.syslog(syslog.LOG_ERR, 'Unable to determine PIN for CA instance: %s' % e)
|
||||
return False
|
||||
|
||||
while attempts < 10:
|
||||
conn = None
|
||||
try:
|
||||
conn = ldap2.ldap2(shared_instance=False, ldap_uri=dogtag_uri)
|
||||
conn.connect(bind_dn=DN(('cn', 'directory manager')),
|
||||
bind_pw=dm_password)
|
||||
(entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'],
|
||||
normalize=False)
|
||||
entry_attrs['usercertificate'].append(dercert)
|
||||
entry_attrs['description'] = '2;%d;%s;%s' % (serial_number, issuer,
|
||||
subject)
|
||||
conn.update_entry(dn, entry_attrs, normalize=False)
|
||||
updated = True
|
||||
break
|
||||
except errors.NetworkError:
|
||||
syslog.syslog(syslog.LOG_ERR, 'Connection to %s failed, sleeping 30s' % dogtag_uri)
|
||||
time.sleep(30)
|
||||
attempts += 1
|
||||
except errors.EmptyModlist:
|
||||
updated = True
|
||||
break
|
||||
except Exception, e:
|
||||
syslog.syslog(syslog.LOG_ERR, 'Updating %s entry failed: %s' % (str(dn), e))
|
||||
break
|
||||
finally:
|
||||
if conn.isconnected():
|
||||
conn.disconnect()
|
||||
|
||||
if not updated:
|
||||
syslog.syslog(syslog.LOG_ERR, 'Update failed.')
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
standard_logging_setup("install.log")
|
||||
if not dogtag.install_constants.SHARED_DB:
|
||||
|
Reference in New Issue
Block a user