Petr Viktorin wrote:
On 01/15/2013 03:41 PM, Petr Viktorin wrote:
On 01/14/2013 10:56 PM, Rob Crittenden wrote:
Petr Viktorin wrote:
On 01/12/2013 12:49 AM, Rob Crittenden wrote:
Rob Crittenden wrote:
Petr Viktorin wrote:
On 01/07/2013 05:42 PM, Rob Crittenden wrote:
Petr Viktorin wrote:
On 01/07/2013 03:09 PM, Rob Crittenden wrote:
Petr Viktorin wrote:
[...]
Works for me, but I have some questions (this is an area I know
little
about).
Can we be 100% sure these certs are always renewed together? Is
certmonger the only possible mechanism to update them?
You raise a good point. If though some mechanism someone replaces
one of
these certs it will cause the script to fail. Some
notification of
this
failure will be logged though, and of course, the certs won't be
renewed.
One could conceivably manually renew one of these certificates.
It is
probably a very remote possibility but it is non-zero.
Can we be sure certmonger always does the updates in parallel?
If it
managed to update the audit cert before starting on the others,
we'd
get
no CA restart for the others.
These all get issued at the same time so should expire at the
same
time
as well (see problem above). The script will hang around for 10
minutes
waiting for the renewal to complete, then give up.
The certs might take different amounts of time to update, right?
Eventually, the expirations could go out of sync enough for it to
matter.
AFAICS, without proper locking we still get a race condition when
the
other certs start being renewed some time (much less than 10 min)
after
the audit one:
(time axis goes down)
audit cert other cert
---------- ----------
certmonger does renew .
post-renew script starts .
check state of other certs: OK .
. certmonger starts renew
certutil modifies NSS DB + certmonger modifies NSS DB ==
boom!
This can't happen because we count the # of expected certs and wait
until all are in MONITORING before continuing.
The problem is that they're also in MONITORING before the whole
renewal
starts. If the script happens to check just before the state changes
from MONITORING to GENERATING_CSR or whatever, we can get
corruption.
The worse that would
happen is the trust wouldn't be set on the audit cert and dogtag
wouldn't be restarted.
The state the system would be in is this:
- audit cert trust not updated, so next restart of CA will fail
- CA is not restarted so will not use updated certificates
And anyway, why does certmonger do renewals in parallel? It
seems
that
if it did one at a time, always waiting until the post-renew
script is
done, this patch wouldn't be necessary.
From what Nalin told me certmonger has some coarse locking such
that
renewals in a the same NSS database are serialized. As you point
out, it
would be nice to extend this locking to the post renewal
scripts. We
can
ask Nalin about it. That would fix the potential corruption
issue.
It is
still much nicer to not have to restart dogtag 4 times.
Well, three extra restarts every few years seems like a small
price to
pay for robustness.
It is a bit of a problem though because the certs all renew within
seconds so end up fighting over who is restarting dogtag. This can
cause
some renewals go into a failure state to be retried later. This is
fine
functionally but makes QE a bit of a pain. You then have to make
sure
that renewal is basically done, then restart certmonger and check
everything again, over and over until all the certs are renewed.
This is
difficult to automate.
So we need to extend the certmonger lock, and wait until Dogtag is
back
up before exiting the script. That way it'd still take longer than 1
restart, but all the renews should succeed.
Right, but older dogtag versions don't have the handy servlet to tell
that the service is actually up and responding. So it is difficult to
tell from tomcat alone whether the CA is actually up and handling
requests.
Revised patch that takes advantage of new version of certmonger.
certmonger-0.65 adds locking from the time renewal begins to the
end of
the post_save_command. This lets us be sure that no other certmonger
renewals will have the NSS database open in read-write mode.
We need to be sure that tomcat is shut down before we let certmonger
save the certificate to the NSS database because dogtag opens its
database read/write and two writers can cause corruption.
rob
stop_pkicad and start_pkicad need the Dogtag version check to select
pki_cad/pki_tomcatd.
Fixed.
A more serious issue is that stop_pkicad needs to be installed on
upgrades. Currently the whole enable_certificate_renewal step in
ipa-upgradeconfig is skipped if it was done before.
I added a separate upgrade test for this. It currently won't work in
SELinux enforcing mode because certmonger isn't allowed to talk to dbus
in an rpm post script. It's being looked at.
In stop_pkicad can you change the first log message to "certmonger
stopping %sd"? It's before the action so we don't want past tense.
Fixed.
rob
I get a bunch of errors when installing the RPM:
[...]
This is the SELinux issue you were talking about. Sorry for not catching
that.
With enforcing off, the patch looks & works well for me. I'm just
concerned about this change in ipa-upgradeconfig:
@@ -707,7 +754,7 @@ def main():
# configuration has changed, restart the name server
root_logger.info('Changes to named.conf have been made,
restart named')
bindinstance.BindInstance(fstore).restart()
- ca_restart = ca_restart or enable_certificate_renewal(ca) or
upgrade_ipa_profile(ca, api.env.domain, fqdn)
+ ca_restart = ca_restart or enable_certificate_renewal(ca) or
upgrade_ipa_profile(ca, api.env.domain, fqdn) or
certificate_renewal_stop_ca(ca)
If the enable_certificate_renewal step was done already, but
upgrade_ipa_profile requests a CA restart, then the short-circuiting
`or` will be satisfied and certificate_renewal_stop_ca won't be run.
Since each upgrade step has its own checking, I think it would be safer
to use something like:
ca_restart = certificate_renewal_stop_ca(ca) or ca_restart
or even:
ca_restart = any([
ca_restart,
enable_certificate_renewal(ca),
upgrade_ipa_profile(ca, api.env.domain, fqdn),
certificate_renewal_stop_ca(ca),
])
I like this suggestion very much. Updated patch attached.
rob
>From b892b4c6d0b5c2b76c948aa094822405242e884c Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Tue, 2 Dec 2014 13:18:36 -0500
Subject: [PATCH] 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
---
freeipa.spec.in | 6 +-
install/restart_scripts/Makefile.am | 1 +
install/restart_scripts/renew_ca_cert | 38 +++++------
install/restart_scripts/renew_ra_cert | 54 ++--------------
install/restart_scripts/restart_pkicad | 25 ++++++--
install/restart_scripts/stop_pkicad | 43 +++++++++++++
install/tools/ipa-upgradeconfig | 54 +++++++++++++++-
ipapython/certmonger.py | 38 +++++++----
ipaserver/install/cainstance.py | 113 +++++++++++++++++++++++++++++----
9 files changed, 272 insertions(+), 100 deletions(-)
create mode 100644 install/restart_scripts/stop_pkicad
diff --git a/freeipa.spec.in b/freeipa.spec.in
index f1c45b6cce0ba109638bd538aa468c47d2024652..e7dd0c53dc39a8de881de3e4fe53731c0430abe7 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -213,7 +213,7 @@ Requires: wget
Requires: libcurl >= 7.21.7-2
Requires: xmlrpc-c >= 1.27.4
Requires: sssd >= 1.8.0
-Requires: certmonger >= 0.60
+Requires: certmonger >= 0.65
Requires: nss-tools
Requires: bind-utils
Requires: oddjob-mkhomedir
@@ -752,6 +752,10 @@ fi
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
%changelog
+* Fri Jan 11 2013 Rob Crittenden <rcrit...@redhat.com> - 3.0.99-10
+- Set certmonger minimum version to 0.65 for NSS locking during
+ renewal
+
* Fri Dec 7 2012 Endi S. Dewata <edew...@redhat.com> - 3.0.99-9
- Bump minimum version of pki-ca to 10.0.0-0.54.b3
diff --git a/install/restart_scripts/Makefile.am b/install/restart_scripts/Makefile.am
index 210c4863e3d7d057627370093638e5bf9c47c802..fc45ecc888a9e3a728ef49564c45b7e89ebed465 100644
--- a/install/restart_scripts/Makefile.am
+++ b/install/restart_scripts/Makefile.am
@@ -7,6 +7,7 @@ app_DATA = \
restart_pkicad \
renew_ca_cert \
renew_ra_cert \
+ stop_pkicad \
$(NULL)
EXTRA_DIST = \
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
index 5317835fc6ad7b598290fa5387be0afa46a6ca5b..b7e4ebaae89472dd12f3767616e004f96358df7e 100644
--- a/install/restart_scripts/renew_ca_cert
+++ b/install/restart_scripts/renew_ca_cert
@@ -34,8 +34,10 @@ from ipapython import services as ipaservices
from ipapython import ipautil
from ipapython import dogtag
from ipaserver.install import certs
+from ipaserver.install.cainstance import update_people_entry
from ipaserver.plugins.ldap2 import ldap2
from ipaserver.install.cainstance import update_cert_config
+from ipapython import certmonger
# This script a post-cert-install command for certmonger. When certmonger
# has renewed a CA subsystem certificate a copy is put into the replicated
@@ -82,8 +84,13 @@ except Exception, e:
finally:
shutil.rmtree(tmpdir)
-# Fix permissions on the audit cert if we're updating it
+update_cert_config(nickname, cert)
+
+if nickname == 'subsystemCert cert-pki-ca':
+ update_people_entry('pkidbuser', cert)
+
if nickname == 'auditSigningCert cert-pki-ca':
+ # Fix trust on the audit cert
db = certs.CertDB(api.env.realm, nssdir=alias_dir)
args = ['-M',
'-n', nickname,
@@ -91,25 +98,20 @@ if nickname == 'auditSigningCert cert-pki-ca':
]
try:
db.run_certutil(args)
+ syslog.syslog(syslog.LOG_NOTICE, 'Updated trust on certificate %s in %s' % (nickname, db.secdir))
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 %sd instance %s to renew %s' %
- (dogtag_instance, dogtag_instance, nickname))
+ syslog.syslog(syslog.LOG_ERR, 'Updating trust on certificate %s failed in %s' % (nickname, db.secdir))
-# We monitor 3 certs that are all likely to be renewed by certmonger more or
-# less at the same time. Each cert renewal is going to need to restart
-# the CA. Add a bit of randomness in this so not all three try to start it
-# at the same time. A restart is needed for each because there is no guarantee
-# that they will all be renewed at the same time.
-pause = random.randint(10,360)
-syslog.syslog(syslog.LOG_NOTICE, 'Pausing %d seconds to restart pki-ca' % pause)
-time.sleep(pause)
+# Now we can start the CA. Using the ipaservices start should fire
+# off the servlet to verify that the CA is actually up and responding so
+# when this returns it should be good-to-go. The CA was stopped in the
+# pre-save state.
+syslog.syslog(syslog.LOG_NOTICE, 'Starting %sd' % dogtag_instance)
try:
- ipaservices.knownservices.pki_cad.restart(dogtag_instance)
+ if configured_constants.DOGTAG_VERSION == 9:
+ ipaservices.knownservices.pki_cad.start(dogtag_instance)
+ else:
+ ipaservices.knownservices.pki_tomcatd.start(dogtag_instance)
except Exception, e:
- syslog.syslog(syslog.LOG_ERR, "Cannot restart %sd: %s" %
+ syslog.syslog(syslog.LOG_ERR, "Cannot start %sd: %s" %
(dogtag_instance, str(e)))
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
index 1f359062b49eed400aaa7b6aeea4742253707b00..a70ba5c1a842f5724ea655d579f5a71f69d0ea21 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -25,13 +25,11 @@ import tempfile
import syslog
import time
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 ipaserver.install.cainstance import update_people_entry
from ipalib import api
from ipapython.dn import DN
-from ipalib import x509
from ipalib import errors
from ipaserver.plugins.ldap2 import ldap2
import ldap as _ldap
@@ -41,52 +39,10 @@ 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)
+dercert = db.get_cert_from_db('ipaCert', pem=False)
# Load it into dogtag
-dn = 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)
-
-attempts = 0
-dogtag_uri='ldap://localhost:%d' % DEFAULT_DSPORT
-updated = False
-
-while attempts < 10:
- conn = None
- try:
- conn = 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(cert)
- 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 agent entry failed: %s' % e)
- break
- finally:
- if conn.isconnected():
- conn.disconnect()
-
-if not updated:
- syslog.syslog(syslog.LOG_ERR, '%s: Giving up. This script may be safely re-executed.' % sys.argv[0])
- sys.exit(1)
+update_people_entry('ipara', dercert)
attempts = 0
updated = False
@@ -104,11 +60,11 @@ while attempts < 10:
conn.connect(ccache=ccache)
try:
(entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'])
- entry_attrs['usercertificate'] = cert
+ entry_attrs['usercertificate'] = dercert
conn.update_entry(dn, entry_attrs, normalize=False)
except errors.NotFound:
entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'],
- usercertificate=cert)
+ usercertificate=dercert)
conn.add_entry(dn, entry_attrs, normalize=False)
except errors.EmptyModlist:
pass
diff --git a/install/restart_scripts/restart_pkicad b/install/restart_scripts/restart_pkicad
index 0b6040a9d1f48d3dfcf41149cf3251c53bf2a612..a58c3f31e1bd288587842ba5fc4335c967b9405e 100644
--- a/install/restart_scripts/restart_pkicad
+++ b/install/restart_scripts/restart_pkicad
@@ -35,8 +35,16 @@ configured_constants = dogtag.configured_constants(api)
alias_dir = configured_constants.ALIAS_DIR
dogtag_instance = configured_constants.PKI_INSTANCE_NAME
-syslog.syslog(syslog.LOG_NOTICE, "certmonger restarted %sd, nickname '%s'" %
- (dogtag_instance, nickname))
+# dogtag opens its NSS database in read/write mode so we need it
+# shut down so certmonger can open it read/write mode. This avoids
+# database corruption. It should already be stopped by the pre-command
+# but lets be sure.
+if ipaservices.knownservices.pki_cad.is_running(dogtag_instance):
+ try:
+ ipaservices.knownservices.pki_cad.stop(dogtag_instance)
+ except Exception, e:
+ syslog.syslog(syslog.LOG_ERR, "Cannot stop %sd: %s" %
+ (dogtag_instance, str(e)))
# Fix permissions on the audit cert if we're updating it
if nickname == 'auditSigningCert cert-pki-ca':
@@ -48,10 +56,13 @@ if nickname == 'auditSigningCert cert-pki-ca':
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(dogtag_instance)
- ipaservices.knownservices.pki_cad.start(dogtag_instance)
+ if configured_constants.DOGTAG_VERSION == 9:
+ ipaservices.knownservices.pki_cad.start(dogtag_instance)
+ else:
+ ipaservices.knownservices.pki_tomcatd.start(dogtag_instance)
except Exception, e:
- syslog.syslog(syslog.LOG_ERR, "Cannot restart %sd: %s" %
+ syslog.syslog(syslog.LOG_ERR, "Cannot start %sd: %s" %
(dogtag_instance, str(e)))
+else:
+ syslog.syslog(syslog.LOG_NOTICE, "certmonger started %sd, nickname '%s'" %
+ (dogtag_instance, nickname))
diff --git a/install/restart_scripts/stop_pkicad b/install/restart_scripts/stop_pkicad
new file mode 100644
index 0000000000000000000000000000000000000000..f023b1bb9c43ca2fac74ddd3e1b9676ae93c7f69
--- /dev/null
+++ b/install/restart_scripts/stop_pkicad
@@ -0,0 +1,43 @@
+#!/usr/bin/python -E
+#
+# Authors:
+# Rob Crittenden <rcrit...@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 ipapython import dogtag
+from ipalib import api
+
+api.bootstrap(context='restart')
+api.finalize()
+
+configured_constants = dogtag.configured_constants(api)
+dogtag_instance = configured_constants.PKI_INSTANCE_NAME
+
+syslog.syslog(syslog.LOG_NOTICE, "certmonger stopping %sd" % dogtag_instance)
+
+try:
+ if configured_constants.DOGTAG_VERSION == 9:
+ ipaservices.knownservices.pki_cad.start(dogtag_instance)
+ else:
+ ipaservices.knownservices.pki_tomcatd.start(dogtag_instance)
+except Exception, e:
+ syslog.syslog(syslog.LOG_ERR, "Cannot stop %sd: %s" %
+ (dogtag_instance, str(e)))
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index 0130fc14b9f9c7b66eb51657911b1f0fcfc36560..5539854d2108806e09fd6c10d395aae8cf995451 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -493,6 +493,53 @@ def enable_certificate_renewal(ca):
return False
+def certificate_renewal_stop_ca(ca):
+ """
+ Validate the certmonger configuration on certificates that already
+ have renewal configured.
+
+ As of certmonger 0.65 it now does locking from the point where it
+ generates the CSR to the end of the post-command. This is to ensure
+ that only one certmonger renewal, and hopefully, one process at a
+ time holds the NSS database open in read/write.
+ """
+ root_logger.info('[Certificate renewal should stop the CA]')
+ if not ca.is_configured():
+ root_logger.info('CA is not configured')
+ return False
+
+ nss_dir = dogtag.configured_constants().ALIAS_DIR
+ # Using the nickname find the certmonger request_id
+ criteria = (('cert_storage_location', nss_dir, certmonger.NPATH),('cert_nickname', 'auditSigningCert cert-pki-ca', None))
+ id = certmonger.get_request_id(criteria)
+ if id is None:
+ root_logger.error('Unable to find certmonger request ID for auditSigning Cert')
+ return False
+
+ if sysupgrade.get_upgrade_state('dogtag', 'stop_ca_during_renewal'):
+ return False
+
+ # State not set, lets see if we are already configured
+ pre_command = certmonger.get_request_value(id, 'pre_certsave_command')
+ if pre_command is not None:
+ if pre_command.strip().endswith('stop_pkicad'):
+ root_logger.info('Already configured to stop CA')
+ return False
+
+ # Ok, now we need to stop tracking, then we can start tracking them
+ # again with new configuration:
+ cainstance.stop_tracking_certificates(dogtag.configured_constants())
+ 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', 'stop_ca_during_renewal', True)
+ root_logger.debug('CA subsystem certificate renewal configured to stop the CA')
+ return True
+
def copy_crl_file(old_path, new_path=None):
"""
Copy CRL to new location, update permissions and SELinux context
@@ -707,7 +754,12 @@ def main():
# configuration has changed, restart the name server
root_logger.info('Changes to named.conf have been made, restart named')
bindinstance.BindInstance(fstore).restart()
- ca_restart = ca_restart or enable_certificate_renewal(ca) or upgrade_ipa_profile(ca, api.env.domain, fqdn)
+ ca_restart = any([
+ ca_restart,
+ enable_certificate_renewal(ca),
+ upgrade_ipa_profile(ca, api.env.domain, fqdn),
+ certificate_renewal_stop_ca(ca),
+ ])
if ca_restart:
root_logger.info('pki-ca configuration changed, restart pki-ca')
diff --git a/ipapython/certmonger.py b/ipapython/certmonger.py
index f29050ea96318a9564358f42405fc8849a2e27b7..d347c2aeb92a852e51da77557598ebf039bed0e7 100644
--- a/ipapython/certmonger.py
+++ b/ipapython/certmonger.py
@@ -261,7 +261,7 @@ def stop_tracking(secdir, request_id=None, nickname=None):
# Fall back to trying to stop tracking using nickname
pass
- args = ['/usr/bin/ipa-getcert',
+ args = ['/usr/bin/getcert',
'stop-tracking',
]
if request_id:
@@ -368,7 +368,8 @@ def get_pin(token, dogtag_constants=None):
return pin.strip()
return None
-def dogtag_start_tracking(ca, nickname, pin, pinfile, secdir, command):
+def dogtag_start_tracking(ca, nickname, pin, pinfile, secdir, pre_command,
+ post_command):
"""
Tell certmonger to start tracking a dogtag CA certificate. These
are handled differently because their renewal must be done directly
@@ -377,7 +378,10 @@ def dogtag_start_tracking(ca, nickname, pin, pinfile, secdir, command):
This uses the generic certmonger command getcert so we can specify
a different helper.
- command is the script to execute.
+ pre_command is the script to execute before a renewal is done.
+ post_command is the script to execute after a renewal is done.
+
+ Both commands can be None.
Returns the stdout, stderr and returncode from running ipa-getcert
@@ -386,20 +390,32 @@ def dogtag_start_tracking(ca, nickname, pin, pinfile, secdir, command):
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 pre_command is not None:
+ if not os.path.isabs(pre_command):
+ if sys.maxsize > 2**32:
+ libpath = 'lib64'
+ else:
+ libpath = 'lib'
+ pre_command = '/usr/%s/ipa/certmonger/%s' % (libpath, pre_command)
+ args.append("-B")
+ args.append(pre_command)
+
+ if post_command is not None:
+ if not os.path.isabs(post_command):
+ if sys.maxsize > 2**32:
+ libpath = 'lib64'
+ else:
+ libpath = 'lib'
+ post_command = '/usr/%s/ipa/certmonger/%s' % (libpath, post_command)
+ args.append("-C")
+ args.append(post_command)
+
if pinfile:
args.append("-p")
args.append(pinfile)
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 86c075c803e0a1e2a170c15c1b81a2456063704b..7d7e2b4f1b7c00bc058dc1c67bc0de9011164762 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -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:
--
1.8.0.2
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel