diff options
author | Martin Basti <mbasti@redhat.com> | 2015-05-13 14:45:32 +0200 |
---|---|---|
committer | Tomas Babej <tbabej@redhat.com> | 2015-07-07 08:37:15 +0200 |
commit | e151492560db25fa13c2a3edf5e2139dc6629047 (patch) | |
tree | 1cfb5a1a48dd522e265d425695122858a9366288 /ipaserver/install/dns.py | |
parent | b258bcee8337063259aa38b4387b9bb5721fb380 (diff) | |
download | freeipa-e151492560db25fa13c2a3edf5e2139dc6629047.tar.gz freeipa-e151492560db25fa13c2a3edf5e2139dc6629047.tar.xz freeipa-e151492560db25fa13c2a3edf5e2139dc6629047.zip |
DNSSEC: allow to disable/replace DNSSEC key master
This commit allows to replace or disable DNSSEC key master
Replacing DNSSEC master requires to copy kasp.db file manually by user
ipa-dns-install:
--disable-dnssec-master DNSSEC master will be disabled
--dnssec-master --kasp-db=FILE This configure new DNSSEC master server, kasp.db from old server is required for sucessful replacement
--force Skip checks
https://fedorahosted.org/freeipa/ticket/4657
Reviewed-By: Petr Spacek <pspacek@redhat.com>
Diffstat (limited to 'ipaserver/install/dns.py')
-rw-r--r-- | ipaserver/install/dns.py | 154 |
1 files changed, 146 insertions, 8 deletions
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py index 8d9570d68..1382382b5 100644 --- a/ipaserver/install/dns.py +++ b/ipaserver/install/dns.py @@ -4,10 +4,15 @@ import sys +from subprocess import CalledProcessError + from ipalib import api +from ipalib import errors from ipaplatform.paths import paths +from ipaplatform import services from ipapython import ipautil from ipapython import sysrestore +from ipapython.dn import DN from ipapython.ipa_log_manager import root_logger from ipapython.ipaldap import AUTOBIND_ENABLED from ipapython.ipautil import user_input @@ -23,6 +28,67 @@ ip_addresses = [] dns_forwarders = [] reverse_zones = [] +NEW_MASTER_MARK = 'NEW_DNSSEC_MASTER' + + +def _find_dnssec_enabled_zones(conn): + search_kw = {'idnssecinlinesigning': True} + dnssec_enabled_filter = conn.make_filter(search_kw) + dn = DN('cn=dns', api.env.basedn) + try: + entries, truncated = conn.find_entries( + base_dn=dn, filter=dnssec_enabled_filter, attrs_list=['idnsname']) + except errors.NotFound: + return [] + else: + return [entry.single_value['idnsname'] for entry in entries + if 'idnsname' in entry] + + +def _is_master(): + # test if server is DNSSEC key master + masters = opendnssecinstance.get_dnssec_key_masters(api.Backend.ldap2) + if api.env.host not in masters: + raise RuntimeError("Current server is not DNSSEC key master") + + +def _disable_dnssec(): + fstore = sysrestore.FileStore(paths.SYSRESTORE) + + ods = opendnssecinstance.OpenDNSSECInstance( + fstore, ldapi=True, autobind=AUTOBIND_ENABLED) + ods.realm = api.env.realm + + ods_exporter = odsexporterinstance.ODSExporterInstance(fstore, ldapi=True) + ods_exporter.realm = api.env.realm + + # unconfigure services first + ods.uninstall() # needs keytab to flush the latest ods database + ods_exporter.uninstall() + + ods.ldap_connect() + ods.ldap_disable('DNSSEC', api.env.host, api.env.basedn) + + ods_exporter.ldap_connect() + ods_exporter.ldap_disable('DNSKeyExporter', api.env.host, api.env.basedn) + ods_exporter.remove_service() + + ods.ldap_disconnect() + ods_exporter.ldap_disconnect() + + conn = api.Backend.ldap2 + dn = DN(('cn', 'DNSSEC'), ('cn', api.env.host), ('cn', 'masters'), + ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) + try: + entry = conn.get_entry(dn) + except errors.NotFound: + pass + else: + ipa_config = entry.get('ipaConfigString', []) + if opendnssecinstance.KEYMASTER in ipa_config: + ipa_config.remove(opendnssecinstance.KEYMASTER) + conn.update_entry(entry) + def install_check(standalone, replica, options, hostname): global ip_addresses @@ -41,14 +107,22 @@ def install_check(standalone, replica, options, hostname): print " * Configure ipa-ods-exporter (required by DNSSEC key master)" print " * Configure OpenDNSSEC (required by DNSSEC key master)" print " * Generate DNSSEC master key (required by DNSSEC key master)" + elif options.disable_dnssec_master: + print " * Unconfigure ipa-ods-exporter" + print " * Unconfigure OpenDNSSEC" + print "" + print "No new zones will be signed without DNSSEC key master IPA server." + print "" + print ("Please copy file from %s after uninstallation. This file is needed " + "on new DNSSEC key " % paths.IPA_KASP_DB_BACKUP) + print "master server" print "" print "NOTE: DNSSEC zone signing is not enabled by default" print "" if options.dnssec_master: print "DNSSEC support is experimental!" print "" - print "Plan carefully, current version doesn't allow you to move DNSSEC" - print "key master to different server and master cannot be uninstalled" + print "Plan carefully, replacing DNSSEC key master is not recommended" print "" print "" print "To accept the default shown in brackets, press the Enter key." @@ -59,22 +133,79 @@ def install_check(standalone, replica, options, hostname): "Do you want to setup this IPA server as DNSSEC key master?", False)): sys.exit("Aborted") + elif (options.disable_dnssec_master and not options.unattended and not + ipautil.user_input( + "Do you want to disable current DNSSEC key master?", + False)): + sys.exit("Aborted") # Check bind packages are installed if not (bindinstance.check_inst(options.unattended) and dnskeysyncinstance.check_inst()): sys.exit("Aborting installation.") - if options.dnssec_master: + if options.disable_dnssec_master: + _is_master() + + if options.disable_dnssec_master or options.dnssec_master: + dnssec_zones = _find_dnssec_enabled_zones(api.Backend.ldap2) + + if options.disable_dnssec_master: + if dnssec_zones and not options.force: + raise RuntimeError( + "Cannot disable DNSSEC key master, DNSSEC signing is still " + "enabled for following zone(s): %s\n" + "Use --force option to skip this check." % + ", ".join([str(zone) for zone in dnssec_zones])) + elif options.dnssec_master: # check opendnssec packages are installed if not opendnssecinstance.check_inst(): sys.exit("Aborting installation") + if options.kasp_db_file: + dnskeysyncd = services.service('ipa-dnskeysyncd') + + if not dnskeysyncd.is_installed(): + raise RuntimeError("ipa-dnskeysyncd is not configured on this " + "server, you cannot reuse OpenDNSSEC " + "database (kasp.db file)") + + # check if replica can be the DNSSEC master + named = services.knownservices.named + ods_enforcerd = services.knownservices.ods_enforcerd + cmd = [paths.IPA_DNSKEYSYNCD_REPLICA] + environment = { + "SOFTHSM2_CONF": paths.DNSSEC_SOFTHSM2_CONF, + } + + # stop dnskeysyncd before test + dnskeysyncd_running = dnskeysyncd.is_running() + dnskeysyncd.stop() + try: + ipautil.run(cmd, env=environment, + runas=ods_enforcerd.get_user_name(), + suplementary_groups=[named.get_group_name()]) + except CalledProcessError as e: + root_logger.debug("%s", e) + raise RuntimeError("IPA server cannot be the new DNSSEC master " + "(some keys are missing)") + finally: + if dnskeysyncd_running: + dnskeysyncd.start() + elif dnssec_zones and not options.force: + # some zones have --dnssec=true, make sure a user really want to + # install new database + raise RuntimeError( + "DNSSEC is enabled for following zone(s): %s\n" + "Please use option --kasp-db to keep current OpenDNSSEC " + "database or use --force option to skip this check." % + ", ".join([str(zone) for zone in dnssec_zones])) + fstore = sysrestore.FileStore(paths.SYSRESTORE) if options.dnssec_master: ods = opendnssecinstance.OpenDNSSECInstance( - fstore, ldapi=True, autobind=AUTOBIND_ENABLED) + fstore, ldapi=True) ods.realm = api.env.realm dnssec_masters = ods.get_masters() # we can reinstall current server if it is dnssec master @@ -126,6 +257,11 @@ def install(standalone, replica, options): global dns_forwarders global reverse_zones + local_dnskeysyncd_dn = DN(('cn', 'DNSKeySync'), ('cn', api.env.host), + ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), + api.env.basedn) + conn = api.Backend.ldap2 + fstore = sysrestore.FileStore(paths.SYSRESTORE) conf_ntp = ntpinstance.NTPInstance(fstore).is_enabled() @@ -149,13 +285,15 @@ def install(standalone, replica, options): dnskeysyncd = dnskeysyncinstance.DNSKeySyncInstance(fstore, ldapi=True) dnskeysyncd.create_instance(api.env.host, api.env.realm) if options.dnssec_master: - ods = opendnssecinstance.OpenDNSSECInstance(fstore, ldapi=True, - autobind=AUTOBIND_ENABLED) + ods = opendnssecinstance.OpenDNSSECInstance(fstore, ldapi=True) ods_exporter = odsexporterinstance.ODSExporterInstance( - fstore, ldapi=True, autobind=AUTOBIND_ENABLED) + fstore, ldapi=True) ods_exporter.create_instance(api.env.host, api.env.realm) - ods.create_instance(api.env.host, api.env.realm) + ods.create_instance(api.env.host, api.env.realm, + kasp_db_file=options.kasp_db_file) + elif options.disable_dnssec_master: + _disable_dnssec() dnskeysyncd.start_dnskeysyncd() bind.start_named() |