Configuring Active Directory authentication integration – Building an OpenIndiana based ZFS File Server – part 3

Getting Kerberos based authentication working with Active Directory is actually pretty simple, there’s numerous blogs out there on the topic, here, here, here and here, so I’m probably mostly covering old ground on the basic integration stuff.

Our Active Directory already has Schema extentions to hold Unix account data, initially Services for Unix (SFU), but we added the Server 2008 schema which adds RFC 2307 attributes which we now use for Linux authentication.

First off, I should point out that we have a disjoint DNS namespace for our AD and normal client DNS. i.e. our AD is socs-ad.cs.bham.ac.uk, but our clients are all in cs.bham.ac.uk. This shouldn’t really cause any problems for most people (I’ve only come across 3 cases, 1: back in about 2003 where a NetApp filer couldn’t work out the DNS name as it didn’t match the netbios name … fixed a long time ago, 2: about 18 months ago when experimenting with SCCM and AMT provisioning – it doesn’t support disjoint DNS, 3: with the OI in-kernel CIFS server … in part 5!).

First off, we need to configure some config files:

/etc/resolv.conf
  domain  cs.bham.ac.uk
  search cs.bham.ac.uk socs-ad.cs.bham.ac.uk
  nameserver  147.188.192.4
  nameserver  147.188.192.8
cp /etc/inet/ntp.client /etc/inet/ntp.conf
/etc/inet/ntp.conf
  server ad1.cs.bham.ac.uk ad2.cs.bham.ac.uk timehost.cs.bham.ac.uk

The first two are our DCs, the latter a general NTP servers – all should be pretty much in step though!

Finally, enable ntp:

svcadm enable ntp

To help with Kerberos principle generation, I grabbed a copy of adjoin. Note that because we have a disjoint namespace, I had to hack it a little otherwise it tries to add the full Windows domain to the hostname in the SPNs:

###fqdn=${nodename}.$dom
fqdn=bigstore.cs.bham.ac.uk
./adjoin -f

Check you have a correct looking machine principle file

klist -e -k /etc/krb5/krb5.keytab

And enable a couple of services we’ll need:

svcadm enable /network/dns/client
svcadm enable /system/name-service-cache

We also need to configure pam.conf to use Kerberos, so you need to add a couple of lines similar to:

 other   auth required           pam_unix_cred.so.1
 other auth sufficient pam_krb5.so.1 debug
 other   auth required           pam_unix_auth.so.1
 other   account requisite       pam_roles.so.1
 other account required pam_krb5.so.1 debug nowarn
 other   account required        pam_unix_account.so.1
 other   password requisite      pam_authtok_check.so.1
 other password sufficient pam_krb5.so.1 debug
 other   password required       pam_authtok_store.so.1

The debug is optional to help with debugging why things aren’t working. The nowarn on the middle example is needed to stop a password expiry warning on each password based login – our AD passwords are set to never expire, but without this, it warns about expiry in 9244 days.

We now need to edit a file to be able to allow us to configure LDAP for passwd/group data, we want to remove all references to ldap except for passwd, group and automount:

/etc/nsswitch.ldap
  passwd:     files ldap
  group:      files ldap
  hosts:      files dns
  ipnodes:    files dns
  automount:  files ldap

Before we go any further, we also need to tweak the krb5 config:

/etc/krb5.conf
  [libdefaults]
    default_tkt_enctypes = rc4-hmac arcfour-hmac arcfour-hmac-md5
    default_tgs_enctypes = rc4-hmac arcfour-hmac arcfour-hmac-md5
    permitted_enctypes = rc4-hmac arcfour-hmac arcfour-hmac-md5

You might not need to do this, our DCs are quite old running Server 2003, without this, Kerberos authentication wouldn’t work.

