diff --git a/install/share/ipa-pki-proxy.conf.template b/install/share/ipa-pki-proxy.conf.template index 04460197e..0710641c3 100644 --- a/install/share/ipa-pki-proxy.conf.template +++ b/install/share/ipa-pki-proxy.conf.template @@ -1,4 +1,4 @@ -# VERSION 13 - DO NOT REMOVE THIS LINE +# VERSION 14 - DO NOT REMOVE THIS LINE ProxyRequests Off @@ -6,7 +6,7 @@ ProxyRequests Off SSLOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate SSLVerifyClient none - ProxyPassMatch ajp://localhost:$DOGTAG_PORT + ProxyPassMatch ajp://localhost:$DOGTAG_PORT $DOGTAG_AJP_SECRET ProxyPassReverse ajp://localhost:$DOGTAG_PORT @@ -14,7 +14,7 @@ ProxyRequests Off SSLOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate SSLVerifyClient none - ProxyPassMatch ajp://localhost:$DOGTAG_PORT + ProxyPassMatch ajp://localhost:$DOGTAG_PORT $DOGTAG_AJP_SECRET ProxyPassReverse ajp://localhost:$DOGTAG_PORT @@ -22,7 +22,7 @@ ProxyRequests Off SSLOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate SSLVerifyClient require - ProxyPassMatch ajp://localhost:$DOGTAG_PORT + ProxyPassMatch ajp://localhost:$DOGTAG_PORT $DOGTAG_AJP_SECRET ProxyPassReverse ajp://localhost:$DOGTAG_PORT @@ -30,7 +30,7 @@ ProxyRequests Off SSLOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate SSLVerifyClient optional - ProxyPassMatch ajp://localhost:$DOGTAG_PORT + ProxyPassMatch ajp://localhost:$DOGTAG_PORT $DOGTAG_AJP_SECRET ProxyPassReverse ajp://localhost:$DOGTAG_PORT @@ -38,7 +38,7 @@ ProxyRequests Off SSLOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate SSLVerifyClient optional - ProxyPassMatch ajp://localhost:$DOGTAG_PORT + ProxyPassMatch ajp://localhost:$DOGTAG_PORT $DOGTAG_AJP_SECRET ProxyPassReverse ajp://localhost:$DOGTAG_PORT diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index 5f0335f6f..c03c44296 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -108,6 +108,7 @@ class BasePathNamespace: PKI_TOMCAT_ALIAS_DIR = "/etc/pki/pki-tomcat/alias" PKI_TOMCAT_ALIAS_PWDFILE_TXT = "/etc/pki/pki-tomcat/alias/pwdfile.txt" PKI_TOMCAT_PASSWORD_CONF = "/etc/pki/pki-tomcat/password.conf" + PKI_TOMCAT_SERVER_XML = "/etc/pki/pki-tomcat/server.xml" ETC_REDHAT_RELEASE = "/etc/redhat-release" RESOLV_CONF = "/etc/resolv.conf" SAMBA_KEYTAB = "/etc/samba/samba.keytab" @@ -339,6 +340,7 @@ class BasePathNamespace: KRB5KDC_LOG = "/var/log/krb5kdc.log" MESSAGES = "/var/log/messages" VAR_LOG_PKI_DIR = "/var/log/pki/" + BIN_TOMCAT = "/usr/sbin/tomcat" TOMCAT_TOPLEVEL_DIR = "/var/log/pki/pki-tomcat" TOMCAT_CA_DIR = "/var/log/pki/pki-tomcat/ca" TOMCAT_CA_ARCHIVE_DIR = "/var/log/pki/pki-tomcat/ca/archive" diff --git a/ipaplatform/debian/paths.py b/ipaplatform/debian/paths.py index 764b5a281..1014c6ae3 100644 --- a/ipaplatform/debian/paths.py +++ b/ipaplatform/debian/paths.py @@ -59,6 +59,7 @@ class DebianPathNamespace(BasePathNamespace): SYSCONFIG_PKI = "/etc/dogtag/" SYSCONFIG_PKI_TOMCAT = "/etc/default/pki-tomcat" SYSCONFIG_PKI_TOMCAT_PKI_TOMCAT_DIR = "/etc/dogtag/tomcat/pki-tomcat" + BIN_TOMCAT = "/usr/share/tomcat9/bin/version.sh" SYSTEMD_SYSTEM_HTTPD_D_DIR = "/etc/systemd/system/apache2.service.d/" SYSTEMD_SYSTEM_HTTPD_IPA_CONF = "/etc/systemd/system/apache2.service.d/ipa.conf" DNSSEC_TRUSTED_KEY = "/etc/bind/trusted-key.key" diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index fe63229af..2836bdd25 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -401,6 +401,7 @@ class CAInstance(DogtagInstance): self.step("configuring certificate server instance", self.__spawn_instance) self.step("Add ipa-pki-wait-running", self.add_ipa_wait) + self.step("secure AJP connector", self.secure_ajp_connector) self.step("reindex attributes", self.reindex_task) self.step("exporting Dogtag certificate store pin", self.create_certstore_passwdfile) @@ -452,6 +453,7 @@ class CAInstance(DogtagInstance): self.step("configure certificate renewals", self.configure_renewal) self.step("Configure HTTP to proxy connections", self.http_proxy) + # This restart is needed for ACL reload in CA, do not remove it self.step("restarting certificate server", self.restart_instance) self.step("updating IPA configuration", update_ipa_conf) self.step("enabling CA instance", self.__enable_instance) diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py index 18a24f02f..efcf81509 100644 --- a/ipaserver/install/dogtaginstance.py +++ b/ipaserver/install/dogtaginstance.py @@ -28,6 +28,9 @@ import os import shutil import traceback import dbus +import re +import pwd +import lxml.etree from configparser import DEFAULTSECT, ConfigParser, RawConfigParser @@ -42,6 +45,7 @@ from ipalib.constants import CA_DBUS_TIMEOUT, IPA_CA_RECORD, RENEWAL_CA_NAME from ipaplatform import services from ipaplatform.constants import constants from ipaplatform.paths import paths +from ipaplatform.tasks import tasks from ipapython import directivesetter from ipapython import ipaldap from ipapython import ipautil @@ -158,6 +162,7 @@ class DogtagInstance(service.Service): self.pki_config_override = None self.ca_subject = None self.subject_base = None + self.ajp_secret = None def is_installed(self): """ @@ -275,6 +280,72 @@ class DogtagInstance(service.Service): logger.critical("failed to uninstall %s instance %s", self.subsystem, e) + def __is_newer_tomcat_version(self, default=None): + try: + result = ipautil.run([paths.BIN_TOMCAT, "version"], + capture_output=True) + sn = re.search( + r'Server number:\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', + result.output) + if sn is None: + logger.info("tomcat version cannot be parsed, " + "default to pre-%s", default) + return False + v = tasks.parse_ipa_version(sn.group(1)) + if v >= tasks.parse_ipa_version(default): + return True + except ipautil.CalledProcessError as e: + logger.info( + "failed to discover tomcat version, " + "default to pre-%s, error: %s", + default, str(e)) + return False + + def secure_ajp_connector(self): + """ Update AJP connector to use a password protection """ + + server_xml = lxml.etree.parse(paths.PKI_TOMCAT_SERVER_XML) + doc = server_xml.getroot() + + # no AJP connector means no need to update anything + connectors = doc.xpath('//Connector[@port="8009"]') + if len(connectors) == 0: + return + + # AJP connector is set on port 8009. Use non-greedy search to find it + connector = connectors[0] + + # Detect tomcat version and choose the right option name + # pre-9.0.31.0 uses 'requiredSecret' + # 9.0.31.0 or later uses 'secret' + secretattr = 'requiredSecret' + oldattr = 'requiredSecret' + if self.__is_newer_tomcat_version('9.0.31.0'): + secretattr = 'secret' + + rewrite = True + if secretattr in connector.attrib: + # secret is already in place + # Perhaps, we need to synchronize it with Apache configuration + self.ajp_secret = connector.attrib[secretattr] + rewrite = False + else: + if oldattr in connector.attrib: + self.ajp_secret = connector.attrib[oldattr] + connector.attrib[secretattr] = self.ajp_secret + del connector.attrib[oldattr] + else: + # Generate password, don't use special chars to not break XML + self.ajp_secret = ipautil.ipa_generate_password(special=None) + connector.attrib[secretattr] = self.ajp_secret + + if rewrite: + pent = pwd.getpwnam(constants.PKI_USER) + with open(paths.PKI_TOMCAT_SERVER_XML, "wb") as fd: + server_xml.write(fd, pretty_print=True, encoding="utf-8") + os.fchmod(fd.fileno(), 0o660) + os.fchown(fd.fileno(), pent.pw_uid, pent.pw_gid) + def http_proxy(self): """ Update the http proxy file """ template_filename = ( @@ -284,11 +355,20 @@ class DogtagInstance(service.Service): DOGTAG_PORT=8009, CLONE='' if self.clone else '#', FQDN=self.fqdn, + DOGTAG_AJP_SECRET='', ) + if self.ajp_secret: + sub_dict['DOGTAG_AJP_SECRET'] = "secret={}".format(self.ajp_secret) template = ipautil.template_file(template_filename, sub_dict) with open(paths.HTTPD_IPA_PKI_PROXY_CONF, "w") as fd: fd.write(template) os.fchmod(fd.fileno(), 0o640) + # Restart httpd + http_service = services.knownservices.httpd + logger.debug("Restarting %s to apply AJP changes", + http_service.service_name) + http_service.restart() + logger.debug("%s successfully restarted", http_service.service_name) def configure_certmonger_renewal_helpers(self): """ diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py index 09efdcad9..99a53861e 100644 --- a/ipaserver/install/krainstance.py +++ b/ipaserver/install/krainstance.py @@ -133,8 +133,6 @@ class KRAInstance(DogtagInstance): self.step("configure certmonger for renewals", self.configure_certmonger_renewal_helpers) self.step("configure certificate renewals", self.configure_renewal) - self.step("configure HTTP to proxy connections", - self.http_proxy) if not self.clone: self.step("add vault container", self.__add_vault_container) self.step("apply LDAP updates", self.__apply_updates) diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py index 503e271da..b4ef31199 100644 --- a/ipaserver/install/server/upgrade.py +++ b/ipaserver/install/server/upgrade.py @@ -1966,6 +1966,14 @@ def upgrade_configuration(): os.path.join(paths.USR_SHARE_IPA_DIR, "ipa-kdc-proxy.conf.template")) if ca.is_configured(): + # Handle upgrade of AJP connector configuration + ca.secure_ajp_connector() + if ca.ajp_secret: + sub_dict['DOGTAG_AJP_SECRET'] = "secret={}".format( + ca.ajp_secret) + else: + sub_dict['DOGTAG_AJP_SECRET'] = '' + upgrade_file( sub_dict, paths.HTTPD_IPA_PKI_PROXY_CONF,