On 30/06/15 22:09, Petr Spacek wrote:
On 30.6.2015 16:04, Martin Basti wrote:
On 30/06/15 10:25, Martin Basti wrote:
On 29/06/15 15:16, Martin Basti wrote:
On 25/06/15 13:46, Petr Spacek wrote:
On 17.6.2015 13:37, Martin Basti wrote:
On 17/06/15 13:26, Petr Spacek wrote:
On 16.6.2015 15:40, Martin Basti wrote:
On 05/06/15 12:54, Petr Spacek wrote:
On 20.5.2015 18:00, Martin Basti wrote:
This patch allows to disable DNSSEC key master on IPA server, or replace
current DNSSEC key master with another IPA server.
Only for master branch.
https://fedorahosted.org/freeipa/ticket/4657
Patches attached.
NACK. This happens on DNSSEC key master:
$ ipa-dns-install --disable-dnssec-master
Do you want to disable current DNSSEC key master? [no]: yes
Unexpected error - see /var/log/ipaserver-install.log for details:
TypeError: sequence item 0: expected string, DNSName found
2015-06-05T10:52:35Z DEBUG File
"/usr/lib/python2.7/site-packages/ipaserver/install/installutils.py",
line
733, in run_script
return_value = main_function()
File "/sbin/ipa-dns-install", line 128, in main
dns_installer.disable_dnssec_master(options.unattended)
File "/usr/lib/python2.7/site-packages/ipaserver/install/dns.py",
line
112,
in disable_dnssec_master
", ".join(dnssec_zones))
2015-06-05T10:52:35Z DEBUG The ipa-dns-install command failed, exception:
TypeError: sequence item 0: expected string, DNSName found
Updated patches attached.
Due new installers, more changes were required.
Sorry, NACK, I'm not able to apply this patch set to current master
(69607250b9762a6c9b657dd31653b03d54a7b411).
Rebased patches attached.
NACK.
0) ipa-dns-install --replace-dnssec-master always puts file into
/root/ipa-kasp.db.
It would be better to put it into local working directory or /var/lib/ipa (as
with replica files).
1) I installed DNSSEC key master role on the vm-134 but DNSSEC services were
not stopped by ipactl stop:
[root@vm-134 review]# ipactl stop
Stopping ipa-otpd Service
Stopping httpd Service
Stopping ipa_memcached Service
Stopping kadmin Service
Stopping krb5kdc Service
Stopping Directory Service
ipa: INFO: The ipactl command was successful
[root@vm-134 review]# ipactl start
Starting Directory Service
Starting krb5kdc Service
Starting kadmin Service
Starting named Service
Starting ipa_memcached Service
Starting httpd Service
Starting ipa-otpd Service
Starting ipa-ods-exporter Service
Starting ods-enforcerd Service
Starting ipa-dnskeysyncd Service
Subsequent ipactl stop worked fine, only the first one is affected.
2a) vm-134 was the original master. I ran this:
[root@vm-134 review]# ipa-dns-install
--replace-dnssec-master=vm-090.abc.idm.lab.eng.brq.redhat.com
... and then attempted to install master to vm-059:
[root@vm-059 review]# ipa-dns-install --dnssec-master
This command was accepted despite of missing --kasp-db option and wrong
replica name.
It should error out and tell the user to run the command with --kasp-db
option.
Even better, we could get rid of explicit replica name specification in
--replace-dnssec-master option and allow to run installation with
--kasp-db on
any replica as long as the kasp.db file is provided.
2b) Attempt to move DNSSEC key master from vm-134 to vm-090 *without*
specifying --kasp-db option was accepted.
[root@vm-090 review]# ipa-dns-install --dnssec-master
As in case (2a), it should print what user is supposed to do.
I propose following text:
Current DNSSEC key master <vm-134.abc.idm.lab.eng.brq.redhat.com> is being
moved to different server.
You need to copy kasp.db file from <vm-134.abc.idm.lab.eng.brq.redhat.com>
and
run following command to complete the transition:
# ipa-dns-install --dnssec-master --kasp-db=/path/to/the/copied/kasp.db
3) [root@vm-134 review]# ipa-dns-install
--replace-dnssec-master=vm-090.abc.idm.lab.eng.brq.redhat.com
does not remove ISMASTER option from file /etc/sysconfig/ipa-dnskeysyncd .
4) [root@vm-134 review]# ipa-dns-install
--replace-dnssec-master=vm-090.abc.idm.lab.eng.brq.redhat.com
it is possible to run
[root@vm-134 review]# ipa-dns-install --dnssec-master
again without --kasp-db and it is accepted.
Moreover, in this case ipaConfigString "NEW_DNSSEC_MASTER" is not properly
removed from
cn=DNSKeySync,cn=vm-090.abc.idm.lab.eng.brq.redhat.com,cn=masters,cn=ipa,cn=etc,dc=ipa,dc=example.
5) Sequence of commands
[root@vm-134 review]# ipa-dns-install
--replace-dnssec-master=vm-090.abc.idm.lab.eng.brq.redhat.com
[root@vm-090 review]# ipa-replica-manage del
vm-134.abc.idm.lab.eng.brq.redhat.com
allows me to run
[root@vm-090 review]# ipa-dns-install --dnssec-master
without --kasp-db option, it does not throw an error, and the information
that
some other master existed somewhere is lost.
It would be probably better to replace this and to use some global attribute
in cn=dns so similar problems do not happen.
6) The migration itself seems to work, KASP DB seems to work properly,
however
it is necessary to run 'ods-ksmutil zonelist' command *before* all the
daemons
on the new master are (re)started. This needs do be done to re-generate file
/etc/opendnssec/zonelist.xml from the new (copied) DB.
Here please be careful about file permissions.
The command should be ran under 'ods' user to avoid permission clobbering.
Thank you for your hard work on this!
New patches attached.
Major part of the code was changed.
Please apply patch 268 first.
Updated patches attached.
I just changed the error log to debug log
ipautil.run(cmd, runas=ods_enforcerd.get_user_name())
- except CalledProcessError as e:
- root_logger.error("%s", e)
+ except CalledProcessError:
+ root_logger.debug("OpenDNSSEC database has not been updated")
As this is not error during uninstall.
--
Martin Basti
Updated patches attached.
Cond-NACK. Moving master does not work without additional patching. I'm
attaching fix for this + some polish for messages.
Please review my amendments, it can be pushed if you are okay with my changes.
Thank you, it works. I did 2 small changes
1)
In patch 51 i moved the check to parser, and fixed error message to
proper option
2)
in patch 50 I switched:
if api.env.host not in dnssec_masters and dnssec_masters:
to
if dnssec_masters and api.env.host not in dnssec_masters:
These patches belong to master branch only.
All patches attached.
--
Martin Basti
From 96cdbd12782eb36ddd1d8f4213d875d2cb371aa9 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Wed, 13 May 2015 14:45:32 +0200
Subject: [PATCH 1/2] 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
---
install/tools/ipa-dns-install | 12 +++
ipaplatform/base/paths.py | 2 +
ipaserver/install/dns.py | 154 +++++++++++++++++++++++++++--
ipaserver/install/odsexporterinstance.py | 12 ++-
ipaserver/install/opendnssecinstance.py | 98 ++++++++++++++++--
ipaserver/install/server/install.py | 23 ++++-
ipaserver/install/server/replicainstall.py | 30 +++++-
7 files changed, 309 insertions(+), 22 deletions(-)
diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
index fd9311657e813988310db2be604ca68d26936af5..d827992010685936d64b7f03f0980ef39e94e0b0 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -61,6 +61,15 @@ def parse_options():
help="DNS zone manager e-mail address. Defaults to hostmaster@DOMAIN")
parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
default=False, help="unattended installation never prompts the user")
+ parser.add_option("--disable-dnssec-master", dest="disable_dnssec_master",
+ action="store_true", default=False, help="Disable the "
+ "DNSSEC master on this server")
+ parser.add_option("--kasp-db", dest="kasp_db_file", type="string",
+ metavar="FILE", action="store", help="Copy OpenDNSSEC "
+ "metadata from the specified file (will not create a new "
+ "kasp.db file)")
+ parser.add_option("--force", dest="force", action="store_true",
+ help="Force install")
options, args = parser.parse_args()
safe_options = parser.get_safe_opts(options)
@@ -74,6 +83,9 @@ def parse_options():
if not options.forwarders and not options.no_forwarders:
parser.error("You must specify at least one --forwarder option or --no-forwarders option")
+ if options.kasp_db_file and not ipautil.file_exists(options.kasp_db_file):
+ parser.error("File %s does not exist" % options.kasp_db_file)
+
if options.dm_password:
print ("WARNING: Option -p/--ds-password is deprecated "
"and should not be used anymore.")
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
index e847f93b543d187f9ec72788e17f67e7afe90c07..af341691a4fe154295dd164763a3429ad3f9ed13 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -90,6 +90,7 @@ class BasePathNamespace(object):
ETC_OPENDNSSEC_DIR = "/etc/opendnssec"
OPENDNSSEC_CONF_FILE = "/etc/opendnssec/conf.xml"
OPENDNSSEC_KASP_FILE = "/etc/opendnssec/kasp.xml"
+ OPENDNSSEC_ZONELIST_FILE = "/etc/opendnssec/zonelist.xml"
OPENLDAP_LDAP_CONF = "/etc/openldap/ldap.conf"
PAM_LDAP_CONF = "/etc/pam_ldap.conf"
PASSWD = "/etc/passwd"
@@ -276,6 +277,7 @@ class BasePathNamespace(object):
SYSRESTORE_INDEX = "/var/lib/ipa-client/sysrestore/sysrestore.index"
IPA_BACKUP_DIR = "/var/lib/ipa/backup"
IPA_DNSSEC_DIR = "/var/lib/ipa/dnssec"
+ IPA_KASP_DB_BACKUP = "/var/lib/ipa/ipa-kasp.db.backup"
DNSSEC_TOKENS_DIR = "/var/lib/ipa/dnssec/tokens"
DNSSEC_SOFTHSM_PIN = "/var/lib/ipa/dnssec/softhsm_pin"
IPA_CA_CSR = "/var/lib/ipa/ca.csr"
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 8d9570d68c5c84116839371f3ce8e73d71da2db5..1382382b587edce097fc866cac3079b9d0590e87 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()
diff --git a/ipaserver/install/odsexporterinstance.py b/ipaserver/install/odsexporterinstance.py
index 5b6245bc48803b4c5545299e4386213319ae859a..c37095cfc3bba8c6724f45d23293bdf6f4a200ee 100644
--- a/ipaserver/install/odsexporterinstance.py
+++ b/ipaserver/install/odsexporterinstance.py
@@ -15,12 +15,12 @@ from ipapython.dn import DN
from ipapython import sysrestore, ipautil, ipaldap
from ipaplatform.paths import paths
from ipaplatform import services
-from ipalib import errors
+from ipalib import errors, api
class ODSExporterInstance(service.Service):
def __init__(self, fstore=None, dm_password=None, ldapi=False,
- start_tls=False, autobind=ipaldap.AUTOBIND_DISABLED):
+ start_tls=False, autobind=ipaldap.AUTOBIND_ENABLED):
service.Service.__init__(
self, "ipa-ods-exporter",
service_desc="IPA OpenDNSSEC exporter daemon",
@@ -150,6 +150,14 @@ class ODSExporterInstance(service.Service):
def __start(self):
self.start()
+ def remove_service(self):
+ dns_exporter_principal = ("ipa-ods-exporter/%s@%s" % (self.fqdn,
+ self.realm))
+ try:
+ api.Command.service_del(dns_exporter_principal)
+ except errors.NotFound:
+ pass
+
def uninstall(self):
if not self.is_configured():
return
diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py
index 5384759858463b25e92b20b65ac633b79519d5dd..d68691fa32f135c7527ce28ed771757eadab4831 100644
--- a/ipaserver/install/opendnssecinstance.py
+++ b/ipaserver/install/opendnssecinstance.py
@@ -9,6 +9,9 @@ import os
import pwd
import grp
import stat
+import shutil
+
+from subprocess import CalledProcessError
import _ipap11helper
@@ -31,7 +34,7 @@ def get_dnssec_key_masters(conn):
"""
assert conn is not None
- dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
+ dn = DN(api.env.container_masters, api.env.basedn)
filter_attrs = {
u'cn': u'DNSSEC',
@@ -62,7 +65,7 @@ def check_inst():
class OpenDNSSECInstance(service.Service):
def __init__(self, fstore=None, dm_password=None, ldapi=False,
- start_tls=False, autobind=ipaldap.AUTOBIND_DISABLED):
+ start_tls=False, autobind=ipaldap.AUTOBIND_ENABLED):
service.Service.__init__(
self, "ods-enforcerd",
service_desc="OpenDNSSEC enforcer daemon",
@@ -94,12 +97,14 @@ class OpenDNSSECInstance(service.Service):
self.ldap_connect()
return get_dnssec_key_masters(self.admin_conn)
- def create_instance(self, fqdn, realm_name, generate_master_key=True):
+ def create_instance(self, fqdn, realm_name, generate_master_key=True,
+ kasp_db_file=None):
self.backup_state("enabled", self.is_enabled())
self.backup_state("running", self.is_running())
self.fqdn = fqdn
self.realm = realm_name
self.suffix = ipautil.realm_to_suffix(self.realm)
+ self.kasp_db_file = kasp_db_file
try:
self.stop()
@@ -152,6 +157,21 @@ class OpenDNSSECInstance(service.Service):
except errors.DuplicateEntry:
root_logger.error("DNSSEC service already exists")
+ # add the KEYMASTER identifier into ipaConfigString
+ # this is needed for the re-enabled DNSSEC master
+ dn = DN(('cn', 'DNSSEC'), ('cn', self.fqdn), api.env.container_masters,
+ api.env.basedn)
+ try:
+ entry = self.admin_conn.get_entry(dn, ['ipaConfigString'])
+ except errors.NotFound as e:
+ root_logger.error(
+ "DNSSEC service entry not found in the LDAP (%s)", e)
+ else:
+ config = entry.setdefault('ipaConfigString', [])
+ if KEYMASTER not in config:
+ config.append(KEYMASTER)
+ self.admin_conn.update_entry(entry)
+
def __setup_conf_files(self):
if not self.fstore.has_file(paths.OPENDNSSEC_CONF_FILE):
self.fstore.backup_file(paths.OPENDNSSEC_CONF_FILE)
@@ -250,7 +270,7 @@ class OpenDNSSECInstance(service.Service):
def __setup_dnssec(self):
# run once only
- if self.get_state("KASP_DB_configured"):
+ if self.get_state("KASP_DB_configured") and not self.kasp_db_file:
root_logger.debug("Already configured, skipping step")
return
@@ -259,13 +279,33 @@ class OpenDNSSECInstance(service.Service):
if not self.fstore.has_file(paths.OPENDNSSEC_KASP_DB):
self.fstore.backup_file(paths.OPENDNSSEC_KASP_DB)
- command = [
- paths.ODS_KSMUTIL,
- 'setup'
- ]
+ if self.kasp_db_file:
+ # copy user specified kasp.db to proper location and set proper
+ # privileges
+ shutil.copy(self.kasp_db_file, paths.OPENDNSSEC_KASP_DB)
+ os.chown(paths.OPENDNSSEC_KASP_DB, self.ods_uid, self.ods_gid)
+ os.chmod(paths.OPENDNSSEC_KASP_DB, 0660)
- ods_enforcerd = services.knownservices.ods_enforcerd
- ipautil.run(command, stdin="y", runas=ods_enforcerd.get_user_name())
+ # regenerate zonelist.xml
+ ods_enforcerd = services.knownservices.ods_enforcerd
+ cmd = [paths.ODS_KSMUTIL, 'zonelist', 'export']
+ stdout, stderr, retcode = ipautil.run(cmd,
+ runas=ods_enforcerd.get_user_name())
+ with open(paths.OPENDNSSEC_ZONELIST_FILE, 'w') as zonelistf:
+ zonelistf.write(stdout)
+ os.chown(paths.OPENDNSSEC_ZONELIST_FILE,
+ self.ods_uid, self.ods_gid)
+ os.chmod(paths.OPENDNSSEC_ZONELIST_FILE, 0660)
+
+ else:
+ # initialize new kasp.db
+ command = [
+ paths.ODS_KSMUTIL,
+ 'setup'
+ ]
+
+ ods_enforcerd = services.knownservices.ods_enforcerd
+ ipautil.run(command, stdin="y", runas=ods_enforcerd.get_user_name())
def __setup_dnskeysyncd(self):
# set up dnskeysyncd this is DNSSEC master
@@ -286,6 +326,44 @@ class OpenDNSSECInstance(service.Service):
running = self.restore_state("running")
enabled = self.restore_state("enabled")
+ # stop DNSSEC services before backing up kasp.db
+ try:
+ self.stop()
+ except Exception:
+ pass
+
+ ods_exporter = services.service('ipa-ods-exporter')
+ try:
+ ods_exporter.stop()
+ except Exception:
+ pass
+
+ # remove directive from ipa-dnskeysyncd, this server is not DNSSEC
+ # master anymore
+ installutils.set_directive(paths.SYSCONFIG_IPA_DNSKEYSYNCD,
+ 'ISMASTER', None,
+ quotes=False, separator='=')
+
+ if ipautil.file_exists(paths.OPENDNSSEC_KASP_DB):
+
+ # force to export data
+ ods_enforcerd = services.knownservices.ods_enforcerd
+ cmd = [paths.IPA_ODS_EXPORTER, 'ipa-full-update']
+ try:
+ ipautil.run(cmd, runas=ods_enforcerd.get_user_name())
+ except CalledProcessError:
+ root_logger.debug("OpenDNSSEC database has not been updated")
+
+ try:
+ shutil.copy(paths.OPENDNSSEC_KASP_DB,
+ paths.IPA_KASP_DB_BACKUP)
+ except IOError as e:
+ root_logger.error(
+ "Unable to backup OpenDNSSEC database: %s", e)
+ else:
+ root_logger.info("OpenDNSSEC database backed up in %s",
+ paths.IPA_KASP_DB_BACKUP)
+
for f in [paths.OPENDNSSEC_CONF_FILE, paths.OPENDNSSEC_KASP_FILE,
paths.OPENDNSSEC_KASP_DB, paths.SYSCONFIG_ODS]:
try:
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index bde34851871f9b9f2bdf6dfecfd428755cc42e31..ad7243b8418c3eaaa6d977e5a056eb748a1bc2d6 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -1330,6 +1330,25 @@ class ServerDNS(common.Installable, core.Group, core.Composite):
description="Setup server to be DNSSEC key master",
)
+ disable_dnssec_master = Knob(
+ bool, False,
+ initializable=False,
+ description="Disable the DNSSEC master on this server",
+ )
+
+ kasp_db_file = Knob(
+ str, None,
+ initializable=False,
+ description="Copy OpenDNSSEC metadata from the specified file (will "
+ "not create a new kasp.db file)",
+ )
+
+ force = Knob(
+ bool, False,
+ initializable=False,
+ description="Force install",
+ )
+
zonemgr = Knob(
str, None,
description=("DNS zone manager e-mail address. Defaults to "
@@ -1618,7 +1637,6 @@ class Server(common.Installable, common.Interactive, core.Composite):
self.ca_cert_files = self.ca.ca_cert_files
self.subject = self.ca.subject
self.ca_signing_algorithm = self.ca.ca_signing_algorithm
-
self.setup_dns = self.dns.setup_dns
self.forwarders = self.dns.forwarders
self.no_forwarders = self.dns.no_forwarders
@@ -1626,6 +1644,9 @@ class Server(common.Installable, common.Interactive, core.Composite):
self.no_reverse = self.dns.no_reverse
self.no_dnssec_validation = self.dns.no_dnssec_validation
self.dnssec_master = self.dns.dnssec_master
+ self.disable_dnssec_master = self.dns.disable_dnssec_master
+ self.kasp_db_file = self.dns.kasp_db_file
+ self.force = self.dns.force
self.zonemgr = self.dns.zonemgr
self.no_host_dns = self.dns.no_host_dns
self.no_dns_sshfp = self.dns.no_dns_sshfp
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 54d1ede1340afddeca6e1de453aadd166fb19444..4fe7e1f78388901b3cc4e9dc0c2046a193dcfa94 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -699,6 +699,31 @@ class ReplicaDNS(common.Installable, core.Group, core.Composite):
description="Disable DNSSEC validation",
)
+ dnssec_master = Knob(
+ bool, False,
+ initializable=False,
+ description="Setup server to be DNSSEC key master",
+ )
+
+ disable_dnssec_master = Knob(
+ bool, False,
+ initializable=False,
+ description="Disable the DNSSEC master on this server",
+ )
+
+ force = Knob(
+ bool, False,
+ initializable=False,
+ description="Force install",
+ )
+
+ kasp_db_file = Knob(
+ str, None,
+ initializable=False,
+ description="Copy OpenDNSSEC metadata from the specified file (will "
+ "not create a new kasp.db file)",
+ )
+
no_host_dns = Knob(
bool, False,
description="Do not use DNS for hostname lookup during installation",
@@ -847,7 +872,10 @@ class Replica(common.Installable, common.Interactive, core.Composite):
self.reverse_zones = self.dns.reverse_zones
self.no_reverse = self.dns.no_reverse
self.no_dnssec_validation = self.dns.no_dnssec_validation
- self.dnssec_master = False
+ self.dnssec_master = self.dns.dnssec_master
+ self.disable_dnssec_master = self.dns.disable_dnssec_master
+ self.kasp_db_file = self.dns.kasp_db_file
+ self.force = self.dns.force
self.zonemgr = None
self.no_host_dns = self.dns.no_host_dns
self.no_dns_sshfp = self.dns.no_dns_sshfp
--
2.4.3
From aad47c54f1ebdaf74c78c3b13d5f457b1e71d5e6 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Wed, 17 Jun 2015 13:35:18 +0200
Subject: [PATCH 2/2] DNSSEC: update message
https://fedorahosted.org/freeipa/ticket/4657
---
install/tools/ipa-replica-manage | 1 +
ipaserver/install/dns.py | 28 +++++++++++++++++++++-------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 57e30bc54ae030a4620660d1fa7539626721ebbd..b178c2f0b1b08c4a27175d4d8347c48ea3f12f23 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -623,6 +623,7 @@ def ensure_last_services(conn, hostname, masters, options):
dnssec_masters = opendnssecinstance.get_dnssec_key_masters(conn)
if hostname in dnssec_masters:
print "Replica is active DNSSEC key master. Uninstall could break your DNS system."
+ print "Please disable or replace DNSSEC key master first."
sys.exit("Deletion aborted")
ca = cainstance.CAInstance(api.env.realm, certs.NSS_DIR)
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 1382382b587edce097fc866cac3079b9d0590e87..bd176c1efc5ed0cddefe481c94c41f7be484b98e 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -154,8 +154,15 @@ def install_check(standalone, replica, options, hostname):
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." %
+ "enabled for following zone(s):\n"
+ "%s\n"
+ "It is possible to move DNSSEC key master role to a different "
+ "server by using --force option to skip this check.\n\n"
+ "WARNING: You have to immediatelly copy kasp.db file to a new "
+ "server and run command 'ipa-dns-install --dnssec-master "
+ "--kasp-db'.\n"
+ "Your DNS zones will become unavailable if you "
+ "do not reinstall the DNSSEC key master role immediatelly." %
", ".join([str(zone) for zone in dnssec_zones]))
elif options.dnssec_master:
# check opendnssec packages are installed
@@ -186,8 +193,10 @@ def install_check(standalone, replica, options, hostname):
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)")
+ raise RuntimeError("This IPA server cannot be promoted to "
+ "DNSSEC master role because some keys were "
+ "not replicated from the original "
+ "DNSSEC master server")
finally:
if dnskeysyncd_running:
dnskeysyncd.start()
@@ -195,9 +204,14 @@ def install_check(standalone, replica, options, hostname):
# 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." %
+ "DNSSEC signing is already enabled for following zone(s): %s\n"
+ "Installation cannot continue without the OpenDNSSEC database "
+ "file from the original DNSSEC master server.\n"
+ "Please use option --kasp-db to specify location "
+ "of the kasp.db file copied from the original "
+ "DNSSEC master server.\n"
+ "WARNING: Zones will become unavailable if you do not provide "
+ "the original kasp.db file." %
", ".join([str(zone) for zone in dnssec_zones]))
--
2.4.3
From 2f5c1ed3cc54f1954000d96322a1c35217b2d260 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Fri, 26 Jun 2015 12:44:20 +0200
Subject: [PATCH] Allow to run subprocess with suplementary groups
Param suplementary_groups allows to specify list of group names to be
used for subprocess.
suplementary_groups param requires runas param to be specified.
Required for ticket: https://fedorahosted.org/freeipa/ticket/4657
---
ipapython/ipautil.py | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index f0c9c6b5ab1ac3f2a66b3467e833dcc21bc98a49..88e89706b8e2aa6dea80809510d88bceaa836e85 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -36,6 +36,7 @@ import netaddr
import time
import krbV
import pwd
+import grp
from dns import resolver, rdatatype
from dns.exception import DNSException
from contextlib import contextmanager
@@ -250,7 +251,7 @@ def shell_quote(string):
def run(args, stdin=None, raiseonerr=True,
nolog=(), env=None, capture_output=True, skip_output=False, cwd=None,
- runas=None, timeout=None):
+ runas=None, timeout=None, suplementary_groups=[]):
"""
Execute a command and return stdin, stdout and the process return code.
@@ -276,11 +277,15 @@ def run(args, stdin=None, raiseonerr=True,
:param capture_output: Capture stderr and stdout
:param skip_output: Redirect the output to /dev/null and do not capture it
:param cwd: Current working directory
- :param runas: Name of a user that the command shold be run as. The spawned
+ :param runas: Name of a user that the command should be run as. The spawned
process will have both real and effective UID and GID set.
:param timeout: Timeout if the command hasn't returned within the specified
number of seconds.
+ :param suplementary_groups: List of group names that will be used as
+ suplementary groups for subporcess.
+ The option runas must be specified together with this option.
"""
+ assert isinstance(suplementary_groups, list)
p_in = None
p_out = None
p_err = None
@@ -317,11 +322,22 @@ def run(args, stdin=None, raiseonerr=True,
preexec_fn = None
if runas is not None:
pent = pwd.getpwnam(runas)
+
+ suplementary_gids = [
+ grp.getgrnam(group).gr_gid for group in suplementary_groups
+ ]
+
root_logger.debug('runas=%s (UID %d, GID %s)', runas,
pent.pw_uid, pent.pw_gid)
+ if suplementary_groups:
+ for group, gid in zip(suplementary_groups, suplementary_gids):
+ root_logger.debug('suplementary_group=%s (GID %d)', group, gid)
- preexec_fn = lambda: (os.setregid(pent.pw_gid, pent.pw_gid),
- os.setreuid(pent.pw_uid, pent.pw_uid))
+ preexec_fn = lambda: (
+ os.setgroups(suplementary_gids),
+ os.setregid(pent.pw_gid, pent.pw_gid),
+ os.setreuid(pent.pw_uid, pent.pw_uid),
+ )
try:
p = subprocess.Popen(args, stdin=p_in, stdout=p_out, stderr=p_err,
--
2.4.3
From 94b82fc0bcd300ab5953f516bee9c148f902835c Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 30 Jun 2015 21:48:47 +0200
Subject: [PATCH 1/2] DNSSEC: ipa-dns-install: Detect existing master server
sooner.
User should get the error before he installs missing packages etc.
https://fedorahosted.org/freeipa/ticket/4657
---
ipaserver/install/dns.py | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index bd176c1efc5ed0cddefe481c94c41f7be484b98e..d22bce7a7cd2e0e8a7ffe0ab4aa496634465903b 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -94,6 +94,7 @@ def install_check(standalone, replica, options, hostname):
global ip_addresses
global dns_forwarders
global reverse_zones
+ fstore = sysrestore.FileStore(paths.SYSRESTORE)
if standalone:
print "=============================================================================="
@@ -164,7 +165,18 @@ def install_check(standalone, replica, options, hostname):
"Your DNS zones will become unavailable if you "
"do not reinstall the DNSSEC key master role immediatelly." %
", ".join([str(zone) for zone in dnssec_zones]))
+
elif options.dnssec_master:
+ ods = opendnssecinstance.OpenDNSSECInstance(
+ fstore, ldapi=True)
+ ods.realm = api.env.realm
+ dnssec_masters = ods.get_masters()
+ # we can reinstall current server if it is dnssec master
+ if dnssec_masters and api.env.host not in dnssec_masters:
+ print "DNSSEC key master(s):", u','.join(dnssec_masters)
+ sys.exit("Only one DNSSEC key master is supported in current "
+ "version.")
+
# check opendnssec packages are installed
if not opendnssecinstance.check_inst():
sys.exit("Aborting installation")
@@ -214,20 +226,6 @@ def install_check(standalone, replica, options, hostname):
"the original kasp.db file." %
", ".join([str(zone) for zone in dnssec_zones]))
-
- fstore = sysrestore.FileStore(paths.SYSRESTORE)
-
- if options.dnssec_master:
- ods = opendnssecinstance.OpenDNSSECInstance(
- fstore, ldapi=True)
- ods.realm = api.env.realm
- dnssec_masters = ods.get_masters()
- # we can reinstall current server if it is dnssec master
- if api.env.host not in dnssec_masters and dnssec_masters:
- print "DNSSEC key master(s):", u','.join(dnssec_masters)
- sys.exit("Only one DNSSEC key master is supported in current "
- "version.")
-
ip_addresses = get_server_ip_address(
hostname, fstore, options.unattended, True, options.ip_addresses)
--
2.4.3
From 76863229b96fae408e4fb30d9f6d19c92e4341ab Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 30 Jun 2015 22:05:44 +0200
Subject: [PATCH 2/2] DNSSEC: Detect attempt to install & disable master at the
same time.
https://fedorahosted.org/freeipa/ticket/4657
---
install/tools/ipa-dns-install | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
index d827992010685936d64b7f03f0980ef39e94e0b0..3fcda04e71d77e25ef328e2037b9e147ed1403bc 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -74,6 +74,10 @@ def parse_options():
options, args = parser.parse_args()
safe_options = parser.get_safe_opts(options)
+ if options.dnssec_master and options.disable_dnssec_master:
+ parser.error("Invalid combination of parameters: --dnssec-master and "
+ "--disable-dnssec-master")
+
if options.forwarders and options.no_forwarders:
parser.error("You cannot specify a --forwarder option together with --no-forwarders")
elif options.reverse_zones and options.no_reverse:
--
2.4.3
--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code