We now need to configure LDAP:

 ldapclient -v manual \
 -a credentialLevel=self \
 -a authenticationMethod=sasl/gssapi \
 -a defaultSearchBase=dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk \
 -a defaultSearchScope=sub \
 -a domainName=socs-ad.cs.bham.ac.uk \
 -a defaultServerList="ad1.socs-ad.cs.bham.ac.uk ad2.socs-ad.cs.bham.ac.uk" \
 -a attributeMap=passwd:gecos=ad1.socs-ad.cs.bham.ac.uk \
 -a attributeMap=passwd:homedirectory=unixHomeDirectory \
 -a attributeMap=passwd:uid=sAMAccountName \
 -a attributeMap=group:uniqueMember=member \
 -a attributeMap=group:cn=sAMAccountName \
 -a objectClassMap=group:posixGroup=group \
 -a objectClassMap=passwd:posixAccount=user \
 -a objectClassMap=shadow:shadowAccount=user \
 -a serviceSearchDescriptor='passwd:ou=people,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk?sub' \
 -a serviceSearchDescriptor='shadow:ou=people,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk?sub?memberOf=CN=sysop,OU=Groups of People,OU=Groups,DC=socs-ad,DC=cs,DC=bham,DC=ac,DC=uk' \
 -a serviceSearchDescriptor='group:ou=groups,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk?sub?(&(objectClass=group)(gidNumber=*))'

You’d need to tweak it for your environment of course. Importantly, you need the bit

(&(objectClass=group)(gidNumber=*))

for the group serviceSearchDescriptor, otherwise you’ll get spurious results if you have groups with no gidNumber assigned. Ideally we’d also have similar filters for passwd and shadow, but that didn’t seem to work properly.

Restart the nscd daemon:

svcadm enable name-service-cache

You could try doing an LDAP search with something like:

ldapsearch -R -T -h ad1.socs-ad.cs.bham.ac.uk -o authzid= -o mech=gssapi -b dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk -s sub cn=jaffle

and also getent should now work

getent passwd
getent group

Restricting login access

So, we’ve managed to integrate our password data on the server – pretty much we need to have access to all our directory users for NFS to work properly so that usernames and UIDs match, however this means anyone can login to the server. There’s no equivalent of Linux’s pam_access, and there doesn’t appear to be any native way of specifying Unix groups of people who can login to the system. The closest I found was pam_list, however this only works with netgroups, and as we don’t use these for anything anymore, they were never migrated to our AD, and anyway, we’ve got perfectly good Unix groups of people to use on our other systems.

After running round in circles for a while, and almost creating netgroups, I came across a solution that seems to work nicely. Its a bit of a hack, but actually it quite a nice solution for us. The key is in the ldapclient definition for shadow:

-a serviceSearchDescriptor='shadow:ou=people,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk?sub?memberOf=CN=sysop,OU=Groups of People,OU=Groups,DC=socs-ad,DC=cs,DC=bham,DC=ac,DC=uk'

Note that we add an LDAP filter requiring membership of a specific LDAP group, this means that shadow data is only present for the members of that group and hey presto – we’ve got Unix group based authorisation working on OpenIndiana. If you wanted multiple groups, you’d have to tweak the filter with some parenthesis and a | probably …

And automount/autofs?

Autofs from LDAP was a little bit more complicated to get going, probably complicated a bit as we have Linux format/named autofs maps in our AD. Technically we don’t need this bit working for our file-server, but we thought for completeness, we’d investigate the options for it.

First off, we’ll edit a couple of files:

/etc/auto_home
  #+auto_home

/etc/auto_master
  #
  +auto_master
  /bham   +auto.linux
  #+auto.master

A long time ago, we used NIS for Solaris and Linux – back then the maps had to be discrete – Linux autofs didn’t have nested/multi-mount and Solaris didn’t support nested mount. e.g. under Solaris we could do:

/bham
    ... /foo
    ... /baa
    ... /otherdir
            .... /foo
            .... /bar

But under Linux, it had to be:

