1251 lines
50 KiB
Diff
1251 lines
50 KiB
Diff
From 03837bfd6dbf7fd1eaa437da22807d7061b99af7 Mon Sep 17 00:00:00 2001
|
|
From: Rob Crittenden <rcritten@redhat.com>
|
|
Date: Wed, 11 Jul 2012 15:51:01 -0400
|
|
Subject: [PATCH 49/79] Use certmonger to renew CA subsystem certificates
|
|
|
|
Certificate renewal can be done only one one CA as the certificates need
|
|
to be shared amongst them. certmonger has been trained to communicate
|
|
directly with dogtag to perform the renewals. The initial CA installation
|
|
is the defacto certificate renewal master.
|
|
|
|
A copy of the certificate is stored in the IPA LDAP tree in
|
|
cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX, the rdn being the nickname of the
|
|
certificate, when a certificate is renewed. Only the most current
|
|
certificate is stored. It is valid to have no certificates there, it means
|
|
that no renewals have taken place.
|
|
|
|
The clones are configured with a new certmonger CA type that polls this
|
|
location in the IPA tree looking for an updated certificate. If one is
|
|
not found then certmonger is put into the CA_WORKING state and will poll
|
|
every 8 hours until an updated certificate is available.
|
|
|
|
The RA agent certificate, ipaCert in /etc/httpd/alias, is a special case.
|
|
When this certificate is updated we also need to update its entry in
|
|
the dogtag tree, adding the updated certificate and telling dogtag which
|
|
certificate to use. This is the certificate that lets IPA issue
|
|
certificates.
|
|
|
|
On upgrades we check to see if the certificate tracking is already in
|
|
place. If not then we need to determine if this is the master that will
|
|
do the renewals or not. This decision is made based on whether it was
|
|
the first master installed. It is concievable that this master is no
|
|
longer available meaning that none are actually tracking renewal. We
|
|
will need to document this.
|
|
|
|
https://fedorahosted.org/freeipa/ticket/2803
|
|
---
|
|
freeipa.spec.in | 7 +-
|
|
install/Makefile.am | 1 +
|
|
install/certmonger/Makefile.am | 14 ++
|
|
.../certmonger/dogtag-ipa-retrieve-agent-submit | 80 +++++++++++
|
|
install/conf/Makefile.am | 3 +-
|
|
install/conf/ca_renewal | 6 +
|
|
install/configure.ac | 1 +
|
|
install/restart_scripts/Makefile.am | 3 +
|
|
install/restart_scripts/renew_ca_cert | 93 +++++++++++++
|
|
install/restart_scripts/renew_ra_cert | 96 ++++++++++++++
|
|
install/restart_scripts/restart_dirsrv | 25 +++-
|
|
install/restart_scripts/restart_httpd | 25 +++-
|
|
install/restart_scripts/restart_pkicad | 50 +++++++
|
|
install/share/bootstrap-template.ldif | 6 +
|
|
install/share/default-aci.ldif | 10 ++
|
|
install/tools/ipa-replica-install | 1 +
|
|
install/tools/ipa-upgradeconfig | 52 ++++++--
|
|
install/updates/21-ca_renewal_container.update | 8 ++
|
|
install/updates/40-delegation.update | 4 +
|
|
install/updates/Makefile.am | 1 +
|
|
ipalib/x509.py | 8 ++
|
|
ipapython/certmonger.py | 65 +++++++++
|
|
ipapython/ipautil.py | 23 ++++
|
|
ipapython/platform/base.py | 2 +-
|
|
ipapython/platform/fedora16.py | 1 +
|
|
ipaserver/install/cainstance.py | 147 ++++++++++++++++++++-
|
|
selinux/ipa_dogtag/ipa_dogtag.te | 10 +-
|
|
27 files changed, 724 insertions(+), 18 deletions(-)
|
|
create mode 100644 install/certmonger/Makefile.am
|
|
create mode 100644 install/certmonger/dogtag-ipa-retrieve-agent-submit
|
|
create mode 100644 install/conf/ca_renewal
|
|
create mode 100644 install/restart_scripts/renew_ca_cert
|
|
create mode 100644 install/restart_scripts/renew_ra_cert
|
|
create mode 100644 install/restart_scripts/restart_pkicad
|
|
create mode 100644 install/updates/21-ca_renewal_container.update
|
|
|
|
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
|
index 719932d4bca61a8ef4a29f0ea060fffcaa403fce..6b24a0b0dc5f4e38ec0adab74fbbbeb20f25bb8a 100644
|
|
--- a/freeipa.spec.in
|
|
+++ b/freeipa.spec.in
|
|
@@ -249,7 +249,7 @@ Requires: xmlrpc-c
|
|
%endif
|
|
%endif
|
|
Requires: sssd >= 1.8.0
|
|
-Requires: certmonger >= 0.53
|
|
+Requires: certmonger >= 0.58
|
|
Requires: nss-tools
|
|
Requires: bind-utils
|
|
Requires: oddjob-mkhomedir
|
|
@@ -571,6 +571,7 @@ fi
|
|
%{_sbindir}/ipactl
|
|
%{_sbindir}/ipa-upgradeconfig
|
|
%{_sbindir}/ipa-compliance
|
|
+%{_libexecdir}/certmonger/dogtag-ipa-retrieve-agent-submit
|
|
%{_sysconfdir}/cron.d/ipa-compliance
|
|
%config(noreplace) %{_sysconfdir}/sysconfig/ipa_memcached
|
|
%dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/
|
|
@@ -633,6 +634,7 @@ fi
|
|
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf
|
|
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf
|
|
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf
|
|
+%{_usr}/share/ipa/ca_renewal
|
|
%{_usr}/share/ipa/ipa.conf
|
|
%{_usr}/share/ipa/ipa-rewrite.conf
|
|
%{_usr}/share/ipa/ipa-pki-proxy.conf
|
|
@@ -745,6 +747,9 @@ fi
|
|
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
|
|
|
|
%changelog
|
|
+* Tue Jul 24 2012 Rob Crittenden <rcritten@redhat.com> - 2.99.0-39
|
|
+- Set minimum certmonger to 0.58 for dogtag cert renewal
|
|
+
|
|
* Wed Jul 18 2012 Alexander Bokovoy <abokovoy@redhat.com> - 2.99.0-38
|
|
- Require samba4-devel >= 4.0.0-128 due to passdb API change in beta4
|
|
|
|
diff --git a/install/Makefile.am b/install/Makefile.am
|
|
index 5670f9bd9e29182adb6aebe92eaf72368bfb01cf..54c456a977efad1c07be0b1aca7d0dbbe82ed411 100644
|
|
--- a/install/Makefile.am
|
|
+++ b/install/Makefile.am
|
|
@@ -5,6 +5,7 @@ AUTOMAKE_OPTIONS = 1.7
|
|
NULL =
|
|
|
|
SUBDIRS = \
|
|
+ certmonger \
|
|
conf \
|
|
html \
|
|
migration \
|
|
diff --git a/install/certmonger/Makefile.am b/install/certmonger/Makefile.am
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2023a2aec2f818b0ab1e7abd04fc3f0d18367469
|
|
--- /dev/null
|
|
+++ b/install/certmonger/Makefile.am
|
|
@@ -0,0 +1,14 @@
|
|
+NULL =
|
|
+
|
|
+appdir = $(libexecdir)/certmonger/
|
|
+app_SCRIPTS = \
|
|
+ dogtag-ipa-retrieve-agent-submit \
|
|
+ $(NULL)
|
|
+
|
|
+EXTRA_DIST = \
|
|
+ $(app_SCRIPTS) \
|
|
+ $(NULL)
|
|
+
|
|
+MAINTAINERCLEANFILES = \
|
|
+ *~ \
|
|
+ Makefile.in
|
|
diff --git a/install/certmonger/dogtag-ipa-retrieve-agent-submit b/install/certmonger/dogtag-ipa-retrieve-agent-submit
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..24e1844a54891f1f08ba0a2a689ce4213aaa1724
|
|
--- /dev/null
|
|
+++ b/install/certmonger/dogtag-ipa-retrieve-agent-submit
|
|
@@ -0,0 +1,80 @@
|
|
+#!/usr/bin/python -E
|
|
+#
|
|
+# Authors:
|
|
+# Rob Crittenden <rcritten@redhat.com>
|
|
+#
|
|
+# Copyright (C) 2012 Red Hat
|
|
+# see file 'COPYING' for use and warranty information
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation, either version 3 of the License, or
|
|
+# (at your option) any later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+
|
|
+# The certificate rewewal is done on only one dogtag CA. The others
|
|
+# retrieve the updated certificate from IPA.
|
|
+
|
|
+import os
|
|
+import sys
|
|
+import shutil
|
|
+import tempfile
|
|
+import krbV
|
|
+import syslog
|
|
+from ipalib import api
|
|
+from ipalib.dn import DN
|
|
+from ipalib import errors
|
|
+from ipalib import x509
|
|
+from ipapython import services as ipaservices
|
|
+from ipapython import ipautil
|
|
+from ipaserver.install import certs
|
|
+from ipaserver.plugins.ldap2 import ldap2
|
|
+import base64
|
|
+
|
|
+# We cheat and pass in the nickname as the CA profile to execute against.
|
|
+# Some way is needed to determine which entry to retrieve from LDAP
|
|
+operation = os.environ.get('CERTMONGER_OPERATION')
|
|
+nickname = os.environ.get('CERTMONGER_CA_PROFILE')
|
|
+
|
|
+if operation not in ['SUBMIT', 'POLL']:
|
|
+ sys.exit(6) # unsupported operation
|
|
+
|
|
+api.bootstrap(context='renew')
|
|
+api.finalize()
|
|
+
|
|
+# Update or add it
|
|
+tmpdir = tempfile.mkdtemp(prefix = "tmp-")
|
|
+try:
|
|
+ dn = str(DN(('cn',nickname),('cn=ca_renewal,cn=ipa,cn=etc'),(api.env.basedn)))
|
|
+ principal = str('host/%s@%s' % (api.env.host, api.env.realm))
|
|
+ ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
|
|
+ conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
|
|
+ conn.connect(ccache=ccache)
|
|
+ try:
|
|
+ syslog.syslog(syslog.LOG_NOTICE, "Updating certificate for %s" % nickname)
|
|
+ (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
|
|
+ cert = entry_attrs['usercertificate'][0]
|
|
+ cert = base64.b64encode(cert)
|
|
+ print x509.make_pem(cert)
|
|
+ except errors.NotFound:
|
|
+ syslog.syslog(syslog.LOG_INFO, "Updated certificate for %s not available" % nickname)
|
|
+ # No cert available yet, tell certmonger to wait another 8 hours
|
|
+ print 8 * 60 * 60
|
|
+ sys.exit(5)
|
|
+ finally:
|
|
+ conn.disconnect()
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, "Exception trying to retrieve %s: %s" % (nickname, e))
|
|
+ # Unhandled error
|
|
+ sys.exit(3)
|
|
+finally:
|
|
+ shutil.rmtree(tmpdir)
|
|
+
|
|
+sys.exit(0)
|
|
diff --git a/install/conf/Makefile.am b/install/conf/Makefile.am
|
|
index 5ee3eddb5979356565377ba3e52a987345c22783..06b3b32df0f85bec6817890fd6a49549de779263 100644
|
|
--- a/install/conf/Makefile.am
|
|
+++ b/install/conf/Makefile.am
|
|
@@ -2,8 +2,9 @@ NULL =
|
|
|
|
appdir = $(IPA_DATA_DIR)
|
|
app_DATA = \
|
|
+ ca_renewal \
|
|
ipa.conf \
|
|
- ipa-pki-proxy.conf \
|
|
+ ipa-pki-proxy.conf \
|
|
ipa-rewrite.conf \
|
|
$(NULL)
|
|
|
|
diff --git a/install/conf/ca_renewal b/install/conf/ca_renewal
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..57a9e9c2421c5d948cdca421fc5b2e4fcf58079c
|
|
--- /dev/null
|
|
+++ b/install/conf/ca_renewal
|
|
@@ -0,0 +1,6 @@
|
|
+# A separate helper for fetching dogtag certificates that are renewed on
|
|
+# another system.
|
|
+id=dogtag-ipa-retrieve-agent-submit
|
|
+ca_is_default=0
|
|
+ca_type=EXTERNAL
|
|
+ca_external_helper=/usr/libexec/certmonger/dogtag-ipa-retrieve-agent-submit
|
|
diff --git a/install/configure.ac b/install/configure.ac
|
|
index 9e781a684429191b3c5eb46aed4fceecc9be6586..c5934d93db341fd0802da5021edce199aa1cd929 100644
|
|
--- a/install/configure.ac
|
|
+++ b/install/configure.ac
|
|
@@ -75,6 +75,7 @@ AC_SUBST(IPA_SYSCONF_DIR)
|
|
|
|
AC_CONFIG_FILES([
|
|
Makefile
|
|
+ certmonger/Makefile
|
|
conf/Makefile
|
|
html/Makefile
|
|
migration/Makefile
|
|
diff --git a/install/restart_scripts/Makefile.am b/install/restart_scripts/Makefile.am
|
|
index abc066b305356da3ed51beafc8c8dee7829b98ff..210c4863e3d7d057627370093638e5bf9c47c802 100644
|
|
--- a/install/restart_scripts/Makefile.am
|
|
+++ b/install/restart_scripts/Makefile.am
|
|
@@ -4,6 +4,9 @@ appdir = $(libdir)/ipa/certmonger
|
|
app_DATA = \
|
|
restart_dirsrv \
|
|
restart_httpd \
|
|
+ restart_pkicad \
|
|
+ renew_ca_cert \
|
|
+ renew_ra_cert \
|
|
$(NULL)
|
|
|
|
EXTRA_DIST = \
|
|
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d3b756042685b4e35dab754a0e45ccb37e871d21
|
|
--- /dev/null
|
|
+++ b/install/restart_scripts/renew_ca_cert
|
|
@@ -0,0 +1,93 @@
|
|
+#!/usr/bin/python -E
|
|
+#
|
|
+# Authors:
|
|
+# Rob Crittenden <rcritten@redhat.com>
|
|
+#
|
|
+# Copyright (C) 2012 Red Hat
|
|
+# see file 'COPYING' for use and warranty information
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation, either version 3 of the License, or
|
|
+# (at your option) any later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+
|
|
+import os
|
|
+import sys
|
|
+import shutil
|
|
+import tempfile
|
|
+import krbV
|
|
+import syslog
|
|
+from ipalib import api
|
|
+from ipalib.dn import DN
|
|
+from ipalib import errors
|
|
+from ipapython import services as ipaservices
|
|
+from ipapython import ipautil
|
|
+from ipaserver.install import certs
|
|
+from ipaserver.plugins.ldap2 import ldap2
|
|
+from ipaserver.install.cainstance import update_cert_config
|
|
+
|
|
+nickname = sys.argv[1]
|
|
+
|
|
+api.bootstrap(context='restart')
|
|
+api.finalize()
|
|
+
|
|
+# Fetch the new certificate
|
|
+db = certs.CertDB(api.env.realm, nssdir='/var/lib/pki-ca/alias')
|
|
+cert = db.get_cert_from_db(nickname, pem=False)
|
|
+
|
|
+if not cert:
|
|
+ syslog.syslog(syslog.LOG_ERR, 'No certificate %s found.' % nickname)
|
|
+ sys.exit(1)
|
|
+
|
|
+# Update or add it
|
|
+tmpdir = tempfile.mkdtemp(prefix = "tmp-")
|
|
+try:
|
|
+ dn = str(DN(('cn',nickname),('cn=ca_renewal,cn=ipa,cn=etc'),(api.env.basedn)))
|
|
+ principal = str('host/%s@%s' % (api.env.host, api.env.realm))
|
|
+ ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
|
|
+ conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
|
|
+ conn.connect(ccache=ccache)
|
|
+ try:
|
|
+ (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
|
|
+ entry_attrs['usercertificate'] = cert
|
|
+ conn.update_entry(dn, entry_attrs, normalize=False)
|
|
+ except errors.NotFound:
|
|
+ entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'],
|
|
+ usercertificate=cert)
|
|
+ conn.add_entry(dn, entry_attrs, normalize=False)
|
|
+ except errors.EmptyModlist:
|
|
+ pass
|
|
+ conn.disconnect()
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, 'Updating renewal certificate failed: %s' % e)
|
|
+finally:
|
|
+ shutil.rmtree(tmpdir)
|
|
+
|
|
+# Fix permissions on the audit cert if we're updating it
|
|
+if nickname == 'auditSigningCert cert-pki-ca':
|
|
+ db = certs.CertDB(api.env.realm, nssdir='/var/lib/pki-ca/alias')
|
|
+ args = ['-M',
|
|
+ '-n', nickname,
|
|
+ '-t', 'u,u,Pu',
|
|
+ ]
|
|
+ try:
|
|
+ db.run_certutil(args)
|
|
+ except ipautil.CalledProcessError:
|
|
+ syslog.syslog(syslog.LOG_ERR, 'Updating trust on certificate %s failed in %s' % (nickname, db.secdir))
|
|
+
|
|
+update_cert_config(nickname, cert)
|
|
+
|
|
+syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted pki-cad instance pki-ca')
|
|
+
|
|
+try:
|
|
+ ipaservices.knownservices.pki_cad.restart('pki-ca')
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, "Cannot restart pki-cad: %s" % str(e))
|
|
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2fcf1a79b2893eb4e70342b05c8378337bbdf083
|
|
--- /dev/null
|
|
+++ b/install/restart_scripts/renew_ra_cert
|
|
@@ -0,0 +1,96 @@
|
|
+#!/usr/bin/python -E
|
|
+#
|
|
+# Authors:
|
|
+# Rob Crittenden <rcritten@redhat.com>
|
|
+#
|
|
+# Copyright (C) 2012 Red Hat
|
|
+# see file 'COPYING' for use and warranty information
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation, either version 3 of the License, or
|
|
+# (at your option) any later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+
|
|
+import sys
|
|
+import shutil
|
|
+import tempfile
|
|
+import syslog
|
|
+from ipapython import services as ipaservices
|
|
+from ipapython.certmonger import get_pin
|
|
+from ipapython import ipautil
|
|
+from ipaserver.install import certs
|
|
+from ipaserver.install.cainstance import DEFAULT_DSPORT
|
|
+from ipalib import api
|
|
+from ipalib.dn import DN
|
|
+from ipalib import x509
|
|
+from ipalib import errors
|
|
+from ipaserver.plugins.ldap2 import ldap2
|
|
+
|
|
+api.bootstrap(context='restart')
|
|
+api.finalize()
|
|
+
|
|
+# Fetch the new certificate
|
|
+db = certs.CertDB(api.env.realm)
|
|
+cert = db.get_cert_from_db('ipaCert', pem=False)
|
|
+serial_number = x509.get_serial_number(cert, datatype=x509.DER)
|
|
+subject = x509.get_subject(cert, datatype=x509.DER)
|
|
+issuer = x509.get_issuer(cert, datatype=x509.DER)
|
|
+
|
|
+# Load it into dogtag
|
|
+dn = str(DN(('uid','ipara'),('ou','People'),('o','ipaca')))
|
|
+
|
|
+try:
|
|
+ dm_password = get_pin('internaldb')
|
|
+except IOError, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, 'Unable to determine PIN for CA instance: %s' % e)
|
|
+ sys.exit(1)
|
|
+
|
|
+try:
|
|
+ conn = ldap2(shared_instance=False, ldap_uri='ldap://localhost:%d' % DEFAULT_DSPORT)
|
|
+ conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password)
|
|
+ (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'], normalize=False)
|
|
+ entry_attrs['usercertificate'].append(cert)
|
|
+ entry_attrs['description'] = '2;%d;%s;%s' % (serial_number, issuer, subject)
|
|
+ conn.update_entry(dn, entry_attrs, normalize=False)
|
|
+ conn.disconnect()
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, 'Updating agent entry failed: %s' % e)
|
|
+ sys.exit(1)
|
|
+
|
|
+# Store it in the IPA LDAP server
|
|
+tmpdir = tempfile.mkdtemp(prefix = "tmp-")
|
|
+try:
|
|
+ dn = str(DN(('cn','ipaCert'),('cn=ca_renewal,cn=ipa,cn=etc'),(api.env.basedn)))
|
|
+ principal = str('host/%s@%s' % (api.env.host, api.env.realm))
|
|
+ ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
|
|
+ conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
|
|
+ conn.connect(ccache=ccache)
|
|
+ try:
|
|
+ (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
|
|
+ entry_attrs['usercertificate'] = cert
|
|
+ conn.update_entry(dn, entry_attrs, normalize=False)
|
|
+ except errors.NotFound:
|
|
+ entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'],
|
|
+ usercertificate=cert)
|
|
+ conn.add_entry(dn, entry_attrs, normalize=False)
|
|
+ except errors.EmptyModlist:
|
|
+ pass
|
|
+ conn.disconnect()
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, 'Updating renewal certificate failed: %s' % e)
|
|
+finally:
|
|
+ shutil.rmtree(tmpdir)
|
|
+
|
|
+# Now restart Apache so the new certificate is available
|
|
+try:
|
|
+ ipaservices.knownservices.httpd.restart()
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e))
|
|
diff --git a/install/restart_scripts/restart_dirsrv b/install/restart_scripts/restart_dirsrv
|
|
index e243583f964b047c7af6075ece1c1de25ad56d98..d6bbbbc3f82d5c9e1cf757a461b7e4487e148881 100644
|
|
--- a/install/restart_scripts/restart_dirsrv
|
|
+++ b/install/restart_scripts/restart_dirsrv
|
|
@@ -1,5 +1,26 @@
|
|
#!/usr/bin/python -E
|
|
+#
|
|
+# Authors:
|
|
+# Rob Crittenden <rcritten@redhat.com>
|
|
+#
|
|
+# Copyright (C) 2012 Red Hat
|
|
+# see file 'COPYING' for use and warranty information
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation, either version 3 of the License, or
|
|
+# (at your option) any later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+
|
|
import sys
|
|
+import syslog
|
|
from ipapython import services as ipaservices
|
|
|
|
try:
|
|
@@ -7,7 +28,9 @@ try:
|
|
except IndexError:
|
|
instance = ""
|
|
|
|
+syslog.syslog(syslog.LOG_NOTICE, "certmonger restarted dirsrv instance '%s'" % instance)
|
|
+
|
|
try:
|
|
ipaservices.knownservices.dirsrv.restart(instance)
|
|
except Exception, e:
|
|
- print "Cannot restart dirsrv (instance: '%s'): %s" % (instance, str(e))
|
|
+ syslog.syslog(syslog.LOG_ERR, "Cannot restart dirsrv (instance: '%s'): %s" % (instance, str(e)))
|
|
diff --git a/install/restart_scripts/restart_httpd b/install/restart_scripts/restart_httpd
|
|
index a53ab6e6291ca679bff0f40cb6210e1f7bc792e1..96f80bd8ee1b02ccc582b5050da3199160635ed9 100644
|
|
--- a/install/restart_scripts/restart_httpd
|
|
+++ b/install/restart_scripts/restart_httpd
|
|
@@ -1,7 +1,30 @@
|
|
#!/usr/bin/python -E
|
|
+#
|
|
+# Authors:
|
|
+# Rob Crittenden <rcritten@redhat.com>
|
|
+#
|
|
+# Copyright (C) 2012 Red Hat
|
|
+# see file 'COPYING' for use and warranty information
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation, either version 3 of the License, or
|
|
+# (at your option) any later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+
|
|
+import syslog
|
|
from ipapython import services as ipaservices
|
|
|
|
+syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd')
|
|
+
|
|
try:
|
|
ipaservices.knownservices.httpd.restart()
|
|
except Exception, e:
|
|
- print "Cannot restart httpd: %s" % str(e)
|
|
+ syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e))
|
|
diff --git a/install/restart_scripts/restart_pkicad b/install/restart_scripts/restart_pkicad
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..070760b16c2aecff07c8cce0b25b5d38d45689fb
|
|
--- /dev/null
|
|
+++ b/install/restart_scripts/restart_pkicad
|
|
@@ -0,0 +1,50 @@
|
|
+#!/usr/bin/python -E
|
|
+#
|
|
+# Authors:
|
|
+# Rob Crittenden <rcritten@redhat.com>
|
|
+#
|
|
+# Copyright (C) 2012 Red Hat
|
|
+# see file 'COPYING' for use and warranty information
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation, either version 3 of the License, or
|
|
+# (at your option) any later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
+
|
|
+import sys
|
|
+import syslog
|
|
+from ipapython import services as ipaservices
|
|
+from ipaserver.install import certs
|
|
+from ipalib import api
|
|
+
|
|
+nickname = sys.argv[1]
|
|
+
|
|
+api.bootstrap(context='restart')
|
|
+api.finalize()
|
|
+
|
|
+syslog.syslog(syslog.LOG_NOTICE, "certmonger restarted pki-cad, nickname '%s'" % nickname)
|
|
+
|
|
+# Fix permissions on the audit cert if we're updating it
|
|
+if nickname == 'auditSigningCert cert-pki-ca':
|
|
+ db = certs.CertDB(api.env.realm, nssdir='/var/lib/pki-ca/alias')
|
|
+ args = ['-M',
|
|
+ '-n', nickname,
|
|
+ '-t', 'u,u,Pu',
|
|
+ ]
|
|
+ db.run_certutil(args)
|
|
+
|
|
+try:
|
|
+ # I've seen times where systemd restart does not actually restart
|
|
+ # the process. A full stop/start is required. This works around that
|
|
+ ipaservices.knownservices.pki_cad.stop('pki-ca')
|
|
+ ipaservices.knownservices.pki_cad.start('pki-ca')
|
|
+except Exception, e:
|
|
+ syslog.syslog(syslog.LOG_ERR, "Cannot restart pki-cad: %s" % str(e))
|
|
diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif
|
|
index 23510c953817e48767199378cee2e62009c39742..aac3f059ad30130e085bfcf37a7a1a6f1b49dc8c 100644
|
|
--- a/install/share/bootstrap-template.ldif
|
|
+++ b/install/share/bootstrap-template.ldif
|
|
@@ -161,6 +161,12 @@ objectClass: nsContainer
|
|
objectClass: top
|
|
cn: posix-ids
|
|
|
|
+dn: cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX
|
|
+changetype: add
|
|
+objectClass: nsContainer
|
|
+objectClass: top
|
|
+cn: ca_renewal
|
|
+
|
|
dn: cn=s4u2proxy,cn=etc,$SUFFIX
|
|
changetype: add
|
|
objectClass: nsContainer
|
|
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
|
|
index 870ac12e96c1094b4341a08ead45c1f2ed2577f0..f3ed39599b6ccdf3bc0830dff29a47350813e473 100644
|
|
--- a/install/share/default-aci.ldif
|
|
+++ b/install/share/default-aci.ldif
|
|
@@ -86,3 +86,13 @@ changetype: modify
|
|
add: aci
|
|
aci: (targetattr="userPassword || krbPrincipalKey")(version 3.0; acl "Search existence of password and kerberos keys"; allow(search) userdn = "ldap:///all";)
|
|
|
|
+# Let host add and update CA renewal certificates
|
|
+dn: cn=ipa,cn=etc,$SUFFIX
|
|
+changetype: modify
|
|
+add: aci
|
|
+aci: (target="ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(version 3.0; acl "Add CA Certificates for renewals"; allow(add) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)
|
|
+
|
|
+dn: cn=ipa,cn=etc,$SUFFIX
|
|
+changetype: modify
|
|
+add: aci
|
|
+aci: (target="ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(targetattr="userCertificate")(version 3.0; acl "Modify CA Certificates for renewals"; allow(write) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)
|
|
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
|
|
index 063eea023b2d4a6d43996210e63f90859d048a0c..c322cb62e99493a5da035db6a7745b6d694fad54 100755
|
|
--- a/install/tools/ipa-replica-install
|
|
+++ b/install/tools/ipa-replica-install
|
|
@@ -461,6 +461,7 @@ def main():
|
|
krb = install_krb(config, setup_pkinit=options.setup_pkinit)
|
|
http = install_http(config, auto_redirect=options.ui_redirect)
|
|
if CA:
|
|
+ CA.configure_certmonger_renewal()
|
|
CA.import_ra_cert(dir + "/ra.p12")
|
|
CA.fix_ra_perms()
|
|
ipaservices.knownservices.httpd.restart()
|
|
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
|
|
index cfb9a19e324c47b9c68caa76fb87c5977476f742..951bd485486ae4de99b25d04970299ad47a041a8 100644
|
|
--- a/install/tools/ipa-upgradeconfig
|
|
+++ b/install/tools/ipa-upgradeconfig
|
|
@@ -28,6 +28,7 @@ try:
|
|
from ipapython import ipautil, sysrestore, version
|
|
from ipapython.config import IPAOptionParser
|
|
from ipapython.ipa_log_manager import *
|
|
+ from ipapython import certmonger
|
|
from ipaserver.install import installutils
|
|
from ipaserver.install import dsinstance
|
|
from ipaserver.install import httpinstance
|
|
@@ -43,6 +44,7 @@ try:
|
|
import os
|
|
import shutil
|
|
import fileinput
|
|
+ from ipalib import api
|
|
import ipalib.errors
|
|
except ImportError:
|
|
print >> sys.stderr, """\
|
|
@@ -430,6 +432,35 @@ def named_enable_serial_autoincrement():
|
|
|
|
return changed
|
|
|
|
+def enable_certificate_renewal(realm):
|
|
+ """
|
|
+ If the CA subsystem certificates are not being tracked for renewal then
|
|
+ tell certmonger to start tracking them.
|
|
+ """
|
|
+ ca = cainstance.CAInstance(realm, certs.NSS_DIR)
|
|
+ if not ca.is_configured():
|
|
+ root_logger.debug('dogtag not configured')
|
|
+ return
|
|
+
|
|
+ # Using the nickname find the certmonger request_id
|
|
+ criteria = (('cert_storage_location', '/etc/httpd/alias', certmonger.NPATH),('cert_nickname', 'ipaCert', None))
|
|
+ request_id = certmonger.get_request_id(criteria)
|
|
+ if request_id is not None:
|
|
+ root_logger.debug('Certificate renewal already configured')
|
|
+ return
|
|
+
|
|
+ if not sysupgrade.get_upgrade_state('dogtag', 'renewal_configured'):
|
|
+ if ca.is_master():
|
|
+ ca.configure_renewal()
|
|
+ else:
|
|
+ ca.configure_certmonger_renewal()
|
|
+ ca.configure_clone_renewal()
|
|
+ ca.configure_agent_renewal()
|
|
+ ca.track_servercert()
|
|
+ sysupgrade.set_upgrade_state('dogtag', 'renewal_configured', True)
|
|
+ ca.restart(cainstance.PKI_INSTANCE_NAME)
|
|
+ root_logger.debug('CA subsystem certificate renewal enabled')
|
|
+
|
|
def main():
|
|
"""
|
|
Get some basics about the system. If getting those basics fail then
|
|
@@ -440,6 +471,9 @@ def main():
|
|
if not os.geteuid()==0:
|
|
sys.exit("\nYou must be root to run this script.\n")
|
|
|
|
+ if not installutils.is_ipa_configured():
|
|
+ sys.exit(0)
|
|
+
|
|
safe_options, options = parse_options()
|
|
|
|
standard_logging_setup('/var/log/ipaupgrade.log', verbose=True,
|
|
@@ -448,11 +482,8 @@ def main():
|
|
|
|
fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
|
|
|
|
- try:
|
|
- krbctx = krbV.default_context()
|
|
- except krbV.Krb5Error, e:
|
|
- # Unable to get default kerberos realm
|
|
- sys.exit(0)
|
|
+ api.bootstrap(context='restart')
|
|
+ api.finalize()
|
|
|
|
fqdn = find_hostname()
|
|
if fqdn is None:
|
|
@@ -464,13 +495,13 @@ def main():
|
|
check_certs()
|
|
|
|
auto_redirect = find_autoredirect(fqdn)
|
|
- sub_dict = { "REALM" : krbctx.default_realm, "FQDN": fqdn, "AUTOREDIR": '' if auto_redirect else '#'}
|
|
+ sub_dict = { "REALM" : api.env.realm, "FQDN": fqdn, "AUTOREDIR": '' if auto_redirect else '#'}
|
|
|
|
upgrade(sub_dict, "/etc/httpd/conf.d/ipa.conf", ipautil.SHARE_DIR + "ipa.conf")
|
|
upgrade(sub_dict, "/etc/httpd/conf.d/ipa-rewrite.conf", ipautil.SHARE_DIR + "ipa-rewrite.conf")
|
|
upgrade(sub_dict, "/etc/httpd/conf.d/ipa-pki-proxy.conf", ipautil.SHARE_DIR + "ipa-pki-proxy.conf", add=True)
|
|
upgrade_pki(fstore)
|
|
- update_dbmodules(krbctx.default_realm)
|
|
+ update_dbmodules(api.env.realm)
|
|
uninstall_ipa_kpasswd()
|
|
|
|
http = httpinstance.HTTPInstance(fstore)
|
|
@@ -479,25 +510,26 @@ def main():
|
|
|
|
memcache = memcacheinstance.MemcacheInstance()
|
|
memcache.ldapi = True
|
|
- memcache.realm = krbctx.default_realm
|
|
+ memcache.realm = api.env.realm
|
|
try:
|
|
if not memcache.is_configured():
|
|
# 389-ds needs to be running to create the memcache instance
|
|
# because we record the new service in cn=masters.
|
|
ds = dsinstance.DsInstance()
|
|
ds.start()
|
|
- memcache.create_instance('MEMCACHE', fqdn, None, ipautil.realm_to_suffix(krbctx.default_realm))
|
|
+ memcache.create_instance('MEMCACHE', fqdn, None, ipautil.realm_to_suffix(api.env.realm))
|
|
except (ldap.ALREADY_EXISTS, ipalib.errors.DuplicateEntry):
|
|
pass
|
|
|
|
cleanup_kdc(fstore)
|
|
- upgrade_ipa_profile(krbctx.default_realm)
|
|
+ upgrade_ipa_profile(api.env.realm)
|
|
changed_psearch = named_enable_psearch()
|
|
changed_autoincrement = named_enable_serial_autoincrement()
|
|
if changed_psearch or changed_autoincrement:
|
|
# configuration has changed, restart the name server
|
|
root_logger.info('Changes to named.conf have been made, restart named')
|
|
bindinstance.BindInstance(fstore).restart()
|
|
+ enable_certificate_renewal(api.env.realm)
|
|
|
|
if __name__ == '__main__':
|
|
installutils.run_script(main, operation_name='ipa-upgradeconfig')
|
|
diff --git a/install/updates/21-ca_renewal_container.update b/install/updates/21-ca_renewal_container.update
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..50b92d73d8af75cbc782769c45b6c439b07bbb2d
|
|
--- /dev/null
|
|
+++ b/install/updates/21-ca_renewal_container.update
|
|
@@ -0,0 +1,8 @@
|
|
+#
|
|
+# Add CA renewal container if not available
|
|
+#
|
|
+
|
|
+dn: cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX
|
|
+add:objectClass: top
|
|
+add:objectClass: nsContainer
|
|
+add:cn: ca_renewal
|
|
diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update
|
|
index de112d99d9a5bdbe553d9ec94016e852524494d6..1e512d0f7ce085f9d16e03b091b6ea5b2b28b453 100644
|
|
--- a/install/updates/40-delegation.update
|
|
+++ b/install/updates/40-delegation.update
|
|
@@ -356,3 +356,7 @@ replace:aci:'(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr
|
|
# Don't allow the default 'manage group membership' to be able to manage the
|
|
# admins group
|
|
replace:aci:'(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";)::(targetfilter = "(!(cn=admins))")(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";)'
|
|
+
|
|
+dn: cn=ipa,cn=etc,$SUFFIX
|
|
+add:aci:'(target = "ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(version 3.0; acl "Add CA Certificates for renewals"; allow(add) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)'
|
|
+add:aci:'(target = "ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(targetattr = "userCertificate")(version 3.0; acl "Modify CA Certificates for renewals"; allow(write) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)'
|
|
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
|
|
index e45690f14c41dbd9eb10b5969ee14a257b8c7883..bc7945d7a5cd77469f7fe7175ebd9da66b9119d1 100644
|
|
--- a/install/updates/Makefile.am
|
|
+++ b/install/updates/Makefile.am
|
|
@@ -22,6 +22,7 @@ app_DATA = \
|
|
20-user_private_groups.update \
|
|
20-winsync_index.update \
|
|
21-replicas_container.update \
|
|
+ 21-ca_renewal_container.update \
|
|
30-s4u2proxy.update \
|
|
40-delegation.update \
|
|
40-dns.update \
|
|
diff --git a/ipalib/x509.py b/ipalib/x509.py
|
|
index 1274673c35e3218c5b2de0b910289d1ea24273c6..1b133adfb54f3a74011ec14dafbf6f5d379ab4c4 100644
|
|
--- a/ipalib/x509.py
|
|
+++ b/ipalib/x509.py
|
|
@@ -141,6 +141,14 @@ def get_subject(certificate, datatype=PEM, dbdir=None):
|
|
nsscert = load_certificate(certificate, datatype, dbdir)
|
|
return nsscert.subject
|
|
|
|
+def get_issuer(certificate, datatype=PEM, dbdir=None):
|
|
+ """
|
|
+ Load an X509.3 certificate and get the issuer.
|
|
+ """
|
|
+
|
|
+ nsscert = load_certificate(certificate, datatype, dbdir)
|
|
+ return nsscert.issuer
|
|
+
|
|
def get_serial_number(certificate, datatype=PEM, dbdir=None):
|
|
"""
|
|
Return the decimal value of the serial number.
|
|
diff --git a/ipapython/certmonger.py b/ipapython/certmonger.py
|
|
index 22a599ae69526b82b9364b96271d44306e440315..bdc8591e7a1ddd91455b910f0ee125881913e419 100644
|
|
--- a/ipapython/certmonger.py
|
|
+++ b/ipapython/certmonger.py
|
|
@@ -22,6 +22,7 @@
|
|
# server certificates created during the IPA server installation.
|
|
|
|
import os
|
|
+import sys
|
|
import re
|
|
import time
|
|
from ipapython import ipautil
|
|
@@ -329,6 +330,70 @@ def remove_principal_from_cas():
|
|
fp.write(line)
|
|
fp.close()
|
|
|
|
+# Routines specific to renewing dogtag CA certificates
|
|
+def get_pin(token):
|
|
+ """
|
|
+ Dogtag stores its NSS pin in a file formatted as token:PIN.
|
|
+
|
|
+ The caller is expected to handle any exceptions raised.
|
|
+ """
|
|
+ filename = '/var/lib/pki-ca/conf/password.conf'
|
|
+ with open(filename, 'r') as f:
|
|
+ for line in f:
|
|
+ (tok, pin) = line.split('=', 1)
|
|
+ if token == tok:
|
|
+ return pin.strip()
|
|
+ return None
|
|
+
|
|
+def dogtag_start_tracking(ca, nickname, pin, pinfile, secdir, command):
|
|
+ """
|
|
+ Tell certmonger to start tracking a dogtag CA certificate. These
|
|
+ are handled differently because their renewal must be done directly
|
|
+ and not through IPA.
|
|
+
|
|
+ This uses the generic certmonger command getcert so we can specify
|
|
+ a different helper.
|
|
+
|
|
+ command is the script to execute.
|
|
+
|
|
+ Returns the stdout, stderr and returncode from running ipa-getcert
|
|
+
|
|
+ This assumes that certmonger is already running.
|
|
+ """
|
|
+ if not cert_exists(nickname, os.path.abspath(secdir)):
|
|
+ raise RuntimeError('Nickname "%s" doesn\'t exist in NSS database "%s"' % (nickname, secdir))
|
|
+
|
|
+ if command is not None and not os.path.isabs(command):
|
|
+ if sys.maxsize > 2**32:
|
|
+ libpath = 'lib64'
|
|
+ else:
|
|
+ libpath = 'lib'
|
|
+ command = '/usr/%s/ipa/certmonger/%s' % (libpath, command)
|
|
+
|
|
+ args = ["/usr/bin/getcert", "start-tracking",
|
|
+ "-d", os.path.abspath(secdir),
|
|
+ "-n", nickname,
|
|
+ "-c", ca,
|
|
+ "-C", command,
|
|
+ ]
|
|
+
|
|
+ if pinfile:
|
|
+ args.append("-p")
|
|
+ args.append(pinfile)
|
|
+ else:
|
|
+ args.append("-P")
|
|
+ args.append(pin)
|
|
+
|
|
+ if ca == 'dogtag-ipa-retrieve-agent-submit':
|
|
+ # We cheat and pass in the nickname as the profile when
|
|
+ # renewing on a clone. The submit otherwise doesn't pass in the
|
|
+ # nickname and we need some way to find the right entry in LDAP.
|
|
+ args.append("-T")
|
|
+ args.append(nickname)
|
|
+
|
|
+ (stdout, stderr, returncode) = ipautil.run(args, nolog=[pin])
|
|
+
|
|
+
|
|
if __name__ == '__main__':
|
|
request_id = request_cert("/etc/httpd/alias", "Test", "cn=tiger.example.com,O=IPA", "HTTP/tiger.example.com@EXAMPLE.COM")
|
|
csr = get_request_value(request_id, 'csr')
|
|
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
|
|
index 22c8e2937a731252ffcac77c9bd7e0bf636e61ff..bed5435b5dfb3ff6e36d50b9eba422660fa25571 100644
|
|
--- a/ipapython/ipautil.py
|
|
+++ b/ipapython/ipautil.py
|
|
@@ -42,6 +42,7 @@ import xmlrpclib
|
|
import datetime
|
|
import netaddr
|
|
import time
|
|
+import krbV
|
|
from dns import resolver, rdatatype
|
|
from dns.exception import DNSException
|
|
|
|
@@ -1086,3 +1087,25 @@ def wait_for_open_socket(socket_name, timeout=0):
|
|
time.sleep(1)
|
|
else:
|
|
raise e
|
|
+
|
|
+def kinit_hostprincipal(keytab, ccachedir, principal):
|
|
+ """
|
|
+ Given a ccache directory and a principal kinit as that user.
|
|
+
|
|
+ This blindly overwrites the current CCNAME so if you need to save
|
|
+ it do so before calling this function.
|
|
+
|
|
+ Thus far this is used to kinit as the local host.
|
|
+ """
|
|
+ try:
|
|
+ ccache_file = 'FILE:%s/ccache' % ccachedir
|
|
+ krbcontext = krbV.default_context()
|
|
+ ktab = krbV.Keytab(name=keytab, context=krbcontext)
|
|
+ princ = krbV.Principal(name=principal, context=krbcontext)
|
|
+ os.environ['KRB5CCNAME'] = ccache_file
|
|
+ ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=princ)
|
|
+ ccache.init(princ)
|
|
+ ccache.init_creds_keytab(keytab=ktab, principal=princ)
|
|
+ return ccache_file
|
|
+ except krbV.Krb5Error, e:
|
|
+ raise StandardError('Error initializing principal %s in %s: %s' % (principal, keytab, str(e)))
|
|
diff --git a/ipapython/platform/base.py b/ipapython/platform/base.py
|
|
index 6f9d3867ad48360727472f8c5231c030ce9d8bc2..8c694ac04c35e3a2f6b0cf9af662712373cec997 100644
|
|
--- a/ipapython/platform/base.py
|
|
+++ b/ipapython/platform/base.py
|
|
@@ -25,7 +25,7 @@ from ipalib.plugable import MagicDict
|
|
wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc',
|
|
'messagebus', 'nslcd', 'nscd', 'ntpd', 'portmap',
|
|
'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd',
|
|
- 'rpcidmapd']
|
|
+ 'rpcidmapd', 'pki_cad']
|
|
|
|
|
|
# The common ports for these services. This is used to wait for the
|
|
diff --git a/ipapython/platform/fedora16.py b/ipapython/platform/fedora16.py
|
|
index 8b730e41cbdd63bbe9d0c9cb7809d0f6d4de8fbb..100bbb2abd93f3d07264d53a66bab7e9b2fc01ae 100644
|
|
--- a/ipapython/platform/fedora16.py
|
|
+++ b/ipapython/platform/fedora16.py
|
|
@@ -60,6 +60,7 @@ system_units['dirsrv'] = 'dirsrv@.service'
|
|
system_units['pkids'] = 'dirsrv@PKI-IPA.service'
|
|
# Our PKI instance is pki-cad@pki-ca.service
|
|
system_units['pki-cad'] = 'pki-cad@pki-ca.service'
|
|
+system_units['pki_cad'] = system_units['pki-cad']
|
|
|
|
class Fedora16Service(systemd.SystemdService):
|
|
def __init__(self, service_name):
|
|
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
|
index 62c1dc4d082df740f675d8447a7dd13d69f2ec88..2644689a0bc18fdb97d1e66d3f929af24cd101ba 100644
|
|
--- a/ipaserver/install/cainstance.py
|
|
+++ b/ipaserver/install/cainstance.py
|
|
@@ -37,6 +37,7 @@ import stat
|
|
import socket
|
|
from ipapython import dogtag
|
|
from ipapython.certdb import get_ca_nickname
|
|
+from ipapython import certmonger
|
|
from ipalib import pkcs10, x509
|
|
from ipalib.dn import DN
|
|
import subprocess
|
|
@@ -324,7 +325,7 @@ class CADSInstance(service.Service):
|
|
# We only handle one server cert
|
|
self.nickname = server_certs[0][0]
|
|
self.dercert = dsdb.get_cert_from_db(self.nickname, pem=False)
|
|
- dsdb.track_server_cert(self.nickname, self.principal, dsdb.passwd_fname)
|
|
+ dsdb.track_server_cert(self.nickname, self.principal, dsdb.passwd_fname, 'restart_dirsrv %s' % self.serverid)
|
|
|
|
def create_certdb(self):
|
|
"""
|
|
@@ -337,7 +338,7 @@ class CADSInstance(service.Service):
|
|
cadb.export_ca_cert('ipaCert', False)
|
|
dsdb.create_from_cacert(cadb.cacert_fname, passwd=None)
|
|
self.dercert = dsdb.create_server_cert("Server-Cert", self.fqdn, cadb)
|
|
- dsdb.track_server_cert("Server-Cert", self.principal, dsdb.passwd_fname)
|
|
+ dsdb.track_server_cert("Server-Cert", self.principal, dsdb.passwd_fname, 'restart_dirsrv %s' % self.serverid)
|
|
dsdb.create_pin_file()
|
|
|
|
def enable_ssl(self):
|
|
@@ -404,6 +405,24 @@ class CADSInstance(service.Service):
|
|
# At one time we removed this user on uninstall. That can potentially
|
|
# orphan files, or worse, if another useradd runs in the intermim,
|
|
# cause files to have a new owner.
|
|
+ cmonger = ipaservices.knownservices.certmonger
|
|
+ ipaservices.knownservices.messagebus.start()
|
|
+ cmonger.start()
|
|
+
|
|
+ for nickname in ['Server-Cert cert-pki-ca',
|
|
+ 'auditSigningCert cert-pki-ca',
|
|
+ 'ocspSigningCert cert-pki-ca',
|
|
+ 'subsystemCert cert-pki-ca']:
|
|
+ try:
|
|
+ certmonger.stop_tracking('/var/lib/pki-ca/alias', nickname=nickname)
|
|
+ except (ipautil.CalledProcessError, RuntimeError), e:
|
|
+ root_logger.error("certmonger failed to stop tracking certificate: %s" % str(e))
|
|
+
|
|
+ try:
|
|
+ certmonger.stop_tracking('/etc/httpd/alias', nickname='ipaCert')
|
|
+ except (ipautil.CalledProcessError, RuntimeError), e:
|
|
+ root_logger.error("certmonger failed to stop tracking certificate: %s" % str(e))
|
|
+ cmonger.stop()
|
|
|
|
class CAInstance(service.Service):
|
|
"""
|
|
@@ -526,6 +545,11 @@ class CAInstance(service.Service):
|
|
self.step("requesting RA certificate from CA", self.__request_ra_certificate)
|
|
self.step("issuing RA agent certificate", self.__issue_ra_cert)
|
|
self.step("adding RA agent as a trusted user", self.__configure_ra)
|
|
+ self.step("configure certificate renewals", self.configure_renewal)
|
|
+ else:
|
|
+ self.step("configure certmonger for renewals", self.configure_certmonger_renewal)
|
|
+ self.step("configure clone certificate renewals", self.configure_clone_renewal)
|
|
+ self.step("configure Server-Cert certificate renewal", self.track_servercert)
|
|
self.step("Configure HTTP to proxy connections", self.__http_proxy)
|
|
|
|
self.start_creation("Configuring certificate server", 210)
|
|
@@ -797,6 +821,18 @@ class CAInstance(service.Service):
|
|
finally:
|
|
os.remove(agent_name)
|
|
|
|
+ self.configure_agent_renewal()
|
|
+
|
|
+ def configure_agent_renewal(self):
|
|
+ """
|
|
+ Set up the agent cert for renewal. No need to make any changes to
|
|
+ the dogtag LDAP here since the originator will do that so we
|
|
+ only call restart_httpd after retrieving the cert.
|
|
+
|
|
+ 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')
|
|
+
|
|
def __configure_ra(self):
|
|
# Create an RA user in the CA LDAP server and add that user to
|
|
# the appropriate groups so it can issue certificates without
|
|
@@ -1058,6 +1094,8 @@ class CAInstance(service.Service):
|
|
# cause files to have a new owner.
|
|
user_exists = self.restore_state("user_exists")
|
|
|
|
+ installutils.remove_file("/var/lib/certmonger/cas/ca_renewal")
|
|
+
|
|
def publish_ca_cert(self, location):
|
|
args = ["-L", "-n", self.canickname, "-a"]
|
|
(cert, err, returncode) = self.__run_certutil(args)
|
|
@@ -1070,6 +1108,77 @@ class CAInstance(service.Service):
|
|
shutil.copy(ipautil.SHARE_DIR + "ipa-pki-proxy.conf",
|
|
HTTPD_CONFD + "ipa-pki-proxy.conf")
|
|
|
|
+ def track_servercert(self):
|
|
+ try:
|
|
+ pin = certmonger.get_pin('internal')
|
|
+ except IOError, e:
|
|
+ raise RuntimeError('Unable to determine PIN for CA instance: %s' % str(e))
|
|
+ certmonger.dogtag_start_tracking('dogtag-ipa-renew-agent', 'Server-Cert cert-pki-ca', pin, None, '/var/lib/pki-ca/alias', 'restart_pkicad "Server-Cert cert-pki-ca"')
|
|
+
|
|
+ def configure_renewal(self):
|
|
+ cmonger = ipaservices.knownservices.certmonger
|
|
+ cmonger.enable()
|
|
+ ipaservices.knownservices.messagebus.start()
|
|
+ cmonger.start()
|
|
+
|
|
+ try:
|
|
+ pin = certmonger.get_pin('internal')
|
|
+ except IOError, e:
|
|
+ raise RuntimeError('Unable to determine PIN for CA instance: %s' % str(e))
|
|
+
|
|
+ # Server-Cert cert-pki-ca is renewed per-server
|
|
+ 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, '/var/lib/pki-ca/alias', 'renew_ca_cert "%s"' % nickname)
|
|
+
|
|
+ # 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')
|
|
+
|
|
+ def configure_certmonger_renewal(self):
|
|
+ """
|
|
+ Create a new CA type for certmonger that will retrieve updated
|
|
+ certificates from the dogtag master server.
|
|
+ """
|
|
+ target_fname = '/var/lib/certmonger/cas/ca_renewal'
|
|
+ if ipautil.file_exists(target_fname):
|
|
+ # This CA can be configured either during initial CA installation
|
|
+ # if the replica is created with --setup-ca or when Apache is
|
|
+ # being configured if not.
|
|
+ return
|
|
+ txt = ipautil.template_file(ipautil.SHARE_DIR + "ca_renewal", dict())
|
|
+ fd = open(target_fname, "w")
|
|
+ fd.write(txt)
|
|
+ fd.close()
|
|
+ os.chmod(target_fname, 0600)
|
|
+ ipaservices.restore_context(target_fname)
|
|
+
|
|
+ cmonger = ipaservices.knownservices.certmonger
|
|
+ cmonger.enable()
|
|
+ ipaservices.knownservices.messagebus.start()
|
|
+ cmonger.restart()
|
|
+
|
|
+ def configure_clone_renewal(self):
|
|
+ """
|
|
+ The actual renewal is done on the master. On the clone side we
|
|
+ use a separate certmonger CA that polls LDAP to see if an updated
|
|
+ certificate is available. If it is then it gets installed.
|
|
+ """
|
|
+
|
|
+ try:
|
|
+ pin = certmonger.get_pin('internal')
|
|
+ except IOError, e:
|
|
+ raise RuntimeError('Unable to determine PIN for CA instance: %s' % str(e))
|
|
+
|
|
+ # Server-Cert cert-pki-ca is renewed per-server
|
|
+ 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, '/var/lib/pki-ca/alias', 'restart_pkicad "%s"' % nickname)
|
|
+
|
|
+ # The agent renewal is configured in import_ra_cert which is called
|
|
+ # after the HTTP instance is created.
|
|
+
|
|
def enable_subject_key_identifier(self):
|
|
"""
|
|
See if Subject Key Identifier is set in the profile and if not, add it.
|
|
@@ -1109,6 +1218,21 @@ class CAInstance(service.Service):
|
|
# No update was done
|
|
return False
|
|
|
|
+ def is_master(self):
|
|
+ """
|
|
+ There are some tasks that are only done on a single dogtag master.
|
|
+ By default this is the first one installed. Use this to determine if
|
|
+ that is the case.
|
|
+
|
|
+ If users have changed their topology so the initial master is either
|
|
+ gone or no longer performing certain duties then it is their
|
|
+ responsibility to handle changes on upgrades.
|
|
+ """
|
|
+ master = installutils.get_directive(
|
|
+ '/var/lib/pki-ca/conf/CS.cfg', 'subsystem.select', '=')
|
|
+
|
|
+ return master == 'New'
|
|
+
|
|
def install_replica_ca(config, postinstall=False):
|
|
"""
|
|
Install a CA on a replica.
|
|
@@ -1179,6 +1303,25 @@ def install_replica_ca(config, postinstall=False):
|
|
|
|
return (ca, cs)
|
|
|
|
+def update_cert_config(nickname, cert):
|
|
+ """
|
|
+ When renewing a CA subsystem certificate the configuration file
|
|
+ needs to get the new certificate as well.
|
|
+
|
|
+ nickname is one of the known nicknames.
|
|
+ cert is a DER-encoded certificate.
|
|
+ """
|
|
+ # The cert directive to update per nickname
|
|
+ directives = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert',
|
|
+ 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert',
|
|
+ 'caSigningCert cert-pki-ca': 'ca.signing.cert',
|
|
+ 'Server-Cert cert-pki-ca': 'ca.sslserver.cert' }
|
|
+
|
|
+ installutils.set_directive('/var/lib/%s/conf/CS.cfg' % PKI_INSTANCE_NAME,
|
|
+ directives[nickname],
|
|
+ base64.b64encode(cert),
|
|
+ quotes=False, separator='=')
|
|
+
|
|
if __name__ == "__main__":
|
|
standard_logging_setup("install.log")
|
|
cs = CADSInstance()
|
|
diff --git a/selinux/ipa_dogtag/ipa_dogtag.te b/selinux/ipa_dogtag/ipa_dogtag.te
|
|
index 3750e4d1061d5268cbf826c315d2de132178d7f8..1404e17ca6d40f6678fe15a1a371a7d004df3dba 100644
|
|
--- a/selinux/ipa_dogtag/ipa_dogtag.te
|
|
+++ b/selinux/ipa_dogtag/ipa_dogtag.te
|
|
@@ -1,15 +1,19 @@
|
|
-module ipa_dogtag 1.4;
|
|
+module ipa_dogtag 1.5;
|
|
|
|
require {
|
|
type httpd_t;
|
|
type cert_t;
|
|
type pki_ca_t;
|
|
type pki_ca_var_lib_t;
|
|
+ type certmonger_t;
|
|
class dir write;
|
|
class dir add_name;
|
|
class dir remove_name;
|
|
class dir search;
|
|
class dir getattr;
|
|
+ class file read;
|
|
+ class file getattr;
|
|
+ class file open;
|
|
class file create;
|
|
class file write;
|
|
class file rename;
|
|
@@ -35,3 +39,7 @@ allow pki_ca_t cert_t:lnk_file unlink;
|
|
|
|
# Let apache read the CRLs
|
|
allow httpd_t pki_ca_var_lib_t:dir { search getattr };
|
|
+
|
|
+# Let certmonger manage the dogtag certificate database for renewals
|
|
+allow certmonger_t pki_ca_var_lib_t:dir { search getattr} ;
|
|
+allow certmonger_t pki_ca_var_lib_t:file { read write getattr open };
|
|
--
|
|
1.7.11.2
|
|
|