--- title: FreeNAS, FreeIPA, Samba and Kerberos date: 2017-02-19 layout: Post tags: - university tech --- 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: ```txt 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= 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 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: ```txt 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= ``` To check, use: ```txt freenas# dispatcherctl call dscached.account.getpwnam '"admin"' ``` which should show non-`null` entries for `"nthash"` and `"sid"`. and ```txt 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: ```txt 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: ```txt 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: ```txt 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: ```txt 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!