|
|
e3ffab |
From c0d13f5e58cb84eb3162aec1c2202329230c120d Mon Sep 17 00:00:00 2001
|
|
|
e3ffab |
From: Jan Cholasta <jcholast@redhat.com>
|
|
|
e3ffab |
Date: Thu, 8 Jan 2015 09:06:46 +0000
|
|
|
e3ffab |
Subject: [PATCH] Make certificate renewal process synchronized
|
|
|
e3ffab |
|
|
|
e3ffab |
Synchronization is achieved using a global renewal lock.
|
|
|
e3ffab |
|
|
|
e3ffab |
https://fedorahosted.org/freeipa/ticket/4803
|
|
|
e3ffab |
|
|
|
e3ffab |
Reviewed-By: David Kupka <dkupka@redhat.com>
|
|
|
e3ffab |
---
|
|
|
e3ffab |
freeipa.spec.in | 1 +
|
|
|
e3ffab |
install/certmonger/Makefile.am | 1 +
|
|
|
e3ffab |
.../certmonger/dogtag-ipa-ca-renew-agent-submit | 4 +-
|
|
|
e3ffab |
install/certmonger/ipa-server-guard | 55 +++++++++++
|
|
|
e3ffab |
install/restart_scripts/renew_ca_cert | 11 ++-
|
|
|
e3ffab |
install/restart_scripts/renew_ra_cert | 11 ++-
|
|
|
e3ffab |
install/restart_scripts/restart_dirsrv | 10 +-
|
|
|
e3ffab |
install/restart_scripts/restart_httpd | 10 +-
|
|
|
e3ffab |
install/restart_scripts/stop_pkicad | 4 +
|
|
|
e3ffab |
install/tools/ipa-upgradeconfig | 3 +
|
|
|
e3ffab |
ipaplatform/base/paths.py | 2 +
|
|
|
e3ffab |
ipaserver/install/cainstance.py | 38 ++++++++
|
|
|
e3ffab |
ipaserver/install/certs.py | 104 +++++++++++++++++++++
|
|
|
e3ffab |
ipaserver/install/httpinstance.py | 42 +++++++++
|
|
|
e3ffab |
14 files changed, 290 insertions(+), 6 deletions(-)
|
|
|
e3ffab |
create mode 100755 install/certmonger/ipa-server-guard
|
|
|
e3ffab |
|
|
|
e3ffab |
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
|
|
e3ffab |
index 1c975b3912d0a7470a32f1b7e314cfde74446e85..b72d05a4c16d58144207233f2078a336b087604d 100644
|
|
|
e3ffab |
--- a/freeipa.spec.in
|
|
|
e3ffab |
+++ b/freeipa.spec.in
|
|
|
e3ffab |
@@ -650,6 +650,7 @@ fi
|
|
|
e3ffab |
%{_sbindir}/ipa-advise
|
|
|
e3ffab |
%{_sbindir}/ipa-cacert-manage
|
|
|
e3ffab |
%{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
|
|
|
e3ffab |
+%{_libexecdir}/certmonger/ipa-server-guard
|
|
|
e3ffab |
%{_libexecdir}/ipa-otpd
|
|
|
e3ffab |
%dir %{_libexecdir}/ipa
|
|
|
e3ffab |
%{_libexecdir}/ipa/ipa-dnskeysyncd
|
|
|
e3ffab |
diff --git a/install/certmonger/Makefile.am b/install/certmonger/Makefile.am
|
|
|
e3ffab |
index ef6a0a635eed77a582bf0c43b40593678326c8eb..2dc476f188cb284f60a284a6cf90cf3c1ee8692f 100644
|
|
|
e3ffab |
--- a/install/certmonger/Makefile.am
|
|
|
e3ffab |
+++ b/install/certmonger/Makefile.am
|
|
|
e3ffab |
@@ -3,6 +3,7 @@ NULL =
|
|
|
e3ffab |
appdir = $(libexecdir)/certmonger/
|
|
|
e3ffab |
app_SCRIPTS = \
|
|
|
e3ffab |
dogtag-ipa-ca-renew-agent-submit \
|
|
|
e3ffab |
+ ipa-server-guard \
|
|
|
e3ffab |
$(NULL)
|
|
|
e3ffab |
|
|
|
e3ffab |
EXTRA_DIST = \
|
|
|
e3ffab |
diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
|
|
|
e3ffab |
index 3c6e8175c337f65046f8631f4393aecfbf207f4d..7b91fc61148912c77d0ae962b3847d73e8d0720e 100755
|
|
|
e3ffab |
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
|
|
|
e3ffab |
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
|
|
|
e3ffab |
@@ -38,7 +38,7 @@ from ipapython.dn import DN
|
|
|
e3ffab |
from ipalib import api, errors, pkcs10, x509
|
|
|
e3ffab |
from ipaplatform.paths import paths
|
|
|
e3ffab |
from ipaserver.plugins.ldap2 import ldap2
|
|
|
e3ffab |
-from ipaserver.install import cainstance
|
|
|
e3ffab |
+from ipaserver.install import cainstance, certs
|
|
|
e3ffab |
|
|
|
e3ffab |
# This is a certmonger CA helper script for IPA CA subsystem cert renewal. See
|
|
|
e3ffab |
# https://git.fedorahosted.org/cgit/certmonger.git/tree/doc/submit.txt for more
|
|
|
e3ffab |
@@ -437,6 +437,7 @@ def main():
|
|
|
e3ffab |
return OPERATION_NOT_SUPPORTED_BY_HELPER
|
|
|
e3ffab |
|
|
|
e3ffab |
tmpdir = tempfile.mkdtemp(prefix="tmp-")
|
|
|
e3ffab |
+ certs.renewal_lock.acquire()
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
|
|
|
e3ffab |
ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal)
|
|
|
e3ffab |
@@ -456,6 +457,7 @@ def main():
|
|
|
e3ffab |
print item
|
|
|
e3ffab |
return res[0]
|
|
|
e3ffab |
finally:
|
|
|
e3ffab |
+ certs.renewal_lock.release()
|
|
|
e3ffab |
shutil.rmtree(tmpdir)
|
|
|
e3ffab |
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
diff --git a/install/certmonger/ipa-server-guard b/install/certmonger/ipa-server-guard
|
|
|
e3ffab |
new file mode 100755
|
|
|
e3ffab |
index 0000000000000000000000000000000000000000..5e31d89b7731a2bafb85cd7fed4a4b9bd6709a2a
|
|
|
e3ffab |
--- /dev/null
|
|
|
e3ffab |
+++ b/install/certmonger/ipa-server-guard
|
|
|
e3ffab |
@@ -0,0 +1,55 @@
|
|
|
e3ffab |
+#!/usr/bin/python2 -E
|
|
|
e3ffab |
+#
|
|
|
e3ffab |
+# Authors:
|
|
|
e3ffab |
+# Jan Cholasta <jcholast@redhat.com>
|
|
|
e3ffab |
+#
|
|
|
e3ffab |
+# Copyright (C) 2015 Red Hat
|
|
|
e3ffab |
+# see file 'COPYING' for use and warranty information
|
|
|
e3ffab |
+#
|
|
|
e3ffab |
+# This program is free software; you can redistribute it and/or modify
|
|
|
e3ffab |
+# it under the terms of the GNU General Public License as published by
|
|
|
e3ffab |
+# the Free Software Foundation, either version 3 of the License, or
|
|
|
e3ffab |
+# (at your option) any later version.
|
|
|
e3ffab |
+#
|
|
|
e3ffab |
+# This program is distributed in the hope that it will be useful,
|
|
|
e3ffab |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
e3ffab |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
e3ffab |
+# GNU General Public License for more details.
|
|
|
e3ffab |
+#
|
|
|
e3ffab |
+# You should have received a copy of the GNU General Public License
|
|
|
e3ffab |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+import os
|
|
|
e3ffab |
+# Prevent garbage from readline on standard output
|
|
|
e3ffab |
+# (see https://fedorahosted.org/freeipa/ticket/4064)
|
|
|
e3ffab |
+if not os.isatty(1):
|
|
|
e3ffab |
+ os.environ['TERM'] = 'dumb'
|
|
|
e3ffab |
+import sys
|
|
|
e3ffab |
+import syslog
|
|
|
e3ffab |
+import traceback
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+from ipapython import ipautil
|
|
|
e3ffab |
+from ipaserver.install import certs
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def main():
|
|
|
e3ffab |
+ if len(sys.argv) < 2:
|
|
|
e3ffab |
+ raise RuntimeError("Not enough arguments")
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ with certs.renewal_lock:
|
|
|
e3ffab |
+ stdout, stderr, rc = ipautil.run(sys.argv[1:], raiseonerr=False,
|
|
|
e3ffab |
+ env=os.environ)
|
|
|
e3ffab |
+ sys.stdout.write(stdout)
|
|
|
e3ffab |
+ sys.stdout.flush()
|
|
|
e3ffab |
+ sys.stderr.write(stderr)
|
|
|
e3ffab |
+ sys.stderr.flush()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ return rc
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+try:
|
|
|
e3ffab |
+ sys.exit(main())
|
|
|
e3ffab |
+except Exception, e:
|
|
|
e3ffab |
+ syslog.syslog(syslog.LOG_ERR, traceback.format_exc())
|
|
|
e3ffab |
+ print "Internal error"
|
|
|
e3ffab |
+ sys.exit(3)
|
|
|
e3ffab |
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
|
|
|
e3ffab |
index 2ad2038703a74fe3549708549091633b35695907..261c424381d8246ab2ca6da2689a7f90010b2a97 100644
|
|
|
e3ffab |
--- a/install/restart_scripts/renew_ca_cert
|
|
|
e3ffab |
+++ b/install/restart_scripts/renew_ca_cert
|
|
|
e3ffab |
@@ -35,7 +35,8 @@ from ipaserver.plugins.ldap2 import ldap2
|
|
|
e3ffab |
from ipaplatform import services
|
|
|
e3ffab |
from ipaplatform.paths import paths
|
|
|
e3ffab |
|
|
|
e3ffab |
-def main():
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def _main():
|
|
|
e3ffab |
nickname = sys.argv[1]
|
|
|
e3ffab |
|
|
|
e3ffab |
api.bootstrap(context='restart')
|
|
|
e3ffab |
@@ -209,6 +210,14 @@ def main():
|
|
|
e3ffab |
syslog.syslog(
|
|
|
e3ffab |
syslog.LOG_NOTICE, "Started %s" % dogtag_service.service_name)
|
|
|
e3ffab |
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def main():
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ _main()
|
|
|
e3ffab |
+ finally:
|
|
|
e3ffab |
+ certs.renewal_lock.release('renew_ca_cert')
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
main()
|
|
|
e3ffab |
except Exception:
|
|
|
e3ffab |
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
|
|
|
e3ffab |
index 6d4b81a5393dcaced56a8335cd0ec6b7a994acdc..7dae3562380e919b2cc5f53825820291fc93fdc5 100644
|
|
|
e3ffab |
--- a/install/restart_scripts/renew_ra_cert
|
|
|
e3ffab |
+++ b/install/restart_scripts/renew_ra_cert
|
|
|
e3ffab |
@@ -32,9 +32,10 @@ from ipaserver.install import certs, cainstance
|
|
|
e3ffab |
from ipaplatform import services
|
|
|
e3ffab |
from ipaplatform.paths import paths
|
|
|
e3ffab |
|
|
|
e3ffab |
-nickname = 'ipaCert'
|
|
|
e3ffab |
|
|
|
e3ffab |
-def main():
|
|
|
e3ffab |
+def _main():
|
|
|
e3ffab |
+ nickname = 'ipaCert'
|
|
|
e3ffab |
+
|
|
|
e3ffab |
api.bootstrap(context='restart')
|
|
|
e3ffab |
api.finalize()
|
|
|
e3ffab |
|
|
|
e3ffab |
@@ -68,6 +69,12 @@ def main():
|
|
|
e3ffab |
else:
|
|
|
e3ffab |
syslog.syslog(syslog.LOG_NOTICE, "Restarted httpd")
|
|
|
e3ffab |
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def main():
|
|
|
e3ffab |
+ with certs.renewal_lock:
|
|
|
e3ffab |
+ _main()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
main()
|
|
|
e3ffab |
except Exception:
|
|
|
e3ffab |
diff --git a/install/restart_scripts/restart_dirsrv b/install/restart_scripts/restart_dirsrv
|
|
|
e3ffab |
index 837378191765babbcb4b09afec37ab82cb675e28..723644215cb76aa83b2d8eee70070b979986c0cc 100644
|
|
|
e3ffab |
--- a/install/restart_scripts/restart_dirsrv
|
|
|
e3ffab |
+++ b/install/restart_scripts/restart_dirsrv
|
|
|
e3ffab |
@@ -24,8 +24,10 @@ import syslog
|
|
|
e3ffab |
import traceback
|
|
|
e3ffab |
from ipalib import api
|
|
|
e3ffab |
from ipaplatform import services
|
|
|
e3ffab |
+from ipaserver.install import certs
|
|
|
e3ffab |
|
|
|
e3ffab |
-def main():
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def _main():
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
instance = sys.argv[1]
|
|
|
e3ffab |
except IndexError:
|
|
|
e3ffab |
@@ -41,6 +43,12 @@ def main():
|
|
|
e3ffab |
except Exception, e:
|
|
|
e3ffab |
syslog.syslog(syslog.LOG_ERR, "Cannot restart dirsrv (instance: '%s'): %s" % (instance, str(e)))
|
|
|
e3ffab |
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def main():
|
|
|
e3ffab |
+ with certs.renewal_lock:
|
|
|
e3ffab |
+ _main()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
main()
|
|
|
e3ffab |
except Exception:
|
|
|
e3ffab |
diff --git a/install/restart_scripts/restart_httpd b/install/restart_scripts/restart_httpd
|
|
|
e3ffab |
index e3ef73c4fad29bd0ca4dda167352ad023d5ff31f..f060a3091d439b7811d680b75d9995f5cc391e53 100644
|
|
|
e3ffab |
--- a/install/restart_scripts/restart_httpd
|
|
|
e3ffab |
+++ b/install/restart_scripts/restart_httpd
|
|
|
e3ffab |
@@ -22,8 +22,10 @@
|
|
|
e3ffab |
import syslog
|
|
|
e3ffab |
import traceback
|
|
|
e3ffab |
from ipaplatform import services
|
|
|
e3ffab |
+from ipaserver.install import certs
|
|
|
e3ffab |
|
|
|
e3ffab |
-def main():
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def _main():
|
|
|
e3ffab |
syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd')
|
|
|
e3ffab |
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
@@ -31,6 +33,12 @@ def main():
|
|
|
e3ffab |
except Exception, e:
|
|
|
e3ffab |
syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e))
|
|
|
e3ffab |
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+def main():
|
|
|
e3ffab |
+ with certs.renewal_lock:
|
|
|
e3ffab |
+ _main()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
main()
|
|
|
e3ffab |
except Exception:
|
|
|
e3ffab |
diff --git a/install/restart_scripts/stop_pkicad b/install/restart_scripts/stop_pkicad
|
|
|
e3ffab |
index b8866f16edbec8c58327616324357f7f23ba368a..871e5e7616701ef6925fa2725cb1a90ad0aae512 100644
|
|
|
e3ffab |
--- a/install/restart_scripts/stop_pkicad
|
|
|
e3ffab |
+++ b/install/restart_scripts/stop_pkicad
|
|
|
e3ffab |
@@ -25,6 +25,8 @@ import traceback
|
|
|
e3ffab |
from ipapython import dogtag
|
|
|
e3ffab |
from ipalib import api
|
|
|
e3ffab |
from ipaplatform import services
|
|
|
e3ffab |
+from ipaserver.install import certs
|
|
|
e3ffab |
+
|
|
|
e3ffab |
|
|
|
e3ffab |
def main():
|
|
|
e3ffab |
api.bootstrap(context='restart')
|
|
|
e3ffab |
@@ -34,6 +36,8 @@ def main():
|
|
|
e3ffab |
dogtag_service = services.knownservices[configured_constants.SERVICE_NAME]
|
|
|
e3ffab |
dogtag_instance = configured_constants.PKI_INSTANCE_NAME
|
|
|
e3ffab |
|
|
|
e3ffab |
+ certs.renewal_lock.acquire('renew_ca_cert')
|
|
|
e3ffab |
+
|
|
|
e3ffab |
syslog.syslog(syslog.LOG_NOTICE, "Stopping %s" % dogtag_service.service_name)
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
dogtag_service.stop(dogtag_instance)
|
|
|
e3ffab |
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
|
|
|
e3ffab |
index b00161d58418d6205c0ba0db0260af272ec96130..3f671c3bd5ebb643201b13b2024447bb1273c292 100755
|
|
|
e3ffab |
--- a/install/tools/ipa-upgradeconfig
|
|
|
e3ffab |
+++ b/install/tools/ipa-upgradeconfig
|
|
|
e3ffab |
@@ -1372,6 +1372,8 @@ def main():
|
|
|
e3ffab |
)
|
|
|
e3ffab |
upgrade_pki(ca, fstore)
|
|
|
e3ffab |
|
|
|
e3ffab |
+ ca.configure_certmonger_renewal_guard()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
update_dbmodules(api.env.realm)
|
|
|
e3ffab |
uninstall_ipa_kpasswd()
|
|
|
e3ffab |
|
|
|
e3ffab |
@@ -1384,6 +1386,7 @@ def main():
|
|
|
e3ffab |
http = httpinstance.HTTPInstance(fstore)
|
|
|
e3ffab |
http.configure_selinux_for_httpd()
|
|
|
e3ffab |
http.change_mod_nss_port_from_http()
|
|
|
e3ffab |
+ http.configure_certmonger_renewal_guard()
|
|
|
e3ffab |
|
|
|
e3ffab |
http.stop()
|
|
|
e3ffab |
update_mod_nss_protocol(http)
|
|
|
e3ffab |
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
|
|
|
e3ffab |
index 8bfab1bc92f79b5e76555b35a8b646e1ff56f84b..f78c1f940a101038226ff98e229df775028e3bf1 100644
|
|
|
e3ffab |
--- a/ipaplatform/base/paths.py
|
|
|
e3ffab |
+++ b/ipaplatform/base/paths.py
|
|
|
e3ffab |
@@ -204,6 +204,7 @@ class BasePathNamespace(object):
|
|
|
e3ffab |
LIBSOFTHSM2_SO_64 = "/usr/lib64/pkcs11/libsofthsm2.so"
|
|
|
e3ffab |
DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT = "/usr/libexec/certmonger/dogtag-ipa-ca-renew-agent-submit"
|
|
|
e3ffab |
DOGTAG_IPA_RENEW_AGENT_SUBMIT = "/usr/libexec/certmonger/dogtag-ipa-renew-agent-submit"
|
|
|
e3ffab |
+ IPA_SERVER_GUARD = "/usr/libexec/certmonger/ipa-server-guard"
|
|
|
e3ffab |
IPA_DNSKEYSYNCD_REPLICA = "/usr/libexec/ipa/ipa-dnskeysync-replica"
|
|
|
e3ffab |
IPA_DNSKEYSYNCD = "/usr/libexec/ipa/ipa-dnskeysyncd"
|
|
|
e3ffab |
IPA_ODS_EXPORTER = "/usr/libexec/ipa/ipa-ods-exporter"
|
|
|
e3ffab |
@@ -320,6 +321,7 @@ class BasePathNamespace(object):
|
|
|
e3ffab |
VAR_OPENDNSSEC_DIR = "/var/opendnssec"
|
|
|
e3ffab |
OPENDNSSEC_KASP_DB = "/var/opendnssec/kasp.db"
|
|
|
e3ffab |
VAR_RUN_DIRSRV_DIR = "/var/run/dirsrv"
|
|
|
e3ffab |
+ IPA_RENEWAL_LOCK = "/var/run/ipa/renewal.lock"
|
|
|
e3ffab |
SVC_LIST_FILE = "/var/run/ipa/services.list"
|
|
|
e3ffab |
IPA_MEMCACHED_DIR = "/var/run/ipa_memcached"
|
|
|
e3ffab |
VAR_RUN_IPA_MEMCACHED = "/var/run/ipa_memcached/ipa_memcached"
|
|
|
e3ffab |
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
|
|
e3ffab |
index aac7f4c7ccbad5a68bfd9756c7f7638416e3f6a0..13a75bbb568a25d155325e7084406eb19e8ffc92 100644
|
|
|
e3ffab |
--- a/ipaserver/install/cainstance.py
|
|
|
e3ffab |
+++ b/ipaserver/install/cainstance.py
|
|
|
e3ffab |
@@ -37,6 +37,8 @@ import stat
|
|
|
e3ffab |
import syslog
|
|
|
e3ffab |
import ConfigParser
|
|
|
e3ffab |
import dbus
|
|
|
e3ffab |
+import shlex
|
|
|
e3ffab |
+import pipes
|
|
|
e3ffab |
|
|
|
e3ffab |
from ipapython import dogtag
|
|
|
e3ffab |
from ipapython.certdb import get_ca_nickname
|
|
|
e3ffab |
@@ -1422,6 +1424,16 @@ class CAInstance(service.Service):
|
|
|
e3ffab |
if path:
|
|
|
e3ffab |
iface.remove_known_ca(path)
|
|
|
e3ffab |
|
|
|
e3ffab |
+ helper = self.restore_state('certmonger_dogtag_helper')
|
|
|
e3ffab |
+ if helper:
|
|
|
e3ffab |
+ path = iface.find_ca_by_nickname('dogtag-ipa-renew-agent')
|
|
|
e3ffab |
+ if path:
|
|
|
e3ffab |
+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path)
|
|
|
e3ffab |
+ ca_iface = dbus.Interface(ca_obj,
|
|
|
e3ffab |
+ 'org.freedesktop.DBus.Properties')
|
|
|
e3ffab |
+ ca_iface.Set('org.fedorahosted.certmonger.ca',
|
|
|
e3ffab |
+ 'external-helper', helper)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
cmonger.stop()
|
|
|
e3ffab |
|
|
|
e3ffab |
# remove CRL files
|
|
|
e3ffab |
@@ -1481,6 +1493,32 @@ class CAInstance(service.Service):
|
|
|
e3ffab |
'dogtag-ipa-ca-renew-agent',
|
|
|
e3ffab |
paths.DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT, [])
|
|
|
e3ffab |
|
|
|
e3ffab |
+ self.configure_certmonger_renewal_guard()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def configure_certmonger_renewal_guard(self):
|
|
|
e3ffab |
+ if not self.is_configured():
|
|
|
e3ffab |
+ return
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ bus = dbus.SystemBus()
|
|
|
e3ffab |
+ obj = bus.get_object('org.fedorahosted.certmonger',
|
|
|
e3ffab |
+ '/org/fedorahosted/certmonger')
|
|
|
e3ffab |
+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger')
|
|
|
e3ffab |
+ path = iface.find_ca_by_nickname('dogtag-ipa-renew-agent')
|
|
|
e3ffab |
+ if path:
|
|
|
e3ffab |
+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path)
|
|
|
e3ffab |
+ ca_iface = dbus.Interface(ca_obj,
|
|
|
e3ffab |
+ 'org.freedesktop.DBus.Properties')
|
|
|
e3ffab |
+ helper = ca_iface.Get('org.fedorahosted.certmonger.ca',
|
|
|
e3ffab |
+ 'external-helper')
|
|
|
e3ffab |
+ if helper:
|
|
|
e3ffab |
+ args = shlex.split(helper)
|
|
|
e3ffab |
+ if args[0] != paths.IPA_SERVER_GUARD:
|
|
|
e3ffab |
+ self.backup_state('certmonger_dogtag_helper', helper)
|
|
|
e3ffab |
+ args = [paths.IPA_SERVER_GUARD] + args
|
|
|
e3ffab |
+ helper = ' '.join(pipes.quote(a) for a in args)
|
|
|
e3ffab |
+ ca_iface.Set('org.fedorahosted.certmonger.ca',
|
|
|
e3ffab |
+ 'external-helper', helper)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
def configure_agent_renewal(self):
|
|
|
e3ffab |
try:
|
|
|
e3ffab |
certmonger.dogtag_start_tracking(
|
|
|
e3ffab |
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
|
|
|
e3ffab |
index 7292cbbe3574f57d32daa6f1e310669486fa5eff..bc7dccf805386e9fa84b58d2ff9346085e1b93b1 100644
|
|
|
e3ffab |
--- a/ipaserver/install/certs.py
|
|
|
e3ffab |
+++ b/ipaserver/install/certs.py
|
|
|
e3ffab |
@@ -26,6 +26,10 @@ import xml.dom.minidom
|
|
|
e3ffab |
import pwd
|
|
|
e3ffab |
import base64
|
|
|
e3ffab |
from hashlib import sha1
|
|
|
e3ffab |
+import fcntl
|
|
|
e3ffab |
+import time
|
|
|
e3ffab |
+import datetime
|
|
|
e3ffab |
+import ConfigParser as configparser
|
|
|
e3ffab |
|
|
|
e3ffab |
from ipapython.ipa_log_manager import root_logger
|
|
|
e3ffab |
from ipapython import dogtag
|
|
|
e3ffab |
@@ -647,3 +651,103 @@ class CertDB(object):
|
|
|
e3ffab |
|
|
|
e3ffab |
def export_pem_cert(self, nickname, location):
|
|
|
e3ffab |
return self.nssdb.export_pem_cert(nickname, location)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+class _CrossProcessLock(object):
|
|
|
e3ffab |
+ _DATETIME_FORMAT = '%Y%m%d%H%M%S%f'
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def __init__(self, filename):
|
|
|
e3ffab |
+ self._filename = filename
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def __enter__(self):
|
|
|
e3ffab |
+ self.acquire()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def __exit__(self, exc_type, exc_value, traceback):
|
|
|
e3ffab |
+ self.release()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def acquire(self, owner=None):
|
|
|
e3ffab |
+ self._do(self._acquire, owner)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def release(self, owner=None):
|
|
|
e3ffab |
+ self._do(self._release, owner)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def _acquire(self, owner):
|
|
|
e3ffab |
+ now = datetime.datetime.utcnow()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if self._locked and now >= self._expire:
|
|
|
e3ffab |
+ self._locked = False
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if self._locked:
|
|
|
e3ffab |
+ return False
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ self._locked = True
|
|
|
e3ffab |
+ self._owner = owner
|
|
|
e3ffab |
+ self._expire = now + datetime.timedelta(hours=1)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ return True
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def _release(self, owner):
|
|
|
e3ffab |
+ if not self._locked or self._owner != owner:
|
|
|
e3ffab |
+ raise RuntimeError("lock not acquired by %s" % owner)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ self._locked = False
|
|
|
e3ffab |
+ self._owner = None
|
|
|
e3ffab |
+ self._expire = None
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ return True
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def _do(self, func, owner):
|
|
|
e3ffab |
+ if owner is None:
|
|
|
e3ffab |
+ owner = '%s[%s]' % (os.path.basename(sys.argv[0]), os.getpid())
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ while True:
|
|
|
e3ffab |
+ with open(self._filename, 'a+') as f:
|
|
|
e3ffab |
+ fcntl.flock(f, fcntl.LOCK_EX)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ f.seek(0)
|
|
|
e3ffab |
+ self._read(f)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if func(owner):
|
|
|
e3ffab |
+ f.seek(0)
|
|
|
e3ffab |
+ f.truncate()
|
|
|
e3ffab |
+ self._write(f)
|
|
|
e3ffab |
+ return
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ time.sleep(10)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def _read(self, fileobj):
|
|
|
e3ffab |
+ p = configparser.RawConfigParser()
|
|
|
e3ffab |
+ p.readfp(fileobj)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ self._locked = p.getboolean('lock', 'locked')
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if self._locked:
|
|
|
e3ffab |
+ self._owner = p.get('lock', 'owner')
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ expire = p.get('lock', 'expire')
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ self._expire = datetime.datetime.strptime(
|
|
|
e3ffab |
+ expire, self._DATETIME_FORMAT)
|
|
|
e3ffab |
+ except ValueError:
|
|
|
e3ffab |
+ raise configparser.Error
|
|
|
e3ffab |
+ except configparser.Error:
|
|
|
e3ffab |
+ self._locked = False
|
|
|
e3ffab |
+ self._owner = None
|
|
|
e3ffab |
+ self._expire = None
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ def _write(self, fileobj):
|
|
|
e3ffab |
+ p = configparser.RawConfigParser()
|
|
|
e3ffab |
+ p.add_section('lock')
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ locked = '1' if self._locked else '0'
|
|
|
e3ffab |
+ p.set('lock', 'locked', locked)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if self._locked:
|
|
|
e3ffab |
+ expire = self._expire.strftime(self._DATETIME_FORMAT)
|
|
|
e3ffab |
+ p.set('lock', 'owner', self._owner)
|
|
|
e3ffab |
+ p.set('lock', 'expire', expire)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ p.write(fileobj)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+renewal_lock = _CrossProcessLock(paths.IPA_RENEWAL_LOCK)
|
|
|
e3ffab |
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
|
|
|
e3ffab |
index f9e020039734c7ff61e06ead0e30fb28701d6fc8..2fb315b6b822343860a9c31b016d6a0a22388488 100644
|
|
|
e3ffab |
--- a/ipaserver/install/httpinstance.py
|
|
|
e3ffab |
+++ b/ipaserver/install/httpinstance.py
|
|
|
e3ffab |
@@ -23,6 +23,9 @@ import tempfile
|
|
|
e3ffab |
import pwd
|
|
|
e3ffab |
import shutil
|
|
|
e3ffab |
import re
|
|
|
e3ffab |
+import dbus
|
|
|
e3ffab |
+import shlex
|
|
|
e3ffab |
+import pipes
|
|
|
e3ffab |
|
|
|
e3ffab |
import service
|
|
|
e3ffab |
import certs
|
|
|
e3ffab |
@@ -121,6 +124,9 @@ class HTTPInstance(service.Service):
|
|
|
e3ffab |
self.step("enabling mod_nss renegotiate", self.enable_mod_nss_renegotiate)
|
|
|
e3ffab |
self.step("adding URL rewriting rules", self.__add_include)
|
|
|
e3ffab |
self.step("configuring httpd", self.__configure_http)
|
|
|
e3ffab |
+ if self.ca_is_configured:
|
|
|
e3ffab |
+ self.step("configure certmonger for renewals",
|
|
|
e3ffab |
+ self.configure_certmonger_renewal_guard)
|
|
|
e3ffab |
self.step("setting up ssl", self.__setup_ssl)
|
|
|
e3ffab |
self.step("importing CA certificates from LDAP", self.__import_ca_certs)
|
|
|
e3ffab |
if autoconfig:
|
|
|
e3ffab |
@@ -221,6 +227,27 @@ class HTTPInstance(service.Service):
|
|
|
e3ffab |
if installutils.update_file(paths.HTTPD_NSS_CONF, '</VirtualHost>', 'Include conf.d/ipa-rewrite.conf\n</VirtualHost>') != 0:
|
|
|
e3ffab |
print "Adding Include conf.d/ipa-rewrite to %s failed." % paths.HTTPD_NSS_CONF
|
|
|
e3ffab |
|
|
|
e3ffab |
+ def configure_certmonger_renewal_guard(self):
|
|
|
e3ffab |
+ bus = dbus.SystemBus()
|
|
|
e3ffab |
+ obj = bus.get_object('org.fedorahosted.certmonger',
|
|
|
e3ffab |
+ '/org/fedorahosted/certmonger')
|
|
|
e3ffab |
+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger')
|
|
|
e3ffab |
+ path = iface.find_ca_by_nickname('IPA')
|
|
|
e3ffab |
+ if path:
|
|
|
e3ffab |
+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path)
|
|
|
e3ffab |
+ ca_iface = dbus.Interface(ca_obj,
|
|
|
e3ffab |
+ 'org.freedesktop.DBus.Properties')
|
|
|
e3ffab |
+ helper = ca_iface.Get('org.fedorahosted.certmonger.ca',
|
|
|
e3ffab |
+ 'external-helper')
|
|
|
e3ffab |
+ if helper:
|
|
|
e3ffab |
+ args = shlex.split(helper)
|
|
|
e3ffab |
+ if args[0] != paths.IPA_SERVER_GUARD:
|
|
|
e3ffab |
+ self.backup_state('certmonger_ipa_helper', helper)
|
|
|
e3ffab |
+ args = [paths.IPA_SERVER_GUARD] + args
|
|
|
e3ffab |
+ helper = ' '.join(pipes.quote(a) for a in args)
|
|
|
e3ffab |
+ ca_iface.Set('org.fedorahosted.certmonger.ca',
|
|
|
e3ffab |
+ 'external-helper', helper)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
def __setup_ssl(self):
|
|
|
e3ffab |
fqdn = self.fqdn
|
|
|
e3ffab |
|
|
|
e3ffab |
@@ -355,6 +382,21 @@ class HTTPInstance(service.Service):
|
|
|
e3ffab |
self.stop()
|
|
|
e3ffab |
|
|
|
e3ffab |
self.stop_tracking_certificates()
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ helper = self.restore_state('certmonger_ipa_helper')
|
|
|
e3ffab |
+ if helper:
|
|
|
e3ffab |
+ bus = dbus.SystemBus()
|
|
|
e3ffab |
+ obj = bus.get_object('org.fedorahosted.certmonger',
|
|
|
e3ffab |
+ '/org/fedorahosted/certmonger')
|
|
|
e3ffab |
+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger')
|
|
|
e3ffab |
+ path = iface.find_ca_by_nickname('IPA')
|
|
|
e3ffab |
+ if path:
|
|
|
e3ffab |
+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path)
|
|
|
e3ffab |
+ ca_iface = dbus.Interface(ca_obj,
|
|
|
e3ffab |
+ 'org.freedesktop.DBus.Properties')
|
|
|
e3ffab |
+ ca_iface.Set('org.fedorahosted.certmonger.ca',
|
|
|
e3ffab |
+ 'external-helper', helper)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
if not enabled is None and not enabled:
|
|
|
e3ffab |
self.disable()
|
|
|
e3ffab |
|
|
|
e3ffab |
--
|
|
|
e3ffab |
2.1.0
|
|
|
e3ffab |
|