-
Notifications
You must be signed in to change notification settings - Fork 342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace service certificates with ipa-server-certinstall #6920
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ | |
from ipapython import ipaldap | ||
from ipalib import api, errors | ||
from ipaserver.install import certs, dsinstance, installutils, krbinstance | ||
from ipaserver.install import cainstance | ||
from ipaserver.install import cainstance, httpinstance | ||
|
||
|
||
class ServerCertInstall(admintool.AdminTool): | ||
|
@@ -138,6 +138,8 @@ def run(self): | |
api.Backend.ldap2.disconnect() | ||
|
||
def install_dirsrv_cert(self): | ||
from ipaserver.plugins.service import revoke_certs | ||
|
||
serverid = ipaldap.realm_to_serverid(api.env.realm) | ||
dirname = dsinstance.config_dirname(serverid) | ||
|
||
|
@@ -147,21 +149,35 @@ def install_dirsrv_cert(self): | |
['nssslpersonalityssl']) | ||
old_cert = entry.single_value['nssslpersonalityssl'] | ||
|
||
server_cert = self.import_cert(dirname, self.options.pin, | ||
old_cert, 'ldap/%s' % api.env.host, | ||
'restart_dirsrv %s' % serverid) | ||
nickname, cert = self.import_cert(dirname, self.options.pin, | ||
old_cert, 'ldap/%s' % api.env.host, | ||
'restart_dirsrv %s' % serverid) | ||
|
||
entry['nssslpersonalityssl'] = [server_cert] | ||
entry['nssslpersonalityssl'] = [nickname] | ||
try: | ||
conn.update_entry(entry) | ||
except errors.EmptyModlist: | ||
pass | ||
|
||
ds = dsinstance.DsInstance() | ||
ds.suffix = api.env.basedn | ||
ds.realm = api.env.realm | ||
ds.fqdn = api.env.host | ||
ds.service_prefix = 'ldap' | ||
ds.cert = cert | ||
name = f'{ds.service_prefix}/{ds.fqdn}' | ||
oldcerts = api.Command.cert_find(service=name)['result'] | ||
ds.add_cert_to_service(append=False) | ||
|
||
revoke_certs(oldcerts) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not comfortable with the revocation of the previous cert. For instance, if the same 3rd-party cert is used initially for both LDAP and HTTP but later on the administrator realizes he should reduce the attack surface and replaces the LDAP cert with another one (in order to have a distinct cert for each service), he doesn't want to revoke the HTTP cert. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But they should be able to issue a new HTTP, LDAP or PKINIT cert from IPA using certmonger. I'll give that a try but I don't see why it wouldn't work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So yes, it's possible. I tested replacing the Apache and LDAP certs with 3rd party certs, then replaced those with IPA-issued certificates. For Apache you first need to move the cert and key out of the way (or remove them). Then you can have certminger issue a new one: ipa-getcert request -f /var/lib/ipa/certs/httpd.crt -k /var/lib/ipa/private/httpd.key -p /var/lib/ipa/passwds/ipa.example.test-443-RSA -D ipa.example.test -D ipa-ca.example.test -K HTTP/ipa.example.test@EXAMPLE.TEST -C /usr/libexec/ipa/certmonger/restart_httpd -T caIPAserviceCert -v -w Restart httpd: systemctl restart httpd The paths are the same for all HTTP certs, CA-issued or 3rd party For 389-ds you can request a new cert: ipa-getcert request -d /etc/dirsrv/slapd-EXAMPLE-TEST -n Server-Cert -p /etc/dirsrv/slapd-EXAMPLE-TEST/pwdfile.txt -D ipa.example.test -K ldap/ipa.example.test@EXAMPLE.TEST -C "/usr/libexec/ipa/certmonger/restart_dirsrv EXAMPLE-TEST" -T caIPAserviceCert -v -w Stop dirsrv Edit dse.ldif and replace nsSSLPersonalitySSL with Server-Cert, or whatever nickname was chosen, then restart dirsrv. Done and the certs are replaced and tracked now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, I blogged about this a few years ago https://rcritten.wordpress.com/2019/05/07/how-do-i-revert-back-to-using-ipa-issued-web-ldap-certs/ |
||
|
||
def replace_http_cert(self): | ||
""" | ||
Replace the current HTTP cert-key pair with another one | ||
from a PKCS#12 file | ||
""" | ||
from ipaserver.plugins.service import revoke_certs | ||
|
||
# pass in `host_name` to perform | ||
# `NSSDatabase.verify_server_cert_validity()`` | ||
cert, key, ca_cert = self.load_pkcs12( | ||
|
@@ -184,6 +200,18 @@ def replace_http_cert(self): | |
req_id, 'HTTP/{host}'.format(host=api.env.host)) | ||
certmonger.add_subject(req_id, str(DN(cert.subject))) | ||
|
||
http = httpinstance.HTTPInstance() | ||
http.suffix = api.env.basedn | ||
http.realm = api.env.realm | ||
http.fqdn = api.env.host | ||
http.service_prefix = 'HTTP' | ||
http.cert = cert | ||
name = f'{http.service_prefix}/{http.fqdn}' | ||
oldcerts = api.Command.cert_find(service=name)['result'] | ||
http.add_cert_to_service(append=False) | ||
|
||
revoke_certs(oldcerts) | ||
|
||
def replace_kdc_cert(self): | ||
# pass in `realm` to perform `NSSDatabase.verify_kdc_cert_validity()` | ||
cert, key, ca_cert = self.load_pkcs12( | ||
|
@@ -314,7 +342,8 @@ def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): | |
cdb.import_pkcs12(pkcs12_file.name, pin) | ||
news = cdb.find_server_certs() | ||
server_certs = [item for item in news if item not in prevs] | ||
server_cert = server_certs[0][0] | ||
nickname = server_certs[0][0] | ||
cert = cdb.get_cert_from_db(nickname) | ||
|
||
if ca_enabled: | ||
# Start tracking only if the cert was issued by IPA CA | ||
|
@@ -323,11 +352,11 @@ def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): | |
get_ca_nickname(api.env.realm)) | ||
# And compare with the CA which signed this certificate | ||
if ca_cert == ipa_ca_cert: | ||
cdb.track_server_cert(server_cert, | ||
cdb.track_server_cert(nickname, | ||
principal, | ||
cdb.passwd_fname, | ||
command) | ||
except RuntimeError as e: | ||
raise admintool.ScriptError(str(e)) | ||
|
||
return server_cert | ||
return nickname, cert |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The option append=False introduces a slightly different behavior for IPA-issued certs and 3rd-party certs.
When the LDAP server cert is issued by IPA and renewed by IPA, the new certificate is added to the service entry and the old one is kept: https://github.com/freeipa/freeipa/blob/master/ipaserver/plugins/cert.py#L961-L968
With this code, if the LDAP server cert is a 3rd-party cert, it replaces the old cert in the service entry (the old cert is removed).
IMO the logic should be similar in both cases (either always replace or always add). No strong opinion on the best choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been a while so I forget my reasoning. I think it may be related to what cert-find returned since it also looks in the service cert values. I'll double-check.