[Freeipa-devel] [RFE] Multiple trust servers per realm

Alexander Bokovoy abokovoy at redhat.com
Fri Mar 8 13:16:26 UTC 2013


Hi,

http://www.freeipa.org/page/V3/MultipleTrustServers covers RFE to have
multiple domain controllers exposed to trusted domains.

Attached patch also implements needed changes for ipa-adtrust-install
part. Global trust configuration options are already implemented and
available in git master, while Web UI support for them needs to be
added.

The patch attached actually fixes our current (rather wrong) way of
exposing all LDAP- and Kerberos-related SRV records to default site
configuration and _msdcs SRV namespace. This was wrong because it
assumed that all servers mentioned in SRV records could be domain
controllers, that is, they are usable to contact over SMB protocol.
The latter isn't true until we ran ipa-adtrust-install on them.

The patch only exposes those servers which manage cifs/fqdn at REALM
services and only if those services are also members of cn=adtrust
agents container. This is fairly strict filter and it allows also to
have other types of SMB servers as part of the realm.

Below is a copy of the RFE:
==================================================================
__NOTOC__

= Overview =

Ticket [https://fedorahosted.org/freeipa/ticket/2189 #2189];

Each FreeIPA server in the realm has potential to serve as domain
controller in the cross-forest realm trust. This page outlines design
for implementing multiple servers support in FreeIPA.

= Use Cases =

Once <tt>ipa-adtrust-install</tt> ran on the FreeIPA server, the server
can handle requests from trusted domains by means of Samba project's
<tt>smbd</tt> and <tt>winbindd</tt> daemons.

Hosts in FreeIPA realm may be enrolled against specific FreeIPA replica
server. User from trusted domain can access these hosts and their
identities will be resolved against the replica. However, if replica
server does not have trust support configured, these identities will not
be processed since running <tt>winbindd</tt> process is required to
contact the trusted domain's domain controllers and Global Catalog
servers.

Domain controllers are advertised to clients via SRV records in DNS.
Since replica servers may be arranged in a specific topology, adding new
domain controller would need to respect the topology design. It means
priority/weight of the domain controller compared to other domain
controllers should be adjustable. Prime use case for this is branch
office deployments.

= Design= 

* Each domain controller uses separate identity and service key to talk
   to FreeIPA LDAP server. The identity is tied to the server hostname.

* Service principal is <tt>cifs/hostname at REALM</tt>, identified in LDAP
   as <tt>krbprincipalname=cifs/hostname at REALM</tt>.

* All identities are members of <tt>cn=adtrust
   agents</tt>,<tt>cn=sysaccounts</tt>,<tt>cn=etc</tt>,<tt>$SUFFIX</tt>.
   Thus, all replica servers can see what other servers are providing
   domain controller service.

* Replica server only becomes domain controller when
   <tt>ipa-adtrust-install</tt> utility was executed on it. It means all
   DC setup is delivered via the <tt>ipa-adtrust-install</tt>.

* <tt>ipa-adtrust-install</tt> should be able to detect other DCs by
   looking at existing identities as members of the <tt>cn=adtrust
   agents</tt>,<tt>cn=sysaccounts</tt>,<tt>cn=etc</tt>,<tt>$SUFFIX</tt>
   tree and modify list of SRV records under <tt>_msdcs</tt> and default
   site configuration if DNS is controlled by FreeIPA.

* Domain Controller priority/weight can be modified at run time since it
   only affects SRV records in the DNS (if FreeIPA controls the DNS).
   Normal <tt>ipa dnsrecord-mod</tt> commands should be used for this
   purpose, operating on SRV records for <tt>_msdcs</tt> and default site
   configuration.

* There are trust properties that are global for the realm. Some of them
   are modifiable, some not. Thus, <tt>ipa trustconfig-show</tt> and
   <tt>ipa trustconfig-mod</tt> should reflect both global and local
   settings (realm-wise and DC-wise).

* Following properties of the trust are global for the realm:
** NetBIOS domain name (read-only, affects existing trusts)
** Domain name (read-only, affects existing trusts)
** Domain GUID (read-only, informational)
** Additional domain suffixes exposed to the trusted party, handled as
    black list against global list of additional domains associated with our
    or transitive realm, read/write
** Fallback primary group (read-write)

* Following properties of the trust are per Domain Controller:
** priority of the DC and GC services (read-write, DNS SRV record)

Details on <tt>ipa trustconfig</tt> commands design are available at
http://www.freeipa.org/page/V3/Trust_config_command
Details on additional domain suffixes handling are available at
http://www.freeipa.org/page/V3/Domain_suffixes

= Implementation =
Implementation-wise there are three parts:

* <tt>ipa-adtrust-install</tt>:
** Gather list of CIFS services that are also members of <tt>cn=adtrust
    agents</tt> and add SRV records for them to _msdcs in
    ipaserver/install/adtrustinstance.py:ADTrustInstance::__add_dns_service_records().
** Once Global Catalog Server implementation will be ready, configure
    its use as one of <tt>ADTrustInstance</tt> setup steps.

* <tt>IPA framework</tt>:
** Add display and modification of trust properties as <tt>ipa
    trustconfig-*</tt> commands, including listing DC and GC servers.
** NOTE: there is no need to modify trust creation procedure since it
appears that AD DC assumes LSA CreateTrustedDomainEx2 call comes from
the DC (in Windows the UI to establish trust is only on DC) and
therefore does not do DNS discovery during validation step. Since smbd
running on the same host that 'ipa trust-add' runs on will contact the
same host's LDAP server, there is no issue in replication at this stage.

* <tt>IPA Web UI</tt>
** Add support for <tt>ipa trustconfig-*</tt> to Web UI.

= Major configuration options and enablement =
No additional options to <tt>ipa-adtrust-install</tt>

= Replication =
All data is already in a replicated namespace.

= Updates and Upgrades =
No changes to schema, no need to run anything additional on updates or
upgrades

= Dependencies =
No additional dependencies beyond AD trusts support

= External Impact =
Once <tt>ipa-adtrust-install</tt> install ran on replica, the replica
will be advertised via <tt>_msdcs</tt> SRV namespace as a domain
controller.
==================================================================


-- 
/ Alexander Bokovoy
-------------- next part --------------
>From 8f258dd0720fc0ca451200c6cd4afa301ec5d593 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Wed, 6 Mar 2013 10:12:40 +0200
Subject: [PATCH 1/2] Enhance ipa-adtrust-install for domains with multiple IPA
 server

As described on http://www.freeipa.org/page/V3/MultipleTrustServers,
notice if FreeIPA server is a replica and adtrust agents contains members
corresponding to the cifs/ services from replication partners. 

Only these servers will be advertised as SMB domain controllers

https://fedorahosted.org/freeipa/ticket/2189
---
 ipaserver/install/adtrustinstance.py | 44 +++++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 794b788..a47c80b 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -477,6 +477,9 @@ class ADTRUSTInstance(service.Service):
         except ipautil.CalledProcessError, e:
             root_logger.critical("Failed to add key for %s" % self.cifs_principal)
 
+    def srv_rec(self, host, port, prio):
+        return "%(prio)d 100 %(port)d %(host)s" % dict(host=host,prio=prio,port=port)
+
     def __add_dns_service_records(self):
         """
         Add DNS service records for Windows if DNS is enabled and the DNS zone
@@ -486,11 +489,12 @@ class ADTRUSTInstance(service.Service):
 
         zone = self.domain_name
         host = self.fqdn.split(".")[0]
+        priority = 0
 
         ipa_srv_rec = (
-            ("_ldap._tcp", ["0 100 389 %s" % host]),
-            ("_kerberos._tcp", ["0 100 88 %s" % host]),
-            ("_kerberos._udp", ["0 100 88 %s" % host])
+            ("_ldap._tcp", [self.srv_rec(host, 389, priority)], 389),
+            ("_kerberos._tcp", [self.srv_rec(host, 88, priority)], 88),
+            ("_kerberos._udp", [self.srv_rec(host, 88, priority)], 88),
         )
         win_srv_suffix = (".Default-First-Site-Name._sites.dc._msdcs",
                           ".dc._msdcs")
@@ -518,10 +522,12 @@ class ADTRUSTInstance(service.Service):
                     self.print_msg(" - %s%s"  % (srv, suff))
             return
 
-        for (srv, rdata) in ipa_srv_rec:
-            ipa_rdata = get_rr(zone, srv, "SRV")
-            if not ipa_rdata:
-                ipa_rdata = rdata
+        for (srv, rdata, port) in ipa_srv_rec:
+            cifs_rdata = list()
+            for fqdn in self.cifs_hosts:
+                cifs_srv = self.srv_rec(fqdn, port, priority)
+                cifs_rdata.append(cifs_srv)
+            cifs_rdata.extend(rdata)
 
             for suff in win_srv_suffix:
                 win_srv = srv+suff
@@ -529,7 +535,7 @@ class ADTRUSTInstance(service.Service):
                 if win_rdata:
                     for rec in win_rdata:
                         del_rr(zone, win_srv, "SRV", rec)
-                for rec in ipa_rdata:
+                for rec in cifs_rdata:
                     add_rr(zone, win_srv, "SRV", rec)
 
     def __configure_selinux_for_smbd(self):
@@ -618,7 +624,27 @@ class ADTRUSTInstance(service.Service):
             self.print_msg("'dns_lookup_kdc' already set to 'true', "
                            "nothing to do.")
 
+    def __check_replica(self):
+        try:
+            cifs_services = DN(api.env.container_service, self.suffix)
+            # Search for cifs services which also belong to adtrust agents, these are our DCs
+            res = self.admin_conn.get_entries(cifs_services,
+                ldap.SCOPE_ONELEVEL,
+                "(&(krbprincipalname=cifs/*@%s)(memberof=%s))" % (self.realm, str(self.smb_dn)))
+            if len(res) > 1:
+                # there are other CIFS services defined, we are not alone
+                for entry in res:
+                    managedBy = entry.single_value('managedBy', None)
+                    if managedBy:
+                        fqdn = DN(managedBy)['fqdn']
+                        if fqdn != unicode(self.fqdn):
+                            # this is CIFS service of a different host in our
+                            # REALM, we need to remember it to announce via
+                            # SRV records for _msdcs
+                            self.cifs_hosts.append(fqdn.split(".")[0])
 
+        except Exception, e:
+            root_logger.critical("Checking replicas for cifs principals failed with error '%s'" % e)
 
     def __start(self):
         try:
@@ -698,6 +724,7 @@ class ADTRUSTInstance(service.Service):
                              api.env.container_service,
                              self.suffix)
         self.selinux_booleans = ["samba_portmapper"]
+        self.cifs_hosts = list()
 
         self.__setup_sub_dict()
 
@@ -755,6 +782,7 @@ class ADTRUSTInstance(service.Service):
         self.step("creating samba config registry", self.__write_smb_registry)
         self.step("writing samba config file", self.__write_smb_conf)
         self.step("adding cifs Kerberos principal", self.__setup_principal)
+        self.step("check for cifs services defined on other replicas", self.__check_replica)
         self.step("adding cifs principal to S4U2Proxy targets", self.__add_s4u2proxy_target)
         self.step("adding admin(group) SIDs", self.__add_admin_sids)
         self.step("adding RID bases", self.__add_rid_bases)
-- 
1.8.1.4



More information about the Freeipa-devel mailing list