diff options
author | Jan Cholasta <jcholast@redhat.com> | 2015-01-08 09:06:46 +0000 |
---|---|---|
committer | Jan Cholasta <jcholast@redhat.com> | 2015-01-13 18:34:59 +0000 |
commit | b9ae7690489368ead9f4983d386fa210dc265dfa (patch) | |
tree | 25437961e983a3a239541f9482e69ff70941c32c /ipaserver | |
parent | 6a1304324fe94b17e8dc4a418f90bea028160ace (diff) | |
download | freeipa-b9ae7690489368ead9f4983d386fa210dc265dfa.tar.gz freeipa-b9ae7690489368ead9f4983d386fa210dc265dfa.tar.xz freeipa-b9ae7690489368ead9f4983d386fa210dc265dfa.zip |
Make certificate renewal process synchronized
Synchronization is achieved using a global renewal lock.
https://fedorahosted.org/freeipa/ticket/4803
Reviewed-By: David Kupka <dkupka@redhat.com>
Diffstat (limited to 'ipaserver')
-rw-r--r-- | ipaserver/install/cainstance.py | 42 | ||||
-rw-r--r-- | ipaserver/install/certs.py | 104 | ||||
-rw-r--r-- | ipaserver/install/dogtaginstance.py | 3 | ||||
-rw-r--r-- | ipaserver/install/httpinstance.py | 42 |
4 files changed, 189 insertions, 2 deletions
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index ea982dc21..2c6933be1 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -38,6 +38,8 @@ import time import tempfile import urllib import xml.dom.minidom +import shlex +import pipes from ipalib import api from ipalib import pkcs10, x509 @@ -1304,6 +1306,16 @@ class CAInstance(DogtagInstance): if path: iface.remove_known_ca(path) + helper = self.restore_state('certmonger_dogtag_helper') + if helper: + path = iface.find_ca_by_nickname('dogtag-ipa-renew-agent') + if path: + ca_obj = bus.get_object('org.fedorahosted.certmonger', path) + ca_iface = dbus.Interface(ca_obj, + 'org.freedesktop.DBus.Properties') + ca_iface.Set('org.fedorahosted.certmonger.ca', + 'external-helper', helper) + cmonger.stop() # remove CRL files @@ -1332,6 +1344,36 @@ class CAInstance(DogtagInstance): fd.close() os.chmod(location, 0444) + + def configure_certmonger_renewal(self): + super(CAInstance, self).configure_certmonger_renewal() + + self.configure_certmonger_renewal_guard() + + def configure_certmonger_renewal_guard(self): + if not self.is_configured(): + return + + bus = dbus.SystemBus() + obj = bus.get_object('org.fedorahosted.certmonger', + '/org/fedorahosted/certmonger') + iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') + path = iface.find_ca_by_nickname('dogtag-ipa-renew-agent') + if path: + ca_obj = bus.get_object('org.fedorahosted.certmonger', path) + ca_iface = dbus.Interface(ca_obj, + 'org.freedesktop.DBus.Properties') + helper = ca_iface.Get('org.fedorahosted.certmonger.ca', + 'external-helper') + if helper: + args = shlex.split(helper) + if args[0] != paths.IPA_SERVER_GUARD: + self.backup_state('certmonger_dogtag_helper', helper) + args = [paths.IPA_SERVER_GUARD] + args + helper = ' '.join(pipes.quote(a) for a in args) + ca_iface.Set('org.fedorahosted.certmonger.ca', + 'external-helper', helper) + def configure_agent_renewal(self): try: certmonger.dogtag_start_tracking( diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py index 7292cbbe3..bc7dccf80 100644 --- a/ipaserver/install/certs.py +++ b/ipaserver/install/certs.py @@ -26,6 +26,10 @@ import xml.dom.minidom import pwd import base64 from hashlib import sha1 +import fcntl +import time +import datetime +import ConfigParser as configparser from ipapython.ipa_log_manager import root_logger from ipapython import dogtag @@ -647,3 +651,103 @@ class CertDB(object): def export_pem_cert(self, nickname, location): return self.nssdb.export_pem_cert(nickname, location) + + +class _CrossProcessLock(object): + _DATETIME_FORMAT = '%Y%m%d%H%M%S%f' + + def __init__(self, filename): + self._filename = filename + + def __enter__(self): + self.acquire() + + def __exit__(self, exc_type, exc_value, traceback): + self.release() + + def acquire(self, owner=None): + self._do(self._acquire, owner) + + def release(self, owner=None): + self._do(self._release, owner) + + def _acquire(self, owner): + now = datetime.datetime.utcnow() + + if self._locked and now >= self._expire: + self._locked = False + + if self._locked: + return False + + self._locked = True + self._owner = owner + self._expire = now + datetime.timedelta(hours=1) + + return True + + def _release(self, owner): + if not self._locked or self._owner != owner: + raise RuntimeError("lock not acquired by %s" % owner) + + self._locked = False + self._owner = None + self._expire = None + + return True + + def _do(self, func, owner): + if owner is None: + owner = '%s[%s]' % (os.path.basename(sys.argv[0]), os.getpid()) + + while True: + with open(self._filename, 'a+') as f: + fcntl.flock(f, fcntl.LOCK_EX) + + f.seek(0) + self._read(f) + + if func(owner): + f.seek(0) + f.truncate() + self._write(f) + return + + time.sleep(10) + + def _read(self, fileobj): + p = configparser.RawConfigParser() + p.readfp(fileobj) + + try: + self._locked = p.getboolean('lock', 'locked') + + if self._locked: + self._owner = p.get('lock', 'owner') + + expire = p.get('lock', 'expire') + try: + self._expire = datetime.datetime.strptime( + expire, self._DATETIME_FORMAT) + except ValueError: + raise configparser.Error + except configparser.Error: + self._locked = False + self._owner = None + self._expire = None + + def _write(self, fileobj): + p = configparser.RawConfigParser() + p.add_section('lock') + + locked = '1' if self._locked else '0' + p.set('lock', 'locked', locked) + + if self._locked: + expire = self._expire.strftime(self._DATETIME_FORMAT) + p.set('lock', 'owner', self._owner) + p.set('lock', 'expire', expire) + + p.write(fileobj) + +renewal_lock = _CrossProcessLock(paths.IPA_RENEWAL_LOCK) diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py index 2f984b814..83ce0ca50 100644 --- a/ipaserver/install/dogtaginstance.py +++ b/ipaserver/install/dogtaginstance.py @@ -296,8 +296,7 @@ class DogtagInstance(service.Service): with open(paths.HTTPD_IPA_PKI_PROXY_CONF, "w") as fd: fd.write(template) - @staticmethod - def configure_certmonger_renewal(): + def configure_certmonger_renewal(self): """ Create a new CA type for certmonger that will retrieve updated certificates from the dogtag master server. diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py index f9e020039..2fb315b6b 100644 --- a/ipaserver/install/httpinstance.py +++ b/ipaserver/install/httpinstance.py @@ -23,6 +23,9 @@ import tempfile import pwd import shutil import re +import dbus +import shlex +import pipes import service import certs @@ -121,6 +124,9 @@ class HTTPInstance(service.Service): self.step("enabling mod_nss renegotiate", self.enable_mod_nss_renegotiate) self.step("adding URL rewriting rules", self.__add_include) self.step("configuring httpd", self.__configure_http) + if self.ca_is_configured: + self.step("configure certmonger for renewals", + self.configure_certmonger_renewal_guard) self.step("setting up ssl", self.__setup_ssl) self.step("importing CA certificates from LDAP", self.__import_ca_certs) if autoconfig: @@ -221,6 +227,27 @@ class HTTPInstance(service.Service): if installutils.update_file(paths.HTTPD_NSS_CONF, '</VirtualHost>', 'Include conf.d/ipa-rewrite.conf\n</VirtualHost>') != 0: print "Adding Include conf.d/ipa-rewrite to %s failed." % paths.HTTPD_NSS_CONF + def configure_certmonger_renewal_guard(self): + bus = dbus.SystemBus() + obj = bus.get_object('org.fedorahosted.certmonger', + '/org/fedorahosted/certmonger') + iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') + path = iface.find_ca_by_nickname('IPA') + if path: + ca_obj = bus.get_object('org.fedorahosted.certmonger', path) + ca_iface = dbus.Interface(ca_obj, + 'org.freedesktop.DBus.Properties') + helper = ca_iface.Get('org.fedorahosted.certmonger.ca', + 'external-helper') + if helper: + args = shlex.split(helper) + if args[0] != paths.IPA_SERVER_GUARD: + self.backup_state('certmonger_ipa_helper', helper) + args = [paths.IPA_SERVER_GUARD] + args + helper = ' '.join(pipes.quote(a) for a in args) + ca_iface.Set('org.fedorahosted.certmonger.ca', + 'external-helper', helper) + def __setup_ssl(self): fqdn = self.fqdn @@ -355,6 +382,21 @@ class HTTPInstance(service.Service): self.stop() self.stop_tracking_certificates() + + helper = self.restore_state('certmonger_ipa_helper') + if helper: + bus = dbus.SystemBus() + obj = bus.get_object('org.fedorahosted.certmonger', + '/org/fedorahosted/certmonger') + iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') + path = iface.find_ca_by_nickname('IPA') + if path: + ca_obj = bus.get_object('org.fedorahosted.certmonger', path) + ca_iface = dbus.Interface(ca_obj, + 'org.freedesktop.DBus.Properties') + ca_iface.Set('org.fedorahosted.certmonger.ca', + 'external-helper', helper) + if not enabled is None and not enabled: self.disable() |