summaryrefslogtreecommitdiffstats
path: root/ipaserver/install/dns.py
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2015-05-13 14:45:32 +0200
committerTomas Babej <tbabej@redhat.com>2015-07-07 08:37:15 +0200
commite151492560db25fa13c2a3edf5e2139dc6629047 (patch)
tree1cfb5a1a48dd522e265d425695122858a9366288 /ipaserver/install/dns.py
parentb258bcee8337063259aa38b4387b9bb5721fb380 (diff)
downloadfreeipa-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.py154
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()