/bham
    ... /foo
    ... /baa

and in another Linux map:

/bham
    ... /otherdir
            .... /foo
            .... /bar

When the NIS maps got carried over the LDAP for Linux when we rolled out Scientific Linux 6, this got carried over as well. Now of course, this won’t work with Solaris and neither does it work with OpenIndiana.

After a bit of consideration, we thought we were going to have to build a separate set of maps for OI again. But then we found that Linux autofs 5 now supports multi-map, so we can use traditional Solaris format maps for nested directories in a single map. A quick test and an early morning edit to the maps, and we can now use the same maps under both OSes.

ldapclient mod \
  -a "serviceSearchDescriptor=auto_master:cn=auto.master,OU=automount,OU=Maps,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk" \
  -a "serviceSearchDescriptor=auto.home:cn=auto.home-linux,OU=automount,OU=Maps,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk" \
  -a "serviceSearchDescriptor=auto.linux:cn=auto.linux,OU=automount,OU=Maps,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk" \
  -a "serviceSearchDescriptor=auto.home-linux:cn=auto.home-linux,OU=automount,OU=Maps,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk" \
  -a objectclassMap=automount:automountMap=nisMap \
  -a objectclassMap=automount:automount=nisObject \
  -a objectclassMap=auto.home-linux:automount=nisObject \
  -a objectclassMap=auto.linux:automount=nisObject \
  -a attributeMap=automount:automountMapName=nisMapName \
  -a attributeMap=automount:automountKey=cn \
  -a attributeMap=automount:automountInformation=nisMapEntry \
  -a attributeMap=auto.home-linux:automountMapName=nisMapName \
  -a attributeMap=auto.home-linux:automountKey=cn \
  -a attributeMap=auto.home-linux:automountInformation=nisMapEntry \
  -a attributeMap=auto.linux:automountMapName=nisMapName \
  -a attributeMap=auto.linux:automountKey=cn \
  -a attributeMap=auto.linux:automountInformation=nisMapEntry

One caveat to note is that we had to map each of the top-level named maps. One might think that the lines:

  -a attributeMap=automount:automountMapName=nisMapName \
  -a attributeMap=automount:automountKey=cn \
  -a attributeMap=automount:automountInformation=nisMapEntry \

would inherit, but apparently not!

So all that’s left to do is restart autofs:

svcadm enable autofs

Just as a side note on the format of maps we use for autofs, I’ve mentioned they are stored in our Active Directory. We’ve created a number of “nisMap” objects, for example, the object at “cn=auto.linux,OU=automount,OU=Maps,dc=socs-ad,dc=cs,dc=bham,dc=ac,dc=uk” is a nisMap object (probably created using ADSI edit, but I think there’s a tab available if you install the right roles on the server).

The nisMap object then contains a number of nisObject objects. e.g.:

CN=bin,CN=auto.linux,OU=automount,OU=Maps,DC=socs-ad,DC=cs,DC=bham,DC=ac,DC=uk
nisMapName -> bin
nisMapEntry -> -rw,suid,hard,intr jaffle:/vol/vol1/bham.linux/bin

For the muilti-mount map entry, each mount point is just space separated in the nisMapEntry, e.g.:

CN=htdocs,CN=auto.linux,OU=automount,OU=Maps,DC=socs-ad,DC=cs,DC=bham,DC=ac,DC=uk
nisMapName -> htdocs
nisMapEntry -> /events -rw,hard,intr jaffle:/vol/vol1/htdocs/web-events /hci -rw,hard,intr jaffle:/vol/vol1/htdocs/web-hci ...

(and yes, if you’re reading in the feed, the parts did get mixed up … I wrote part 4 before 3!)

part 1 – Hardware and Basic information
part 2 – Base Operating System Installation
part 3 – Configuring Active Directory authentication integration
part 4 – Configuring the storage pool and auto snapshots
part 5 – NFS Server config & In-kernel CIFS