The command ipa-getcert rekey no longer revokes the old certificate.
ipa-getcert rekey
# certutil -d /etc/httpd/alias/ -L -n Server-Cert | grep Serial Serial Number: 268369924 (0xfff0004) # ipa-getcert rekey -d /etc/httpd/alias -n Server-Cert Resubmitting "20180401114816" to "IPA". # certutil -d /etc/httpd/alias/ -L -n Server-Cert | grep Serial Serial Number: 268369925 (0xfff0005) # ipa cert-show 0xfff0004 | grep Revoked Revoked: False
The previous certificate should get revoked automatically.
freeipa-server-4.6.3-2.fc27.x86_64 freeipa-client-4.6.3-2.fc27.x86_64 package ipa-server is not installed package ipa-client is not installed 389-ds-base-1.3.7.10-1.fc27.x86_64 pki-ca-10.5.6-2.fc27.noarch krb5-server-1.15.2-7.fc27.x86_64 certmonger-0.79.5-2.fc27.x86_64
Just in case it makes a difference: my test system is composed of three replicas, two of them with CA and KRA.
I'm seeing one RPC request for the rekeying operation, [xmlserver] ... cert_request('MIIE...', profile_id='caIPAserviceCert', principal='HTTP/host.ipa.example@IPA.EXAMPLE', add=True, version='2.51'): SUCCESS
[xmlserver] ... cert_request('MIIE...', profile_id='caIPAserviceCert', principal='HTTP/host.ipa.example@IPA.EXAMPLE', add=True, version='2.51'): SUCCESS
IPA keeps the old certificates in the multi-valued userCert attribute of the principal. For the HTTP server, it's krbprincipalname=HTTP/hostname@REALM,cn=services,cn=accounts,$SUFFIX. The old certs could be used to fix existing systems.
userCert
krbprincipalname=HTTP/hostname@REALM,cn=services,cn=accounts,$SUFFIX
On a side note, the certificates are pretty large. It might be a good idea to replace the revoked certificates with a reference to Dogtag's tree, e.g. cn=268369925,ou=certificateRepository,ou=ca,o=ipaca for serial 0xff0004.
cn=268369925,ou=certificateRepository,ou=ca,o=ipaca
0xff0004
ipa service-del correctly revokes all certificates, both the current one and all old ones.
ipa service-del
The service_mod call is wrong. The cert_request plugin calls service_mod but the service plugin doesn't recognize that it should revoke the old certs.
service_mod
cert_request
(Pdb) w /usr/share/ipa/wsgi.py(57)application() -> return api.Backend.wsgi_dispatch(environ, start_response) /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(265)__call__() -> return self.route(environ, start_response) /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(277)route() -> return app(environ, start_response) /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(693)__call__() -> environ, start_response) /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(429)__call__() -> response = self.wsgi_execute(environ) /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(370)wsgi_execute() -> result = command(*args, **options) /usr/lib/python3.6/site-packages/ipalib/frontend.py(450)__call__() -> return self.__do_call(*args, **options) /usr/lib/python3.6/site-packages/ipalib/frontend.py(478)__do_call() -> ret = self.run(*args, **options) /usr/lib/python3.6/site-packages/ipalib/frontend.py(800)run() -> return self.execute(*args, **options) /usr/lib/python3.6/site-packages/ipaserver/plugins/cert.py(894)execute() -> if principal_type == SERVICE: /usr/lib/python3.6/site-packages/ipalib/frontend.py(450)__call__() -> return self.__do_call(*args, **options) /usr/lib/python3.6/site-packages/ipalib/frontend.py(478)__do_call() -> ret = self.run(*args, **options) /usr/lib/python3.6/site-packages/ipalib/frontend.py(800)run() -> return self.execute(*args, **options) /usr/lib/python3.6/site-packages/ipaserver/plugins/baseldap.py(1422)execute() -> *keys, **options) > /usr/lib/python3.6/site-packages/ipaserver/plugins/service.py(698)pre_callback() -> if 'usercertificate' in options and ca_is_enabled: (Pdb) p 'usercertificate' in options False (Pdb) p options {'addattr': ('usercertificate=MIIFo...',), 'rights': False, 'all': False, 'raw': False, 'version': '2.229', 'no_members': False}
host_mod is also affected. user_mod seems to ignore user certificates.
host_mod
user_mod
@ftweedal user_mod doesn't revoke old user certs. Is this the expected behavior?
Metadata Update from @rcritten: - Issue assigned to rcritten - Issue priority set to: critical - Issue set to the milestone: FreeIPA 4.7
Researching this has exposed another bug in cert_request.
cert_request uses _mod to set the usercertificate value. This does a full attribute replace, it is the equivalent of string a = b rather that list a += b.
The revocation code is already smart enough to revoke all the certs so if you do something like:
# getcert request ... -K test/$HOSTNAME # ipa service-add-cert --certificate=<other cert. test/$HOSTNAME
You now have 2 valid certs in a service (why you'd want to is beside the point).
When you renew the cert them BOTH are revoked
# getcert resubmit ...
There is only one cert in ipa service-show because the other two have been revoked and/or removed from the entry (the revoke_cert cmd is already smart enough to only revoke certs issued by IPA).
Thinking more on this I'm not sure if this is a bug, feature, side-effect or expected.
The ONLY way that a second IPA-issued cert could get into the entry is if it is required for a DIFFERENT service/host/object and then added to another entry (which is how I reproduced this).
I don't know that this is a case we need to care about.
I think it would be a good idea to decompose the revocation and issuance behaviours. i.e. it is undecidable in general whether a new certificate is intended to supersede some existing certificate, such that revocation should be performed.
There are various heuristics you could use (e.g. "for cert with same key and same characteristics, which is close to expiry, assume it should be revoked). But even then, if it is close to expiry there is little benefit to revoking it. And the logic is fuzzy. And the heuristic are non-trivial.
I would rather see the behaviours decomposed and no implicit revocation. If cert-request revokes certificates it should be explicitly requested, and ideally the certificate(s) to revoke explicitly specified. But at that point it's simpler to just run cert-request and cert-revoke as separate commands.
cert-request
cert-revoke
Thoughts?
(Side-note, I am cool with {user,host,service}-del revoking certificates. (Although there should probably be a way to suppress that behaviour... but it's a question for a different ticket.)
{user,host,service}-del
Some other notes I put in the PR (https://github.com/freeipa/freeipa/pull/1915):
As I alluded in the ticket (https://pagure.io/freeipa/issue/7482) I think we should have a broader discussion about what is the correct revocation behaviour in cert-request.
There are three basic scenarios where cert-request will be revoked:
Proposal:
remove revocation behaviour from cert-request
cert-request CSR --principal PRINC --revoke ISSUER:SERIAL
ISSUER:SERIAL
enhance the IPA certmonger helper to supply the appropriate options or invoke ipa cert-revoke separately, to revoke the certificate being renewed. IIIRC the old certificate is provided in the certmonger helper's environment so this should be straightforward.
ipa cert-revoke
Closing invalid.
Design page for certifiate renewal standardisation: https://www.freeipa.org/page/V4/Certificate_revocation_behaviour_standardisation
Associated ticket: https://pagure.io/freeipa/issue/7580
Metadata Update from @ftweedal: - Issue close_status updated to: invalid