Enable upgrades from a mod_nss-installed master to mod_ssl

The existing private/public keys are migrated to PEM files
via a PKCS#12 temporary file. This should work for both
IPA-generated and user-provided server certificates.

Related: https://pagure.io/freeipa/issue/3757
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Rob Crittenden 2017-12-05 09:22:34 -05:00 committed by Stanislav Laznicka
parent 5c64e28512
commit 4596674481
No known key found for this signature in database
GPG Key ID: C98C414936B1A7F3
2 changed files with 88 additions and 59 deletions

View File

@ -116,6 +116,8 @@ class HTTPInstance(service.Service):
self.step("stopping httpd", self.__stop)
self.step("backing up ssl.conf", self.backup_ssl_conf)
self.step("disabling nss.conf", self.disable_nss_conf)
self.step("configuring mod_ssl certificate paths",
self.configure_mod_ssl_certs)
self.step("setting mod_ssl protocol list to TLSv1.0 - TLSv1.2",
self.set_mod_ssl_protocol)
self.step("configuring mod_ssl log directory",
@ -198,6 +200,11 @@ class HTTPInstance(service.Service):
tasks.configure_http_gssproxy_conf(IPAAPI_USER)
services.knownservices.gssproxy.restart()
def get_mod_nss_nickname(self):
cert = installutils.get_directive(paths.HTTPD_NSS_CONF, 'NSSNickname')
nickname = installutils.unquote_directive_value(cert, quote_char="'")
return nickname
def backup_ssl_conf(self):
self.fstore.backup_file(paths.HTTPD_SSL_CONF)
@ -225,7 +232,6 @@ class HTTPInstance(service.Service):
if sysupgrade.get_upgrade_state('http', OCSP_ENABLED) is None:
self.__disable_mod_ssl_ocsp()
sysupgrade.set_upgrade_state('http', OCSP_ENABLED, False)
>>>>>>> 754c26ef6... Revisions for ocsp
def __disable_mod_ssl_ocsp(self):
aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD)
@ -250,6 +256,35 @@ class HTTPInstance(service.Service):
aug.set(ocsp_comment, '{} {}'.format(OCSP_DIRECTIVE, ocsp_state))
aug.save()
# def disable_mod_nss_ocsp(self):
# if sysupgrade.get_upgrade_state('http', NSS_OCSP_ENABLED) is None:
# self.__disable_mod_nss_ocsp()
# sysupgrade.set_upgrade_state('http', NSS_OCSP_ENABLED, False)
# def __disable_mod_nss_ocsp(self):
# aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD)
#
# aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
# aug.set('/augeas/load/Httpd/incl', paths.HTTPD_NSS_CONF)
# aug.load()
#
# path = '/files{}/VirtualHost'.format(paths.HTTPD_NSS_CONF)
# ocsp_path = '{}/directive[.="{}"]'.format(path, OCSP_DIRECTIVE)
# ocsp_arg = '{}/arg'.format(ocsp_path)
# ocsp_comment = '{}/#comment[.="{}"]'.format(path, OCSP_DIRECTIVE)
#
# ocsp_dir = aug.get(ocsp_path)
#
# # there is NSSOCSP directive in nss.conf file, comment it
# # otherwise just do nothing
# if ocsp_dir is not None:
# ocsp_state = aug.get(ocsp_arg)
# aug.remove(ocsp_arg)
# aug.rename(ocsp_path, '#comment')
# aug.set(ocsp_comment, '{} {}'.format(OCSP_DIRECTIVE, ocsp_state))
# aug.save()
def __add_include(self):
"""This should run after __set_mod_nss_port so is already backed up"""
if installutils.update_file(paths.HTTPD_SSL_CONF,
@ -347,7 +382,7 @@ class HTTPInstance(service.Service):
finally:
if prev_helper is not None:
certmonger.modify_ca_helper('IPA', prev_helper)
self.cert = x509.load_der_x509_certificate(
self.cert = x509.load_certificate_from_file(
paths.HTTPD_CERT_FILE
)
@ -363,7 +398,10 @@ class HTTPInstance(service.Service):
# store the CA cert nickname so that we can publish it later on
# self.cacert_nickname = db.cacert_name
# FIXME: figure this out too
sysupgrade.set_upgrade_state('ssl.conf', 'migrated_to_mod_ssl', True)
def configure_mod_ssl_certs(self):
"""Configure the mod_ssl certificate directives"""
installutils.set_directive(paths.HTTPD_SSL_CONF,
'SSLCertificateFile',
paths.HTTPD_CERT_FILE, False)
@ -499,14 +537,14 @@ class HTTPInstance(service.Service):
str(e))
def start_tracking_certificates(self):
cert = x509.load_pem_x509_certificate(paths.HTTPD_CERT_FILE)
cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
if certs.is_ipa_issued_cert(api, cert):
request_id = certmonger.start_tracking(
certpath=(paths.HTTPD_CERT_FILE, paths.HTTPD_CERT_KEY),
post_command='restart_httpd'
certpath=(paths.HTTPD_CERT_FILE, paths.HTTPD_KEY_FILE),
post_command='restart_httpd', storage='FILE'
)
subject = str(DN(cert.subject))
certmonger.add_principal(request_id, principal)
certmonger.add_principal(request_id, self.principal)
certmonger.add_subject(request_id, subject)
else:
logger.debug("Will not track HTTP server cert %s as it is not "
@ -530,3 +568,32 @@ class HTTPInstance(service.Service):
remote_ldap.simple_bind(ipaldap.DIRMAN_DN,
self.dm_password)
replication.wait_for_entry(remote_ldap, service_dn, timeout=60)
def migrate_to_mod_ssl(self):
"""For upgrades only, migrate from mod_nss to mod_ssl"""
db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR)
nickname = self.get_mod_nss_nickname()
with tempfile.NamedTemporaryFile() as temp:
pk12_password = ipautil.ipa_generate_password()
pk12_pwdfile = ipautil.write_tmp_file(pk12_password)
db.export_pkcs12(temp.name, pk12_pwdfile.name, nickname)
certs.install_pem_from_p12(temp.name,
pk12_password,
paths.HTTPD_CERT_FILE)
certs.install_key_from_p12(temp.name,
pk12_password,
paths.HTTPD_KEY_FILE)
self.configure_mod_ssl_certs()
self.set_mod_ssl_protocol()
self.set_mod_ssl_logdir()
self.cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
if self.ca_is_configured:
db.untrack_server_cert(nickname)
self.start_tracking_certificates()
# remove nickname and CA certs from NSS db
self.disable_nss_conf()

View File

@ -13,7 +13,7 @@ import fileinput
import sys
from augeas import Augeas
import dns.exception
from ipalib import api
from ipalib import api, x509
from ipalib.install import certmonger, sysrestore
import SSSDConfig
import ipalib.util
@ -58,6 +58,7 @@ else:
if six.PY3:
unicode = str
logger = logging.getLogger(__name__)
@ -987,13 +988,12 @@ def certificate_renewal_update(ca, ds, http):
return False
# Check the http server cert if issued by IPA
http_nickname = http.get_mod_nss_nickname()
http_db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR)
if http_db.is_ipa_issued_cert(api, http_nickname):
cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
if certs.is_ipa_issued_cert(api, cert):
requests.append(
{
'cert-database': paths.HTTPD_ALIAS_DIR,
'cert-nickname': http_nickname,
'cert-file': paths.HTTPD_CERT_FILE,
'key-storage': paths.HTTPD_KEY_FILE,
'ca-name': 'IPA',
'cert-postsave-command': template % 'restart_httpd',
}
@ -1436,38 +1436,18 @@ def fix_trust_flags():
sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True)
def update_mod_nss_protocol(http):
logger.info('[Updating mod_nss protocol versions]')
def migrate_to_mod_ssl(http):
logger.info('[Migrating from mod_nss to mod_ssl]')
if sysupgrade.get_upgrade_state('nss.conf', 'protocol_updated_tls12'):
logger.info("Protocol versions already updated")
if sysupgrade.get_upgrade_state('ssl.conf', 'migrated_to_mod_ssl'):
logger.info("Already migrated to mod_ssl")
return
http.set_mod_nss_protocol()
http.migrate_to_mod_ssl()
sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True)
sysupgrade.set_upgrade_state('ssl.conf', 'migrated_to_mod_ssl', True)
def disable_mod_nss_ocsp(http):
logger.info('[Updating mod_nss enabling OCSP]')
http.disable_mod_nss_ocsp()
def update_mod_nss_cipher_suite(http):
logger.info('[Updating mod_nss cipher suite]')
revision = sysupgrade.get_upgrade_state('nss.conf', 'cipher_suite_updated')
if revision and revision >= httpinstance.NSS_CIPHER_REVISION:
logger.debug("Cipher suite already updated")
return
http.set_mod_nss_cipher_suite()
sysupgrade.set_upgrade_state(
'nss.conf',
'cipher_suite_updated',
httpinstance.NSS_CIPHER_REVISION)
def update_ipa_httpd_service_conf(http):
logger.info('[Updating HTTPD service IPA configuration]')
@ -1628,21 +1608,6 @@ def enable_certauth(krb):
aug.close()
def disable_httpd_system_trust(http):
ca_certs = []
db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR)
for nickname, trust_flags in db.list_certs():
if not trust_flags.has_key:
cert = db.get_cert_from_db(nickname)
if cert:
ca_certs.append((cert, nickname, trust_flags))
if http.disable_system_trust():
for cert, nickname, trust_flags in ca_certs:
db.add_cert(cert, nickname, trust_flags)
def upgrade_configuration():
"""
Execute configuration upgrade of the IPA services
@ -1797,12 +1762,9 @@ def upgrade_configuration():
http.enable_kdcproxy()
http.stop()
disable_httpd_system_trust(http)
update_ipa_httpd_service_conf(http)
update_ipa_http_wsgi_conf(http)
update_mod_nss_protocol(http)
update_mod_nss_cipher_suite(http)
disable_mod_nss_ocsp(http)
migrate_to_mod_ssl(http)
fix_trust_flags()
update_http_keytab(http)
http.configure_gssproxy()