--- a/daemons/dnssec/ipa-dnskeysync-replica.in +++ b/daemons/dnssec/ipa-dnskeysync-replica.in @@ -145,7 +145,7 @@ def ldap2replica_zone_keys_sync(ldapkeyd # IPA framework initialization -standard_logging_setup(verbose=True, debug=True) +standard_logging_setup(debug=True) ipalib.api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True) ipalib.api.finalize() --- a/daemons/dnssec/ipa-dnskeysyncd.in +++ b/daemons/dnssec/ipa-dnskeysyncd.in @@ -23,12 +23,9 @@ logger = logging.getLogger(os.path.basen # IPA framework initialization -standard_logging_setup(verbose=True) +standard_logging_setup(debug=True) api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True) api.finalize() -if api.env.debug: - root_logger = logging.getLogger() - root_logger.setLevel(logging.DEBUG) # Global state watcher_running = True --- a/daemons/dnssec/ipa-ods-exporter.in +++ b/daemons/dnssec/ipa-ods-exporter.in @@ -29,12 +29,12 @@ import dns.dnssec from gssapi.exceptions import GSSError import six import systemd.daemon -import systemd.journal import ipalib from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL from ipalib.install.kinit import kinit_keytab from ipapython.dn import DN +from ipapython.ipa_log_manager import standard_logging_setup from ipapython import ipaldap from ipaplatform.paths import paths from ipaserver.dnssec.abshsm import sync_pkcs11_metadata, wrappingmech_name2id @@ -650,20 +650,8 @@ def cleanup_ldap_zone(ldap, dns_dn, zone ldap.delete_entry(ldap_key) -# this service is usually socket-activated -root_logger = logging.getLogger() -root_logger.addHandler(systemd.journal.JournalHandler()) -root_logger.setLevel(level=logging.DEBUG) - -if len(sys.argv) > 2: - print(__doc__) - sys.exit(1) -# program was likely invoked from console, log to it -elif len(sys.argv) == 2: - console = logging.StreamHandler() - root_logger.addHandler(console) - # IPA framework initialization +standard_logging_setup(debug=True) ipalib.api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True) ipalib.api.finalize() --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -99,6 +99,15 @@ %global httpd_version 2.4.41-6.1 %endif +# BIND employs 'pkcs11' OpenSSL engine instead of native PKCS11 +%if 0%{?fedora} >= 31 + %global with_bind_pkcs11 0 + %global openssl_pkcs11_version 0.4.10-6 + %global softhsm_version 2.5.0-4 +%else + %global with_bind_pkcs11 1 +%endif + # Don't use Fedora's Python dependency generator on Fedora 30/rawhide yet. # Some packages don't provide new dist aliases. # https://docs.fedoraproject.org/en-US/packaging-guidelines/Python/ @@ -463,8 +472,13 @@ Requires: %{name}-server = %{version}-%{ Requires: bind-dyndb-ldap >= 11.0-2 Requires: bind >= 9.11.0-6.P2 Requires: bind-utils >= 9.11.0-6.P2 +%if 0%{?with_bind_pkcs11} Requires: bind-pkcs11 >= 9.11.0-6.P2 Requires: bind-pkcs11-utils >= 9.11.0-6.P2 +%else +Requires: softhsm >= %{softhsm_version} +Requires: openssl-pkcs11 >= %{openssl_pkcs11_version} +%endif %if 0%{?fedora} >= 32 # See https://bugzilla.redhat.com/show_bug.cgi?id=1825812 Requires: opendnssec >= 2.1.6-5 --- a/install/share/Makefile.am +++ b/install/share/Makefile.am @@ -48,6 +48,8 @@ dist_app_DATA = \ bind.ipa-ext.conf.template \ bind.ipa-options-ext.conf.template \ bind.named.conf.template \ + bind.openssl.cnf.template \ + bind.openssl.cryptopolicy.cnf.template \ certmap.conf.template \ kdc.conf.template \ kdc_extensions.template \ --- /dev/null +++ b/install/share/bind.openssl.cnf.template @@ -0,0 +1,14 @@ +# OpenSSL configuration file +# File generated by IPA instalation +openssl_conf = openssl_init + +[openssl_init] +engines = engine_section + +[engine_section] +$OPENSSL_ENGINE = ${OPENSSL_ENGINE}_section + +[${OPENSSL_ENGINE}_section] +engine_id = $OPENSSL_ENGINE +MODULE_PATH = $SOFTHSM_MODULE +init=0 --- /dev/null +++ b/install/share/bind.openssl.cryptopolicy.cnf.template @@ -0,0 +1,21 @@ +# OpenSSL configuration file +# File generated by IPA instalation +openssl_conf = openssl_init + +[openssl_init] +ssl_conf = ssl_configuration +engines = engine_section + +[ssl_configuration] +system_default = crypto_policy + +[crypto_policy] +.include $CRYPTO_POLICY_FILE + +[engine_section] +$OPENSSL_ENGINE = ${OPENSSL_ENGINE}_section + +[${OPENSSL_ENGINE}_section] +engine_id = $OPENSSL_ENGINE +MODULE_PATH = $SOFTHSM_MODULE +init=0 --- a/ipaplatform/base/constants.py +++ b/ipaplatform/base/constants.py @@ -23,6 +23,8 @@ class BaseConstantsNamespace: NAMED_USER = "named" NAMED_GROUP = "named" NAMED_DATA_DIR = "data/" + NAMED_OPTIONS_VAR = "OPTIONS" + NAMED_OPENSSL_ENGINE = None NAMED_ZONE_COMMENT = "" PKI_USER = 'pkiuser' PKI_GROUP = 'pkiuser' --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -26,6 +26,7 @@ import os class BasePathNamespace: BIN_HOSTNAMECTL = "/bin/hostnamectl" + CRYPTO_POLICY_OPENSSLCNF_FILE = None ECHO = "/bin/echo" FIPS_MODE_SETUP = "/usr/bin/fips-mode-setup" GZIP = "/bin/gzip" @@ -69,6 +70,7 @@ class BasePathNamespace: IPA_DEFAULT_CONF = "/etc/ipa/default.conf" IPA_DNSKEYSYNCD_KEYTAB = "/etc/ipa/dnssec/ipa-dnskeysyncd.keytab" IPA_ODS_EXPORTER_KEYTAB = "/etc/ipa/dnssec/ipa-ods-exporter.keytab" + DNSSEC_OPENSSL_CONF = None DNSSEC_SOFTHSM2_CONF = "/etc/ipa/dnssec/softhsm2.conf" DNSSEC_SOFTHSM_PIN_SO = "/etc/ipa/dnssec/softhsm_pin_so" IPA_NSSDB_DIR = "/etc/ipa/nssdb" @@ -253,8 +255,6 @@ class BasePathNamespace: IPA_REPLICA_CONNCHECK = "/usr/sbin/ipa-replica-conncheck" IPA_RMKEYTAB = "/usr/sbin/ipa-rmkeytab" IPACTL = "/usr/sbin/ipactl" - NAMED = "/usr/sbin/named" - NAMED_PKCS11 = "/usr/sbin/named-pkcs11" CHRONYC = "/usr/bin/chronyc" CHRONYD = "/usr/sbin/chronyd" PKIDESTROY = "/usr/sbin/pkidestroy" --- a/ipaplatform/fedora/constants.py +++ b/ipaplatform/fedora/constants.py @@ -27,4 +27,6 @@ class FedoraConstantsNamespace(RedHatCon if HAS_NFS_CONF: SECURE_NFS_VAR = None + NAMED_OPENSSL_ENGINE = "pkcs11" + constants = FedoraConstantsNamespace() --- a/ipaplatform/fedora/paths.py +++ b/ipaplatform/fedora/paths.py @@ -36,6 +36,8 @@ class FedoraPathNamespace(RedHatPathName NAMED_CRYPTO_POLICY_FILE = "/etc/crypto-policies/back-ends/bind.config" if HAS_NFS_CONF: SYSCONFIG_NFS = '/etc/nfs.conf' + DNSSEC_OPENSSL_CONF = "/etc/ipa/dnssec/openssl.cnf" + DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel" paths = FedoraPathNamespace() --- a/ipaplatform/fedora/services.py +++ b/ipaplatform/fedora/services.py @@ -29,6 +29,8 @@ from ipaplatform.redhat import services # Mappings from service names as FreeIPA code references to these services # to their actual systemd service names fedora_system_units = redhat_services.redhat_system_units.copy() +fedora_system_units['named'] = fedora_system_units['named-regular'] +fedora_system_units['named-conflict'] = fedora_system_units['named-pkcs11'] # Service classes that implement Fedora-specific behaviour @@ -41,6 +43,8 @@ class FedoraService(redhat_services.RedH # of specified name def fedora_service_class_factory(name, api=None): + if name in ['named', 'named-conflict']: + return FedoraService(name, api) return redhat_services.redhat_service_class_factory(name, api) --- a/ipaplatform/redhat/paths.py +++ b/ipaplatform/redhat/paths.py @@ -31,6 +31,9 @@ from ipaplatform.base.paths import BaseP class RedHatPathNamespace(BasePathNamespace): + CRYPTO_POLICY_OPENSSLCNF_FILE = ( + '/etc/crypto-policies/back-ends/opensslcnf.config' + ) # https://docs.python.org/2/library/platform.html#cross-platform if sys.maxsize > 2**32: LIBSOFTHSM2_SO = BasePathNamespace.LIBSOFTHSM2_SO_64 --- a/ipaplatform/redhat/services.py +++ b/ipaplatform/redhat/services.py @@ -68,6 +68,7 @@ redhat_system_units['ipa-dnskeysyncd'] = redhat_system_units['named-regular'] = 'named.service' redhat_system_units['named-pkcs11'] = 'named-pkcs11.service' redhat_system_units['named'] = redhat_system_units['named-pkcs11'] +redhat_system_units['named-conflict'] = redhat_system_units['named-regular'] redhat_system_units['ods-enforcerd'] = 'ods-enforcerd.service' redhat_system_units['ods_enforcerd'] = redhat_system_units['ods-enforcerd'] redhat_system_units['ods-signerd'] = 'ods-signerd.service' --- a/ipaserver/dnssec/bindmgr.py +++ b/ipaserver/dnssec/bindmgr.py @@ -16,11 +16,14 @@ import stat import six import ipalib.constants + from ipapython.dn import DN from ipapython import ipautil +from ipaplatform.constants import constants as platformconstants from ipaplatform.paths import paths from ipaserver.dnssec.temp import TemporaryDirectory +from ipaserver.install import installutils logger = logging.getLogger(__name__) @@ -133,8 +136,11 @@ class BINDMgr: cmd.extend(['-f', 'KSK']) if attrs.get('idnsSecKeyRevoke', [b'FALSE'])[0].upper() == b'TRUE': cmd.extend(['-R', datetime.now().strftime(time_bindfmt)]) + if platformconstants.NAMED_OPENSSL_ENGINE is not None: + cmd.extend(['-E', platformconstants.NAMED_OPENSSL_ENGINE]) cmd.append(zone.to_text()) + installutils.check_entropy() # keys has to be readable by ODS & named result = ipautil.run(cmd, capture_output=True) basename = result.output.strip() --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -663,7 +663,7 @@ class BindInstance(service.Service): self.no_dnssec_validation = False self.sub_dict = None self.reverse_zones = () - self.named_regular = services.service('named-regular', api) + self.named_conflict = services.service('named-conflict', api) suffix = ipautil.dn_attribute_property('_suffix') @@ -770,7 +770,7 @@ class BindInstance(service.Service): # named has to be started after softhsm initialization # self.step("restarting named", self.__start) - self.step("configuring named to start on boot", self.__enable) + self.step("configuring named to start on boot", self.switch_service) self.step( "changing resolv.conf to point to ourselves", self.setup_resolv_conf @@ -783,19 +783,16 @@ class BindInstance(service.Service): def __start(self): try: - if self.get_state("running") is None: - # first time store status - self.backup_state("running", self.is_running()) self.restart() except Exception as e: logger.error("Named service failed to start (%s)", e) print("named service failed to start") + def switch_service(self): + self.mask_conflict() + self.__enable() + def __enable(self): - if self.get_state("enabled") is None: - self.backup_state("enabled", self.is_running()) - self.backup_state("named-regular-enabled", - self.named_regular.is_running()) # We do not let the system start IPA components on its own, # Instead we reply on the IPA init script to start only enabled # components as found in our LDAP configuration tree @@ -806,20 +803,19 @@ class BindInstance(service.Service): # don't crash, just report error logger.error("DNS service already exists") - # disable named, we need to run named-pkcs11 only - if self.get_state("named-regular-running") is None: - # first time store status - self.backup_state("named-regular-running", - self.named_regular.is_running()) + def mask_conflict(self): + # disable named-conflict (either named or named-pkcs11) try: - self.named_regular.stop() + self.named_conflict.stop() except Exception as e: - logger.debug("Unable to stop named (%s)", e) + logger.debug("Unable to stop %s (%s)", + self.named_conflict.systemd_name, e) try: - self.named_regular.mask() + self.named_conflict.mask() except Exception as e: - logger.debug("Unable to mask named (%s)", e) + logger.debug("Unable to mask %s (%s)", + self.named_conflict.systemd_name, e) def _get_dnssec_validation(self): """get dnssec-validation value @@ -1318,11 +1314,6 @@ class BindInstance(service.Service): if self.is_configured(): self.print_msg("Unconfiguring %s" % self.service_name) - running = self.restore_state("running") - enabled = self.restore_state("enabled") - named_regular_running = self.restore_state("named-regular-running") - named_regular_enabled = self.restore_state("named-regular-enabled") - self.dns_backup.clear_records(self.api.Backend.ldap2.isconnected()) try: @@ -1337,23 +1328,10 @@ class BindInstance(service.Service): ipautil.rmtree(paths.BIND_LDAP_DNS_IPA_WORKDIR) - # disabled by default, by ldap_configure() - if enabled: - self.enable() - else: - self.disable() - - if running: - self.restart() - else: - self.stop() - - self.named_regular.unmask() - if named_regular_enabled: - self.named_regular.enable() + self.disable() + self.stop() - if named_regular_running: - self.named_regular.start() + self.named_conflict.unmask() ipautil.remove_file(paths.NAMED_CONF_BAK) ipautil.remove_file(paths.NAMED_CUSTOM_CONF) --- a/ipaserver/install/dnskeysyncinstance.py +++ b/ipaserver/install/dnskeysyncinstance.py @@ -4,11 +4,12 @@ from __future__ import print_function, absolute_import -import logging import errno +import grp +import logging import os import pwd -import grp +import re import shutil import stat @@ -56,10 +57,10 @@ class DNSKeySyncInstance(service.Service keytab=paths.IPA_DNSKEYSYNCD_KEYTAB ) self.extra_config = [u'dnssecVersion 1', ] # DNSSEC enabled - self.named_uid = None - self.named_gid = None - self.ods_uid = None - self.ods_gid = None + self.named_uid = self.__get_named_uid() + self.named_gid = self.__get_named_gid() + self.ods_uid = self.__get_ods_uid() + self.ods_gid = self.__get_ods_gid() suffix = ipautil.dn_attribute_property('_suffix') @@ -67,12 +68,6 @@ class DNSKeySyncInstance(service.Service """ Setting up correct permissions to allow write/read access for daemons """ - if self.named_uid is None: - self.named_uid = self.__get_named_uid() - - if self.named_gid is None: - self.named_gid = self.__get_named_gid() - if not os.path.exists(paths.BIND_LDAP_DNS_IPA_WORKDIR): os.mkdir(paths.BIND_LDAP_DNS_IPA_WORKDIR, 0o770) # dnssec daemons require to have access into the directory @@ -133,20 +128,19 @@ class DNSKeySyncInstance(service.Service except KeyError: raise RuntimeError("Named GID not found") - def __check_dnssec_status(self): - self.named_uid = self.__get_named_uid() - self.named_gid = self.__get_named_gid() - + def __get_ods_uid(self): try: - self.ods_uid = pwd.getpwnam(constants.ODS_USER).pw_uid + return pwd.getpwnam(constants.ODS_USER).pw_uid except KeyError: raise RuntimeError("OpenDNSSEC UID not found") + def __get_ods_gid(self): try: - self.ods_gid = grp.getgrnam(constants.ODS_GROUP).gr_gid + return grp.getgrnam(constants.ODS_GROUP).gr_gid except KeyError: raise RuntimeError("OpenDNSSEC GID not found") + def __check_dnssec_status(self): if not dns_container_exists(self.suffix): raise RuntimeError("DNS container does not exist") @@ -164,10 +158,94 @@ class DNSKeySyncInstance(service.Service self._ldap_mod("dnssec.ldif", {'SUFFIX': self.suffix, }) - def __setup_softhsm(self): - assert self.ods_uid is not None - assert self.named_gid is not None + def _are_named_options_configured(self, options): + """Check whether the sysconfig of named is patched + Additional command line options for named are passed + via OPTIONS env variable. Since custom options can be + supplied by a vendor, at least, the base parsing of such + is required. + Current named command line options: + NS_MAIN_ARGS "46A:c:C:d:D:E:fFgi:lL:M:m:n:N:p:P:sS:t:T:U:u:vVx:X:" + If there are several same options the last passed wins. + """ + if options: + pattern = r"[ ]*-[a-zA-Z46]*E[ ]*(.*?)(?: |$)" + engines = re.findall(pattern, options) + if engines and engines[-1] == constants.NAMED_OPENSSL_ENGINE: + return True + + return False + + def setup_named_openssl_conf(self): + if constants.NAMED_OPENSSL_ENGINE is not None: + logger.debug("Setup OpenSSL config for BIND") + # setup OpenSSL config for BIND, + # this one is needed because FreeIPA installation + # disables p11-kit-proxy PKCS11 module + conf_file_dict = { + 'OPENSSL_ENGINE': constants.NAMED_OPENSSL_ENGINE, + 'SOFTHSM_MODULE': paths.LIBSOFTHSM2_SO, + 'CRYPTO_POLICY_FILE': paths.CRYPTO_POLICY_OPENSSLCNF_FILE, + } + if paths.CRYPTO_POLICY_OPENSSLCNF_FILE is None: + opensslcnf_tmpl = "bind.openssl.cnf.template" + else: + opensslcnf_tmpl = "bind.openssl.cryptopolicy.cnf.template" + + named_openssl_txt = ipautil.template_file( + os.path.join(paths.USR_SHARE_IPA_DIR, opensslcnf_tmpl), + conf_file_dict + ) + with open(paths.DNSSEC_OPENSSL_CONF, 'w') as f: + os.fchmod(f.fileno(), 0o640) + os.fchown(f.fileno(), 0, self.named_gid) + f.write(named_openssl_txt) + + def setup_named_sysconfig(self): + logger.debug("Setup BIND sysconfig") + sysconfig = paths.SYSCONFIG_NAMED + self.fstore.backup_file(sysconfig) + + directivesetter.set_directive( + sysconfig, + 'SOFTHSM2_CONF', paths.DNSSEC_SOFTHSM2_CONF, + quotes=False, separator='=') + + if constants.NAMED_OPENSSL_ENGINE is not None: + directivesetter.set_directive( + sysconfig, + 'OPENSSL_CONF', paths.DNSSEC_OPENSSL_CONF, + quotes=False, separator='=') + + options = directivesetter.get_directive( + paths.SYSCONFIG_NAMED, + constants.NAMED_OPTIONS_VAR, + separator="=" + ) or '' + if not self._are_named_options_configured(options): + engine_cmd = "-E {}".format(constants.NAMED_OPENSSL_ENGINE) + new_options = ' '.join([options, engine_cmd]) + directivesetter.set_directive( + sysconfig, + constants.NAMED_OPTIONS_VAR, new_options, + quotes=True, separator='=') + + def setup_ipa_dnskeysyncd_sysconfig(self): + logger.debug("Setup ipa-dnskeysyncd sysconfig") + sysconfig = paths.SYSCONFIG_IPA_DNSKEYSYNCD + directivesetter.set_directive( + sysconfig, + 'SOFTHSM2_CONF', paths.DNSSEC_SOFTHSM2_CONF, + quotes=False, separator='=') + + if constants.NAMED_OPENSSL_ENGINE is not None: + directivesetter.set_directive( + sysconfig, + 'OPENSSL_CONF', paths.DNSSEC_OPENSSL_CONF, + quotes=False, separator='=') + + def __setup_softhsm(self): token_dir_exists = os.path.exists(paths.DNSSEC_TOKENS_DIR) # create dnssec directory @@ -186,23 +264,15 @@ class DNSKeySyncInstance(service.Service 'tokens_dir': paths.DNSSEC_TOKENS_DIR } logger.debug("Creating new softhsm config file") - named_fd = open(paths.DNSSEC_SOFTHSM2_CONF, 'w') - named_fd.seek(0) - named_fd.truncate(0) - named_fd.write(softhsm_conf_txt) - named_fd.close() - os.chmod(paths.DNSSEC_SOFTHSM2_CONF, 0o644) - - # setting up named to use softhsm2 - if not self.fstore.has_file(paths.SYSCONFIG_NAMED): - self.fstore.backup_file(paths.SYSCONFIG_NAMED) - - # setting up named and ipa-dnskeysyncd to use our softhsm2 config - for sysconfig in [paths.SYSCONFIG_NAMED, - paths.SYSCONFIG_IPA_DNSKEYSYNCD]: - directivesetter.set_directive(sysconfig, 'SOFTHSM2_CONF', - paths.DNSSEC_SOFTHSM2_CONF, - quotes=False, separator='=') + with open(paths.DNSSEC_SOFTHSM2_CONF, 'w') as f: + os.fchmod(f.fileno(), 0o644) + f.write(softhsm_conf_txt) + + # setting up named and ipa-dnskeysyncd to use our softhsm2 and + # openssl configs + self.setup_named_openssl_conf() + self.setup_named_sysconfig() + self.setup_ipa_dnskeysyncd_sysconfig() if (token_dir_exists and os.path.exists(paths.DNSSEC_SOFTHSM_PIN) and os.path.exists(paths.DNSSEC_SOFTHSM_PIN_SO)): @@ -231,23 +301,17 @@ class DNSKeySyncInstance(service.Service entropy_bits=0, special=None, min_len=pin_length) logger.debug("Saving user PIN to %s", paths.DNSSEC_SOFTHSM_PIN) - named_fd = open(paths.DNSSEC_SOFTHSM_PIN, 'w') - named_fd.seek(0) - named_fd.truncate(0) - named_fd.write(pin) - named_fd.close() - os.chmod(paths.DNSSEC_SOFTHSM_PIN, 0o770) - # chown to ods:named - os.chown(paths.DNSSEC_SOFTHSM_PIN, self.ods_uid, self.named_gid) + with open(paths.DNSSEC_SOFTHSM_PIN, 'w') as f: + # chown to ods:named + os.fchown(f.fileno(), self.ods_uid, self.named_gid) + os.fchmod(f.fileno(), 0o660) + f.write(pin) logger.debug("Saving SO PIN to %s", paths.DNSSEC_SOFTHSM_PIN_SO) - named_fd = open(paths.DNSSEC_SOFTHSM_PIN_SO, 'w') - named_fd.seek(0) - named_fd.truncate(0) - named_fd.write(pin_so) - named_fd.close() - # owner must be root - os.chmod(paths.DNSSEC_SOFTHSM_PIN_SO, 0o400) + with open(paths.DNSSEC_SOFTHSM_PIN_SO, 'w') as f: + # owner must be root + os.fchmod(f.fileno(), 0o400) + f.write(pin_so) # initialize SoftHSM @@ -377,7 +441,7 @@ class DNSKeySyncInstance(service.Service os.chown(dir_path, self.ods_uid, self.named_gid) for filename in files: file_path = os.path.join(root, filename) - os.chmod(file_path, 0o770 | stat.S_ISGID) + os.chmod(file_path, 0o660 | stat.S_ISGID) # chown to ods:named os.chown(file_path, self.ods_uid, self.named_gid) @@ -389,7 +453,6 @@ class DNSKeySyncInstance(service.Service logger.error("DNSKeySync service already exists") def __setup_principal(self): - assert self.ods_gid is not None ipautil.remove_keytab(self.keytab) installutils.kadmin_addprinc(self.principal) --- a/ipaserver/install/ipa_backup.py +++ b/ipaserver/install/ipa_backup.py @@ -185,6 +185,7 @@ class Backup(admintool.AdminTool): paths.OPENDNSSEC_KASP_FILE, paths.OPENDNSSEC_ZONELIST_FILE, paths.OPENDNSSEC_KASP_DB, + paths.DNSSEC_OPENSSL_CONF, paths.DNSSEC_SOFTHSM2_CONF, paths.DNSSEC_SOFTHSM_PIN_SO, paths.IPA_ODS_EXPORTER_KEYTAB, --- a/ipaserver/install/kra.py +++ b/ipaserver/install/kra.py @@ -106,9 +106,9 @@ def install(api, replica_config, options # Restart apache for new proxy config file services.knownservices.httpd.restart(capture_output=True) - # Restarted named-pkcs11 to restore bind-dyndb-ldap operation, see + # Restarted named to restore bind-dyndb-ldap operation, see # https://pagure.io/freeipa/issue/5813 - named = services.knownservices.named # alias for named-pkcs11 + named = services.knownservices.named # alias for current named if named.is_running(): named.restart(capture_output=True) --- a/ipaserver/install/opendnssecinstance.py +++ b/ipaserver/install/opendnssecinstance.py @@ -269,7 +269,7 @@ class OpenDNSSECInstance(service.Service os.chown(dir_path, self.ods_uid, self.named_gid) # chown to ods:named for filename in files: file_path = os.path.join(root, filename) - os.chmod(file_path, 0o770 | stat.S_ISGID) + os.chmod(file_path, 0o660 | stat.S_ISGID) os.chown(file_path, self.ods_uid, self.named_gid) # chown to ods:named finally: --- a/ipaserver/install/server/upgrade.py +++ b/ipaserver/install/server/upgrade.py @@ -509,6 +509,24 @@ def ca_initialize_hsm_state(ca): ca.set_hsm_state(config) +def dnssec_set_openssl_engine(dnskeysyncd): + """ + Setup OpenSSL engine for BIND + """ + if constants.NAMED_OPENSSL_ENGINE is None: + return False + + if sysupgrade.get_upgrade_state('dns', 'openssl_engine'): + return False + + logger.info('[Set OpenSSL engine for BIND]') + dnskeysyncd.setup_named_openssl_conf() + dnskeysyncd.setup_named_sysconfig() + dnskeysyncd.setup_ipa_dnskeysyncd_sysconfig() + sysupgrade.set_upgrade_state('dns', 'openssl_engine', True) + + return True + def certificate_renewal_update(ca, kra, ds, http): """ @@ -1395,7 +1413,10 @@ def upgrade_bind(fstore): logger.info("DNS service is not configured") return False - # get rid of old upgrade states + bind_switch_service(bind) + + # get rid of old states + bind_old_states(bind) bind_old_upgrade_states() # only upgrade with drop-in is missing and /etc/resolv.conf is a link to @@ -1428,6 +1449,38 @@ def upgrade_bind(fstore): return changed +def bind_switch_service(bind): + """ + Mask either named or named-pkcs11, we need to run only one, + running both can cause unexpected errors. + """ + named_conflict_name = bind.named_conflict.systemd_name + named_conflict_old = sysupgrade.get_upgrade_state('dns', 'conflict_named') + + # nothing changed + if named_conflict_old and named_conflict_old == named_conflict_name: + return False + + bind.switch_service() + + sysupgrade.set_upgrade_state('dns', 'conflict_named', named_conflict_name) + return True + + +def bind_old_states(bind): + """Remove old states + """ + # no longer used states + old_states = [ + "enabled", + "running", + "named-regular-enabled", + "named-regular-running", + ] + for state in old_states: + bind.delete_state(state) + + def bind_old_upgrade_states(): """Remove old upgrade states """ @@ -1673,6 +1726,9 @@ def upgrade_configuration(): if not dnskeysyncd.is_configured(): dnskeysyncd.create_instance(fqdn, api.env.realm) dnskeysyncd.start_dnskeysyncd() + else: + if dnssec_set_openssl_engine(dnskeysyncd): + dnskeysyncd.start_dnskeysyncd() cleanup_kdc(fstore) cleanup_adtrust(fstore) --- a/ipaserver/install/service.py +++ b/ipaserver/install/service.py @@ -533,6 +533,9 @@ class Service: def get_state(self, key): return self.sstore.get_state(self.service_name, key) + def delete_state(self, key): + self.sstore.delete_state(self.service_name, key) + def print_msg(self, message): print_msg(message, self.output_fd) @@ -660,6 +663,7 @@ class Service: ] extra_config_opts.extend(config) + self.unmask() self.disable() set_service_entry_config( --- a/ipatests/test_integration/test_commands.py +++ b/ipatests/test_integration/test_commands.py @@ -989,7 +989,7 @@ class TestIPACommand(IntegrationTest): # get minimum version from current crypto-policy openssl_cnf = self.master.get_file_contents( - "/etc/crypto-policies/back-ends/opensslcnf.config", + paths.CRYPTO_POLICY_OPENSSLCNF_FILE, encoding="utf-8" ) mo = re.search(r"MinProtocol\s*=\s*(TLSv[0-9.]+)", openssl_cnf)