URL: https://github.com/freeipa/freeipa/pull/479 Author: martbab Title: #479: Merge AD trust installer into composite ones Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/479/head:pr479 git checkout pr479
From 279684608d667d31e919021f4b7ffb397c4a6fcf Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Thu, 16 Feb 2017 14:06:08 +0100 Subject: [PATCH 01/13] Refactor the code checking for missing SIDs Decompose the individual sub-tasks into separate functions. Also perform the lookup only when LDAP is connected. https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/adtrust.py | 107 ++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index 92fe031..69e9834 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -168,6 +168,69 @@ def check_for_installed_deps(): raise ScriptError("Aborting installation.") +def retrieve_entries_without_sid(api): + """ + Retrieve a list of entries without assigned SIDs. + :returns: a list of entries or an empty list if an error occurs + """ + # The filter corresponds to ipa_sidgen_task.c LDAP search filter + filter = '(&(objectclass=ipaobject)(!(objectclass=mepmanagedentry))' \ + '(|(objectclass=posixaccount)(objectclass=posixgroup)' \ + '(objectclass=ipaidobject))(!(ipantsecurityidentifier=*)))' + base_dn = api.env.basedn + try: + root_logger.debug( + "Searching for objects with missing SID with " + "filter=%s, base_dn=%s", filter, base_dn) + entries, _truncated = api.Backend.ldap2.find_entries( + filter=filter, base_dn=base_dn, attrs_list=['']) + return entries + except errors.NotFound: + # All objects have SIDs assigned + pass + except (errors.DatabaseError, errors.NetworkError) as e: + print("Could not retrieve a list of objects that need a SID " + "identifier assigned:") + print(unicode(e)) + + return [] + + +def retrieve_and_ask_about_sids(api, options): + entries = [] + if api.Backend.ldap2.isconnected(): + entries = retrieve_entries_without_sid(api) + else: + root_logger.debug( + "LDAP backend not connected, can not retrieve entries " + "with missing SID") + + object_count = len(entries) + if object_count > 0: + print("") + print("WARNING: %d existing users or groups do not have " + "a SID identifier assigned." % len(entries)) + print("Installer can run a task to have ipa-sidgen " + "Directory Server plugin generate") + print("the SID identifier for all these users. Please note, " + "the in case of a high") + print("number of users and groups, the operation might " + "lead to high replication") + print("traffic and performance degradation. Refer to " + "ipa-adtrust-install(1) man page") + print("for details.") + print("") + if options.unattended: + print("Unattended mode was selected, installer will " + "NOT run ipa-sidgen task!") + else: + if ipautil.user_input( + "Do you want to run the ipa-sidgen task?", + default=False, + allow_empty=False): + options.add_sids = True + + def install_check(standalone, options, api): global netbios_name global reset_netbios_name @@ -225,49 +288,7 @@ def install_check(standalone, options, api): options.netbios_name, options.unattended, api) if not options.add_sids: - # The filter corresponds to ipa_sidgen_task.c LDAP search filter - filter = '(&(objectclass=ipaobject)(!(objectclass=mepmanagedentry))' \ - '(|(objectclass=posixaccount)(objectclass=posixgroup)' \ - '(objectclass=ipaidobject))(!(ipantsecurityidentifier=*)))' - base_dn = api.env.basedn - try: - root_logger.debug( - "Searching for objects with missing SID with " - "filter=%s, base_dn=%s", filter, base_dn) - entries, _truncated = api.Backend.ldap2.find_entries( - filter=filter, base_dn=base_dn, attrs_list=['']) - except errors.NotFound: - # All objects have SIDs assigned - pass - except (errors.DatabaseError, errors.NetworkError) as e: - print("Could not retrieve a list of objects that need a SID " - "identifier assigned:") - print(unicode(e)) - else: - object_count = len(entries) - if object_count > 0: - print("") - print("WARNING: %d existing users or groups do not have " - "a SID identifier assigned." % len(entries)) - print("Installer can run a task to have ipa-sidgen " - "Directory Server plugin generate") - print("the SID identifier for all these users. Please note, " - "the in case of a high") - print("number of users and groups, the operation might " - "lead to high replication") - print("traffic and performance degradation. Refer to " - "ipa-adtrust-install(1) man page") - print("for details.") - print("") - if options.unattended: - print("Unattended mode was selected, installer will " - "NOT run ipa-sidgen task!") - else: - if ipautil.user_input( - "Do you want to run the ipa-sidgen task?", - default=False, - allow_empty=False): - options.add_sids = True + retrieve_and_ask_about_sids(api, options) def install(options, fstore, api): From ce45a3965c7fe44f2a9dc589e31a498b3bab5e10 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Thu, 16 Feb 2017 13:41:32 +0100 Subject: [PATCH 02/13] only check for netbios name when LDAP backend is connected This is to prevent errors due to non-existent LDAP connection such as when installing first IPA master. https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/adtrust.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index 69e9834..fd26e69 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -59,6 +59,21 @@ def read_netbios_name(netbios_default): return netbios_name +def retrieve_netbios_name(api): + flat_name_attr = 'ipantflatname' + try: + entry = api.Backend.ldap2.get_entry( + DN(('cn', api.env.domain), api.env.container_cifsdomains, + ipautil.realm_to_suffix(api.env.realm)), + [flat_name_attr]) + except errors.NotFound: + # trust not configured + root_logger.debug("No previous trust configuration found") + return None + else: + return entry.get(flat_name_attr)[0] + + def set_and_check_netbios_name(netbios_name, unattended, api): """ Depending if trust in already configured or not a given NetBIOS domain @@ -71,22 +86,16 @@ def set_and_check_netbios_name(netbios_name, unattended, api): the stored NetBIOS name it it differs from the current one. """ - flat_name_attr = 'ipantflatname' cur_netbios_name = None gen_netbios_name = None reset_netbios_name = False entry = None - try: - entry = api.Backend.ldap2.get_entry( - DN(('cn', api.env.domain), api.env.container_cifsdomains, - ipautil.realm_to_suffix(api.env.realm)), - [flat_name_attr]) - except errors.NotFound: - # trust not configured - pass + if api.Backend.ldap2.isconnected(): + cur_netbios_name = retrieve_netbios_name(api) else: - cur_netbios_name = entry.get(flat_name_attr)[0] + root_logger.debug( + "LDAP is not connected, can not retrieve NetBIOS name") if cur_netbios_name and not netbios_name: # keep the current NetBIOS name From 0ff276204f8996c1dfb3a414f93a3034b61d09d0 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Thu, 16 Feb 2017 14:14:01 +0100 Subject: [PATCH 03/13] Refactor the code searching and presenting missing trust agents Use newly implemented APIs for searching and presenting potential trust agents. https://fedorahosted.org/freeipa/ticket/6639 --- ipaserver/install/adtrust.py | 196 +++++++++++++++++++++++-------------------- 1 file changed, 106 insertions(+), 90 deletions(-) diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index fd26e69..deb4301 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -9,10 +9,10 @@ from __future__ import print_function import os -import ldap import six +from ipalib.constants import DOMAIN_LEVEL_0 from ipalib import errors from ipaplatform.paths import paths from ipapython.admintool import ScriptError @@ -240,6 +240,110 @@ def retrieve_and_ask_about_sids(api, options): options.add_sids = True +def retrieve_potential_adtrust_agents(api): + """ + Retrieve a sorted list of potential AD trust agents + + :param api: initialized API instance + :returns: sorted list of FQDNs of masters which are not AD trust agents + """ + try: + # Search only masters which have support for domain levels + # because only these masters will have SSSD recent enough + # to support AD trust agents + dl_enabled_masters = api.Command.server_find( + ipamindomainlevel=DOMAIN_LEVEL_0, all=True)['result'] + except (errors.DatabaseError, errors.NetworkError) as e: + print("Could not retrieve a list of existing IPA masters:") + print(unicode(e)) + return + + try: + # search for existing AD trust agents + adtrust_agents = api.Command.server_find( + servrole=u'AD trust agent', all=True)['result'] + except (errors.DatabaseError, errors.NetworkError) as e: + print("Could not retrieve a list of adtrust agents:") + print(unicode(e)) + return + + dl_enabled_master_cns = {m['cn'][0] for m in dl_enabled_masters} + adtrust_agents_cns = {m['cn'][0] for m in adtrust_agents} + + potential_agents_cns = dl_enabled_master_cns - adtrust_agents_cns + + # remove the local host from the potential agents since it will be set up + # by adtrustinstance configuration code + potential_agents_cns -= {api.env.host} + return sorted(potential_agents_cns) + + +def add_hosts_to_adtrust_agents(api, host_list): + """ + Add the CIFS and host principals to the 'adtrust agents' + group as 389-ds only operates with GroupOfNames, we have to + use the principal's proper dn as defined in self.cifs_agent + + :param api: API instance + :param host_list: list of potential AD trust agent FQDNs + """ + agents_dn = DN( + ('cn', 'adtrust agents'), ('cn', 'sysaccounts'), + ('cn', 'etc'), api.env.basedn) + + service.add_principals_to_group( + api.Backend.ldap2, + agents_dn, + "member", + [api.Object.host.get_dn(x) for x in host_list]) + + +def add_new_adtrust_agents(api, options): + """ + Find out IPA masters which are not part of the cn=adtrust agents + and propose them to be added to the list + :param api: API instance + :param options: parsed CLI options + """ + potential_agents_cns = retrieve_potential_adtrust_agents(api) + + if potential_agents_cns: + print("") + print("WARNING: %d IPA masters are not yet able to serve " + "information about users from trusted forests." + % len(potential_agents_cns)) + print("Installer can add them to the list of IPA masters " + "allowed to access information about trusts.") + print("If you choose to do so, you also need to restart " + "LDAP service on those masters.") + print("Refer to ipa-adtrust-install(1) man page for details.") + print("") + if options.unattended: + print("Unattended mode was selected, installer will NOT " + "add other IPA masters to the list of allowed to") + print("access information about trusted forests!") + return + + new_agents = [] + + for name in sorted(potential_agents_cns): + if ipautil.user_input( + "IPA master [%s]?" % (name), + default=False, + allow_empty=False): + new_agents.append(name) + + if new_agents: + add_hosts_to_adtrust_agents(api, new_agents) + + print(""" +WARNING: you MUST restart (e.g. ipactl restart) the following IPA masters in +order to activate them to serve information about users from trusted forests: +""") + for x in new_agents: + print(x) + + def install_check(standalone, options, api): global netbios_name global reset_netbios_name @@ -321,92 +425,4 @@ def install(options, fstore, api): if options.add_agents: # Find out IPA masters which are not part of the cn=adtrust agents # and propose them to be added to the list - base_dn = api.env.basedn - masters_dn = DN( - ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), base_dn) - agents_dn = DN( - ('cn', 'adtrust agents'), ('cn', 'sysaccounts'), - ('cn', 'etc'), base_dn) - new_agents = [] - entries_m = [] - entries_a = [] - try: - # Search only masters which have support for domain levels - # because only these masters will have SSSD recent enough - # to support AD trust agents - entries_m, _truncated = api.Backend.ldap2.find_entries( - filter=("(&(objectclass=ipaSupportedDomainLevelConfig)" - "(ipaMaxDomainLevel=*)(ipaMinDomainLevel=*))"), - base_dn=masters_dn, attrs_list=['cn'], - scope=ldap.SCOPE_ONELEVEL) - except errors.NotFound: - pass - except (errors.DatabaseError, errors.NetworkError) as e: - print("Could not retrieve a list of existing IPA masters:") - print(unicode(e)) - - try: - entries_a, _truncated = api.Backend.ldap2.find_entries( - filter="", base_dn=agents_dn, attrs_list=['member'], - scope=ldap.SCOPE_BASE) - except errors.NotFound: - pass - except (errors.DatabaseError, errors.NetworkError) as e: - print("Could not retrieve a list of adtrust agents:") - print(unicode(e)) - - if len(entries_m) > 0: - existing_masters = [x['cn'][0] for x in entries_m] - adtrust_agents = entries_a[0]['member'] - potential_agents = [] - for m in existing_masters: - mdn = DN(('fqdn', m), api.env.container_host, api.env.basedn) - found = False - for a in adtrust_agents: - if mdn == a: - found = True - break - if not found: - potential_agents += [[m, mdn]] - - object_count = len(potential_agents) - if object_count > 0: - print("") - print("WARNING: %d IPA masters are not yet able to serve " - "information about users from trusted forests." - % (object_count)) - print("Installer can add them to the list of IPA masters " - "allowed to access information about trusts.") - print("If you choose to do so, you also need to restart " - "LDAP service on those masters.") - print("Refer to ipa-adtrust-install(1) man page for details.") - print("") - if options.unattended: - print("Unattended mode was selected, installer will NOT " - "add other IPA masters to the list of allowed to") - print("access information about trusted forests!") - else: - print( - "Do you want to allow following IPA masters to " - "serve information about users from trusted forests?") - for (name, dn) in potential_agents: - if name == api.env.host: - # Don't add this host here - # it shouldn't be here as it was added by the - # adtrustinstance setup code - continue - if ipautil.user_input( - "IPA master [%s]?" % (name), - default=False, - allow_empty=False): - new_agents += [[name, dn]] - - if len(new_agents) > 0: - # Add the CIFS and host principals to the 'adtrust agents' - # group as 389-ds only operates with GroupOfNames, we have to - # use the principal's proper dn as defined in self.cifs_agent - service.add_principals_to_group( - api.Backend.ldap2, - agents_dn, - "member", - [x[1] for x in new_agents]) + add_new_adtrust_agents(api, options) From 3e5a36f6fb4c7dacc455f8e26d2b4078235b2629 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 14:00:24 +0100 Subject: [PATCH 04/13] adtrust.py: Use logging to emit error messages Plain print messages are a) not logged into files and b) get lost in the output from composite installer. https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/adtrust.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index deb4301..4694a25 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -31,9 +31,10 @@ def netbios_name_error(name): - print("\nIllegal NetBIOS name [%s].\n" % name) - print("Up to 15 characters and only uppercase ASCII letters, digits " - "and dashes are allowed. Empty string is not allowed.") + root_logger.error("\nIllegal NetBIOS name [%s].\n" % name) + root_logger.error( + "Up to 15 characters and only uppercase ASCII letters, digits " + "and dashes are allowed. Empty string is not allowed.") def read_netbios_name(netbios_default): @@ -198,9 +199,9 @@ def retrieve_entries_without_sid(api): # All objects have SIDs assigned pass except (errors.DatabaseError, errors.NetworkError) as e: - print("Could not retrieve a list of objects that need a SID " - "identifier assigned:") - print(unicode(e)) + root_logger.error( + "Could not retrieve a list of objects that need a SID " + "identifier assigned: %s", e) return [] @@ -254,8 +255,8 @@ def retrieve_potential_adtrust_agents(api): dl_enabled_masters = api.Command.server_find( ipamindomainlevel=DOMAIN_LEVEL_0, all=True)['result'] except (errors.DatabaseError, errors.NetworkError) as e: - print("Could not retrieve a list of existing IPA masters:") - print(unicode(e)) + root_logger.error( + "Could not retrieve a list of existing IPA masters: %s", e) return try: @@ -263,8 +264,7 @@ def retrieve_potential_adtrust_agents(api): adtrust_agents = api.Command.server_find( servrole=u'AD trust agent', all=True)['result'] except (errors.DatabaseError, errors.NetworkError) as e: - print("Could not retrieve a list of adtrust agents:") - print(unicode(e)) + root_logger.error("Could not retrieve a list of adtrust agents: %s", e) return dl_enabled_master_cns = {m['cn'][0] for m in dl_enabled_masters} From 76d1e2a7c529ee004785cce8e31297c05a09a6d7 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 13:48:46 +0100 Subject: [PATCH 05/13] print the installation info only in standalone mode There is no point in emitting this message during server/replica install. https://fedorahosted.org/freeipa/ticket/6630 --- install/tools/ipa-adtrust-install | 2 +- ipaserver/install/adtrust.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install index 443c3c4..1484598 100755 --- a/install/tools/ipa-adtrust-install +++ b/install/tools/ipa-adtrust-install @@ -208,7 +208,7 @@ def main(): "Unrecognized error during check of admin rights: %s" % e) adtrust.install_check(True, options, api) - adtrust.install(options, fstore, api) + adtrust.install(True, options, fstore, api) print(""" ============================================================================= diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index 4694a25..2eddf45 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -404,8 +404,8 @@ def install_check(standalone, options, api): retrieve_and_ask_about_sids(api, options) -def install(options, fstore, api): - if not options.unattended: +def install(standalone, options, fstore, api): + if not options.unattended and standalone: print("") print("The following operations may take some minutes to complete.") print("Please wait until the prompt is returned.") From b657abfa4fdc0fc11c794e8bfbefd39195ce3cdb Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Tue, 28 Feb 2017 13:58:36 +0100 Subject: [PATCH 06/13] check for installed dependencies when *not* in standalone mode The condition that controls when to check for samba dependencies was misformulated. The check should be run when the installer is *not* run as standalone. In standalone mode the check is already made in different place so the original code triggered it twice. https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/adtrust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index 2eddf45..a8e4dc8 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -348,7 +348,7 @@ def install_check(standalone, options, api): global netbios_name global reset_netbios_name - if standalone: + if not standalone: check_for_installed_deps() realm_not_matching_domain = (api.env.domain.upper() != api.env.realm) From 559cd12190321a750ce7792a6e22ba4416bec902 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Wed, 15 Feb 2017 10:16:27 +0100 Subject: [PATCH 07/13] Add AD trust installer interface for composite installer This interface is to be used to provide AD trust-related options in server and replica installer. https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/adtrust.py | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py index a8e4dc8..b81c27c 100644 --- a/ipaserver/install/adtrust.py +++ b/ipaserver/install/adtrust.py @@ -14,10 +14,12 @@ from ipalib.constants import DOMAIN_LEVEL_0 from ipalib import errors +from ipalib.install.service import ServiceAdminInstallInterface from ipaplatform.paths import paths from ipapython.admintool import ScriptError from ipapython import ipaldap, ipautil from ipapython.dn import DN +from ipapython.install.core import knob from ipapython.ipa_log_manager import root_logger from ipaserver.install import adtrustinstance from ipaserver.install import service @@ -426,3 +428,51 @@ def install(standalone, options, fstore, api): # Find out IPA masters which are not part of the cn=adtrust agents # and propose them to be added to the list add_new_adtrust_agents(api, options) + + +class ADTrustInstallInterface(ServiceAdminInstallInterface): + """ + Interface for the AD trust installer + + Knobs defined here will be available in: + * ipa-server-install + * ipa-replica-install + * ipa-adtrust-install + """ + + # the following knobs are provided on top of those specified for + # admin credentials + add_sids = knob( + None, + description="Add SIDs for existing users and groups as the final step" + ) + add_agents = knob( + None, + description="Add IPA masters to a list of hosts allowed to " + "serve information about users from trusted forests" + ) + enable_compat = knob( + None, + description="Enable support for trusted domains for old clients" + ) + netbios_name = knob( + str, + None, + description="NetBIOS name of the IPA domain" + ) + no_msdcs = knob( + None, + description="Deprecated: has no effect", + deprecated=True + ) + rid_base = knob( + int, + 1000, + description="Start value for mapping UIDs and GIDs to RIDs" + ) + secondary_rid_base = knob( + int, + 100000000, + description="Start value of the secondary range for mapping " + "UIDs and GIDs to RIDs" + ) From 7e8f6b33ca5ddb8d07ede82353c4635f7afebefc Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 13:50:09 +0100 Subject: [PATCH 08/13] expose AD trust related knobs in composite installers --- ipaserver/install/server/__init__.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py index 86cb4a9..743da8d 100644 --- a/ipaserver/install/server/__init__.py +++ b/ipaserver/install/server/__init__.py @@ -38,13 +38,14 @@ from .replicainstall import promote_check as replica_promote_check from .upgrade import upgrade_check, upgrade -from .. import ca, conncheck, dns, kra +from .. import adtrust, ca, conncheck, dns, kra class ServerInstallInterface(client.ClientInstallInterface, ca.CAInstallInterface, kra.KRAInstallInterface, dns.DNSInstallInterface, + adtrust.ADTrustInstallInterface, conncheck.ConnCheckInterface): """ Interface of server installers @@ -144,6 +145,10 @@ def domain_level(self, value): "Domain Level cannot be higher than {0}".format( constants.MAX_DOMAIN_LEVEL)) + setup_adtrust = knob( + None, + description="configure AD trust capability" + ) setup_ca = knob( None, description="configure a dogtag CA", @@ -331,6 +336,11 @@ def dirsrv_config_file(self, value): ) pkinit_cert_name = prepare_only(pkinit_cert_name) + add_agents = knob( + bases=adtrust.ADTrustInstallInterface.add_agents + ) + add_agents = replica_install_only(add_agents) + def __init__(self, **kwargs): super(ServerInstallInterface, self).__init__(**kwargs) @@ -548,6 +558,10 @@ def dm_password(self, value): def admin_password(self, value): validate_admin_password(value) + # always run sidgen task and do not allow adding agents on first master + add_sids = True + add_agents = False + def __init__(self, **kwargs): super(ServerMasterInstall, self).__init__(**kwargs) master_init(self) From 2b8d375b139136a123f61ea8e65bf28428e4764a Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 13:50:36 +0100 Subject: [PATCH 09/13] Merge AD trust configurator into server installer ipa-server-install is now able to configure Samba and winbind services and manage trusts to Active Directory right off the bat with following alterations from standalone installer: * sidgen task is always triggered since there are only a few entries to tag in the beginning * the `--add-agents` option is hardcoded to False, as there are no potential agents to resolve and addd when setting up the first master in topology https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/server/install.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index dd04624..aa95cb5 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -32,7 +32,7 @@ ) import ipaclient.install.ntpconf from ipaserver.install import ( - bindinstance, ca, certs, dns, dsinstance, + adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance, installutils, kra, krbinstance, ntpinstance, otpdinstance, custodiainstance, replication, service, sysupgrade) @@ -386,6 +386,8 @@ def install_check(installer): print(" * Configure Apache (httpd)") if options.setup_dns: print(" * Configure DNS (bind)") + if options.setup_adtrust: + print(" * Configure Samba (smb) and winbind for managing AD trusts") if not options.no_pkinit: print(" * Configure the KDC to enable PKINIT") if options.no_ntp: @@ -610,6 +612,9 @@ def install_check(installer): network_ip_address_warning(ip_addresses) broadcast_ip_address_warning(ip_addresses) + if options.setup_adtrust: + adtrust.install_check(False, options, api) + # installer needs to update hosts file when DNS subsystem will be # installed or custom addresses are used if options.ip_addresses or options.setup_dns: @@ -636,16 +641,17 @@ def install_check(installer): )) print() - # If domain name and realm does not match, IPA server will not be able - # to estabilish trust with Active Directory. Print big fat warning. + if not options.setup_adtrust: + # If domain name and realm does not match, IPA server will not be able + # to estabilish trust with Active Directory. Print big fat warning. - realm_not_matching_domain = (domain_name.upper() != realm_name) + realm_not_matching_domain = (domain_name.upper() != realm_name) - if realm_not_matching_domain: - print("WARNING: Realm name does not match the domain name.\n" - "You will not be able to estabilish trusts with Active " - "Directory unless\nthe realm name of the IPA server matches " - "its domain name.\n\n") + if realm_not_matching_domain: + print("WARNING: Realm name does not match the domain name.\n" + "You will not be able to estabilish trusts with Active " + "Directory unless\nthe realm name of the IPA server matches " + "its domain name.\n\n") if installer.interactive and not user_input( "Continue to configure the system with these values?", False): @@ -855,6 +861,9 @@ def install(installer): no_dnssec_validation=options.no_dnssec_validation) bind.create_file_with_system_records() + if options.setup_adtrust: + adtrust.install(False, options, fstore, api) + # Set the admin user kerberos password ds.change_admin_password(admin_password) From b03c1f3639fb6550f4cf8f6db108047b62ad931f Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 13:51:00 +0100 Subject: [PATCH 10/13] Merge AD trust configurator into replica installer `ipa-replica-install` is now able to configure Samba and winbind services in order to manage Active Directory trusts. `--add-agents` option is exposed in replica installer, while `--add-sids` now defaults to `False` since adding a first AD trust controller to an existing sizeable deployment can result in stuck installation as sidgen tasks can take a long time to complete. That's why adding SIDs should be a conscious decision in this case. https://fedorahosted.org/freeipa/ticket/6630 --- ipaserver/install/server/replicainstall.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index c181258..3757700 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -38,7 +38,7 @@ ) from ipaclient.install.client import configure_krb5_conf, purge_host_keytab from ipaserver.install import ( - bindinstance, ca, certs, dns, dsinstance, httpinstance, + adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance, installutils, kra, krbinstance, ntpinstance, otpdinstance, custodiainstance, service) from ipaserver.install.installutils import ( @@ -862,6 +862,9 @@ def install_check(installer): network_ip_address_warning(config.ips) broadcast_ip_address_warning(config.ips) + if options.setup_adtrust: + adtrust.install_check(False, options, remote_api) + enroll_dl0_replica(installer, fstore, remote_api) ccache = os.environ['KRB5CCNAME'] kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env), @@ -1283,6 +1286,9 @@ def promote_check(installer): network_ip_address_warning(config.ips) broadcast_ip_address_warning(config.ips) + if options.setup_adtrust: + adtrust.install_check(False, options, remote_api) + except errors.ACIError: root_logger.debug(traceback.format_exc()) raise ScriptError("\nInsufficient privileges to promote the server." @@ -1473,6 +1479,10 @@ def install(installer): dns.install(False, True, options, api) else: api.Command.dns_update_system_records() + + if options.setup_adtrust: + adtrust.install(False, options, fstore, api) + api.Backend.ldap2.disconnect() if not promote: From 3a56356ea262faef71849eb986dc3ea2deb6b652 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 17:04:53 +0100 Subject: [PATCH 11/13] Fix erroneous short name options in ipa-adtrust-install man page `--rid-base` and `--secondary-rid-base` had `-U` option assigned by error in the man page. Remove it as these options have not short alias. https://fedorahosted.org/freeipa/ticket/6630 --- install/tools/man/ipa-adtrust-install.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/tools/man/ipa-adtrust-install.1 b/install/tools/man/ipa-adtrust-install.1 index 6e8438b..058422b 100644 --- a/install/tools/man/ipa-adtrust-install.1 +++ b/install/tools/man/ipa-adtrust-install.1 @@ -101,12 +101,12 @@ version 1.13 on IPA master is required to be able to perform as a trust agent. \fB\-U\fR, \fB\-\-unattended\fR An unattended installation that will never prompt for user input .TP -\fB\-U\fR, \fB\-\-rid-base\fR=\fIRID_BASE\fR +\fB\-\-rid-base\fR=\fIRID_BASE\fR First RID value of the local domain. The first Posix ID of the local domain will be assigned to this RID, the second to RID+1 etc. See the online help of the idrange CLI for details. .TP -\fB\-U\fR, \fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR +\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR Start value of the secondary RID range, which is only used in the case a user and a group share numerically the same Posix ID. See the online help of the idrange CLI for details. From 19edfbe24abfe3c07bec984f6b5f990260df2cee Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Fri, 17 Feb 2017 17:06:42 +0100 Subject: [PATCH 12/13] Update server/replica installer man pages Since AD trust installer is now a part of composite installers, their man pages were updated with separate section documenting relevant AD trust-related option descriptions. https://fedorahosted.org/freeipa/ticket/6630 --- install/tools/man/ipa-replica-install.1 | 64 +++++++++++++++++++++++++++++++++ install/tools/man/ipa-server-install.1 | 44 +++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 index 2c09666..f9ebd87 100644 --- a/install/tools/man/ipa-replica-install.1 +++ b/install/tools/man/ipa-replica-install.1 @@ -199,6 +199,70 @@ Do not automatically create DNS SSHFP records. \fB\-\-no\-dnssec\-validation\fR Disable DNSSEC validation on this server. +.SS "AD TRUST OPTIONS" +.TP +\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR +The NetBIOS name for the IPA domain. If not provided then this is determined +based on the leading component of the DNS domain name. Running +ipa\-adtrust\-install for a second time with a different NetBIOS name will +change the name. Please note that changing the NetBIOS name might break +existing trust relationships to other domains. +.TP +\fB\-\-add\-sids\fR +Add SIDs to existing users and groups as on of final steps of the +ipa\-adtrust\-install run. If there a many existing users and groups and a +couple of replicas in the environment this operation might lead to a high +replication traffic and a performance degradation of all IPA servers in the +environment. To avoid this the SID generation can be run after +ipa\-adtrust\-install is run and scheduled independently. To start this task +you have to load an edited version of ipa-sidgen-task-run.ldif with the +ldapmodify command info the directory server. +.TP +\fB\-\-add\-agents\fR +Add IPA masters to the list that allows to serve information about +users from trusted forests. Starting with FreeIPA 4.2, a regular IPA master +can provide this information to SSSD clients. IPA masters aren't added +to the list automatically as restart of the LDAP service on each of them +is required. The host where ipa\-adtrust\-install is being run is added +automatically. +.IP +Note that IPA masters where ipa\-adtrust\-install wasn't run, can serve +information about users from trusted forests only if they are enabled +via \ipa-adtrust\-install run on any other IPA master. At least SSSD +version 1.13 on IPA master is required to be able to perform as a trust agent. +.TP +\fB\-\-rid-base\fR=\fIRID_BASE\fR +First RID value of the local domain. The first Posix ID of the local domain will +be assigned to this RID, the second to RID+1 etc. See the online help of the +idrange CLI for details. +.TP +\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR +Start value of the secondary RID range, which is only used in the case a user +and a group share numerically the same Posix ID. See the online help of the +idrange CLI for details. +.TP +\fB\-\-enable\-compat\fR +Enables support for trusted domains users for old clients through Schema Compatibility plugin. +SSSD supports trusted domains natively starting with version 1.9. For platforms that +lack SSSD or run older SSSD version one needs to use this option. When enabled, slapi\-nis package +needs to be installed and schema\-compat\-plugin will be configured to provide lookup of +users and groups from trusted domains via SSSD on IPA server. These users and groups will be +available under \fBcn=users,cn=compat,$SUFFIX\fR and \fBcn=groups,cn=compat,$SUFFIX\fR trees. +SSSD will normalize names of users and groups to lower case. +.IP +In addition to providing these users and groups through the compat tree, this option enables +authentication over LDAP for trusted domain users with DN under compat tree, i.e. using bind DN +\fBuid=administrator@ad.domain,cn=users,cn=compat,$SUFFIX\fR. +.IP +LDAP authentication performed by the compat tree is done via PAM '\fBsystem\-auth\fR' service. +This service exists by default on Linux systems and is provided by pam package as /etc/pam.d/system\-auth. +If your IPA install does not have default HBAC rule 'allow_all' enabled, then make sure +to define in IPA special service called '\fBsystem\-auth\fR' and create an HBAC +rule to allow access to anyone to this rule on IPA masters. +.IP +As '\fBsystem\-auth\fR' PAM service is not used directly by any other +application, it is safe to use it for trusted domain users via compatibility +path. .SH "EXIT STATUS" 0 if the command was successful diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 index a7c7f81..cd68f72 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -195,6 +195,49 @@ Disable DNSSEC validation on this server. \fB\-\-allow\-zone\-overlap\fR Allow creatin of (reverse) zone even if the zone is already resolvable. Using this option is discouraged as it result in later problems with domain name resolution. +.SS "AD TRUST OPRIONS" + +.TP +\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR +The NetBIOS name for the IPA domain. If not provided then this is determined +based on the leading component of the DNS domain name. Running +ipa\-adtrust\-install for a second time with a different NetBIOS name will +change the name. Please note that changing the NetBIOS name might break +existing trust relationships to other domains. +.TP +\fB\-\-rid-base\fR=\fIRID_BASE\fR +First RID value of the local domain. The first Posix ID of the local domain will +be assigned to this RID, the second to RID+1 etc. See the online help of the +idrange CLI for details. +.TP +\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR +Start value of the secondary RID range, which is only used in the case a user +and a group share numerically the same Posix ID. See the online help of the +idrange CLI for details. +.TP +\fB\-\-enable\-compat\fR +Enables support for trusted domains users for old clients through Schema Compatibility plugin. +SSSD supports trusted domains natively starting with version 1.9. For platforms that +lack SSSD or run older SSSD version one needs to use this option. When enabled, slapi\-nis package +needs to be installed and schema\-compat\-plugin will be configured to provide lookup of +users and groups from trusted domains via SSSD on IPA server. These users and groups will be +available under \fBcn=users,cn=compat,$SUFFIX\fR and \fBcn=groups,cn=compat,$SUFFIX\fR trees. +SSSD will normalize names of users and groups to lower case. +.IP +In addition to providing these users and groups through the compat tree, this option enables +authentication over LDAP for trusted domain users with DN under compat tree, i.e. using bind DN +\fBuid=administrator@ad.domain,cn=users,cn=compat,$SUFFIX\fR. +.IP +LDAP authentication performed by the compat tree is done via PAM '\fBsystem\-auth\fR' service. +This service exists by default on Linux systems and is provided by pam package as /etc/pam.d/system\-auth. +If your IPA install does not have default HBAC rule 'allow_all' enabled, then make sure +to define in IPA special service called '\fBsystem\-auth\fR' and create an HBAC +rule to allow access to anyone to this rule on IPA masters. +.IP +As '\fBsystem\-auth\fR' PAM service is not used directly by any other +application, it is safe to use it for trusted domain users via compatibility +path. + .SS "UNINSTALL OPTIONS" .TP \fB\-\-uninstall\fR @@ -215,3 +258,4 @@ The kerberos master password (normally autogenerated). .SH "SEE ALSO" .BR ipa-dns-install (1) +.BR ipa-adtrust-install (1) From 936d286dbe604d22327217c22d174635ad2bb522 Mon Sep 17 00:00:00 2001 From: Martin Babinsky <mbabi...@redhat.com> Date: Mon, 20 Feb 2017 15:17:11 +0100 Subject: [PATCH 13/13] Provide basic integration tests for built-in AD trust installer A couple of tests were added to server/replica install integration suite to test AD trust install w/ various combinations of other optional components. https://fedorahosted.org/freeipa/ticket/6630 --- ipatests/test_integration/tasks.py | 15 +++++--- ipatests/test_integration/test_installation.py | 49 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/ipatests/test_integration/tasks.py b/ipatests/test_integration/tasks.py index 9523450..6620d12 100644 --- a/ipatests/test_integration/tasks.py +++ b/ipatests/test_integration/tasks.py @@ -249,9 +249,9 @@ def enable_replication_debugging(host): stdin_text=logging_ldif) -def install_master(host, setup_dns=True, setup_kra=False, extra_args=(), - domain_level=None, unattended=True, stdin_text=None, - raiseonerr=True): +def install_master(host, setup_dns=True, setup_kra=False, setup_adtrust=False, + extra_args=(), domain_level=None, unattended=True, + stdin_text=None, raiseonerr=True): if domain_level is None: domain_level = host.config.domain_level setup_server_logs_collecting(host) @@ -275,6 +275,8 @@ def install_master(host, setup_dns=True, setup_kra=False, extra_args=(), '--forwarder', host.config.dns_forwarder, '--auto-reverse' ]) + if setup_adtrust: + args.append('--setup-adtrust') args.extend(extra_args) result = host.run_command(args, raiseonerr=raiseonerr, @@ -343,8 +345,9 @@ def replica_prepare(master, replica, extra_args=(), def install_replica(master, replica, setup_ca=True, setup_dns=False, - setup_kra=False, extra_args=(), domain_level=None, - unattended=True, stdin_text=None, raiseonerr=True): + setup_kra=False, setup_adtrust=False, extra_args=(), + domain_level=None, unattended=True, stdin_text=None, + raiseonerr=True): if domain_level is None: domain_level = domainlevel(master) apply_common_fixes(replica) @@ -367,6 +370,8 @@ def install_replica(master, replica, setup_ca=True, setup_dns=False, '--setup-dns', '--forwarder', replica.config.dns_forwarder ]) + if setup_adtrust: + args.append('--setup-adtrust') if master_authoritative_for_client_domain(master, replica): args.extend(['--ip-address', replica.ip]) diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py index 0929f13..f3e9eba 100644 --- a/ipatests/test_integration/test_installation.py +++ b/ipatests/test_integration/test_installation.py @@ -84,6 +84,29 @@ def test_replica2_ipa_kra_install(self): tasks.install_kra(self.replicas[2]) +class ADTrustInstallTestBase(IntegrationTest): + """ + Base test for builtin AD trust installation im combination with other + components + """ + num_replicas = 2 + topology = 'star' + + @classmethod + def install(cls, mh): + tasks.install_master(cls.master, setup_dns=False) + + def install_replica(self, replica, **kwargs): + tasks.install_replica(self.master, replica, setup_adtrust=True, + **kwargs) + + def test_replica0_only_adtrust(self): + self.install_replica(self.replicas[0], setup_ca=False) + + def test_replica1_all_components_adtrust(self): + self.install_replica(self.replicas[1], setup_ca=True) + + ## # Master X Replicas installation tests ## @@ -213,6 +236,32 @@ def install(cls, mh): tasks.install_master(cls.master, setup_dns=True, setup_kra=True) +class TestADTrustInstall(ADTrustInstallTestBase): + """ + Tests built-in AD trust installation in various combinations (see the base + class for more details) against plain IPA master (no DNS, no KRA, no AD + trust) + """ + pass + + +class TestADTrustInstallWithDNS_KRA_ADTrust(ADTrustInstallTestBase): + """ + Tests built-in AD trust installation in various combinations (see the base + class for more details) against fully equipped (DNS, CA, KRA, ADtrust) + master. Additional two test cases were added to test interplay including + KRA installer + """ + + @classmethod + def install(cls, mh): + tasks.install_master(cls.master, setup_dns=True, setup_kra=True, + setup_adtrust=True) + + def test_replica1_all_components_adtrust(self): + self.install_replica(self.replicas[1], setup_ca=True, setup_kra=True) + + ## # Rest of master installation tests ##
-- 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