FreeNAS, FreeIPA, Samba and Kerberos

As a foreword: the below solution is not recommended - it relies on a prerelease version of FreeNAS for some of its functionality, which isn't supported.

FreeNAS 10 comes with the ability to bind to a FreeIPA directory. Hooray! Let's try it out.


Struggling with binding to the directory

Hmm, using the GUI to bind to the directory doesn't seem to work at all, or even create the entry. Let's try the CLI instead.

After spending a few minutes learning how the CLI works, I got it down to the following commands:

freenas# cli
Welcome to the FreeNAS CLI! Type 'help' to get started.

[...snip...]

unix::>directoryservice directories
unix::/directoryservice/directories>create media type=freeipa enumerate=yes enabled=no
unix::/directoryservice/directories>media properties
unix::/directoryservice/directories/media/properties>set realm=media.su.ic.ac.uk username=<privileged username> password=<privileged password> server=cog.media.su.ic.ac.uk
unix::/directoryservice/directories/media/properties>..
unix::/directoryservice/directories/media>set enabled=yes

Turns out that because of the setup (the SRV records are misconfigured if you're doing a Kerberos bind to the LDAP server - the LDAP server doesn't have a keytab for ldap.media.su.ic.ac.uk), you need to set the server property or FreeNAS gives you some random Python exception. Ho hum.

Having bound to the directory you can set things up as usual on a FreeNAS system, creating shares, but wait...

FreeNAS doesn't seem to respect groups

There appears to be a bug in FreeNAS' dscache plugin for FreeIPA -- it doesn't find any groups other than the main POSIX group.

At a first glance, this appears to be because it's searching for all groups by dn, which isn't a property you can filter on in an LDAP search. Bah.

I applied the following patch. I should probably contribute this back to https://github.com/freenas/middleware...

diff -u a/FreeIPAPlugin.py b/FreeIPAPlugin.py
--- a/FreeIPAPlugin.py	2017-02-19 18:46:41.508852583 +0000
+++ b/FreeIPAPlugin.py	2017-02-19 18:48:03.768854453 +0000
@@ -32,6 +32,7 @@
 import logging
 import errno
 import krb5
+from collections import defaultdict
 from threading import Thread, Condition
 from datetime import datetime
 from plugin import DirectoryServicePlugin, DirectoryState
@@ -55,6 +56,14 @@
 logger = logging.getLogger(__name__)
 
 
+def _split_bases(dns):
+    out = defaultdict(list) 
+    for dn in dns:
+        rdn, _, base_dn = dn.partition(',')
+        out[base_dn].append(rdn)
+    return out
+
+
 class FreeIPAPlugin(DirectoryServicePlugin):
     def __init__(self, context):
         self.context = context
@@ -124,14 +133,13 @@
                 group = dict(ret['attributes'])
 
         if get(entry, 'memberOf'):
-            builder = LdapQueryBuilder()
-            qstr = builder.build_query([
-                ('dn', 'in', get(entry, 'memberOf'))
-            ])
-
-            for r in self.search(self.base_dn, qstr):
-                r = dict(r['attributes'])
-                groups.append(get(r, 'ipaUniqueID.0'))
+            for base_dn, rdns in _split_bases(get(entry, 'memberOf')).items():
+                qstr = '(|({0}))'.format(')('.join(rdns))
+
+                for r in self.search(base_dn, qstr):
+                    r = dict(r['attributes'])
+                    if get(r, 'ipaUniqueID.0'):
+                        groups.append(get(r, 'ipaUniqueID.0'))
 
         if contains(entry, 'ipaNTHash'):
             nthash = binascii.hexlify(entry['ipaNTHash']).decode('ascii')

One cli system reboot later, groups leg13 is now correctly showing all of my groups. Hurrah!

Authenticating Samba against passwords

By default, however, this setup won't work, since FreeNAS won't have permission to read the ipaNTHash attribute on users. Per https://bugs.freenas.org/issues/19976#note-24, the following commands sort that out too:

freeipa$ ipa permission-add 'ipaNTHash service read' --attrs=ipaNTHash --type=user  --right=read
freeipa$ ipa privilege-add 'SMB services'
freeipa$ ipa privilege-add-permission 'SMB services' --permissions='ipaNTHash service read'
freeipa$ ipa role-add trustagent --desc="Trust agent (e.g. Samba servers)"
freeipa$ ipa role-add-privilege trustagent --privileges='SMB services'
freeipa$ ipa role-add-member trustagent --users=<trusted binding user>

To check, use:

freenas# dispatcherctl call dscached.account.getpwnam '"admin"'

which should show non-null entries for "nthash" and "sid".

and

freenas# pdbedit -Lw admin

which shouldn't show Xs in the fourth column.

Authenticating Samba against FreeIPA Kerberos

This is all well and good, but it would be nice if clients with valid Kerberos tickets could also authenticate...

First, FreeIPA needs to know about the FreeNAS server, since FreeNAS doesn't do a "proper" directory bind:

freeipa$ ipa host-add sparkplug.media.su.ic.ac.uk
freeipa$ ipa service-add cifs/sparkplug.media.su.ic.ac.uk
freeipa$ ipa service-add-host cifs/sparkplug.media.su.ic.ac.uk --hosts=sparkplug.media.su.ic.ac.uk

Then, you can fetch a keytab for it:

freeipa$ ipa-getkeytab -p cifs/sparkplug.media.su.ic.ac.uk -k sparkplug.kt

Communicate this to some location (I used /root/sparkplug.kt) on the FreeNAS box, then:

freenas# cli

unix::>directoryservice kerberos keytab
unix::/directoryservice/kerberos/keytab>create cifs keytab=/root/sparkplug.kt

This will add the keys in the keytab to /etc/krb5.keytab. Excellent.

Now we need to configure Samba on FreeNAS to respect the Keytab:

freenas# net conf setparm global 'realm' 'MEDIA.SU.IC.AC.UK'
freenas# net conf setparm global 'kerberos method' 'system keytab'
freenas# net conf setparm global 'security' 'ads'

...and that should be that!