Ubuntu Authentication with Active Directory without Kerberos

I recently got a Raspberry Pi 3 on which I installed Ubuntu Server 16.04. I decided for science that I wanted to enable my AD users to authenticate to the RPi. Most guides I saw required Kerberos which is perfectly reasonable but I don't have a Kerberos server so I needed another solution. It was a bumpy road and I'm quite unfamiliar with most of the stuff, so I decided to document my steps, mostly for myself in case I'd need to replicate them in the future. Then again I probably already forgot some details...

AD configuration

First add new Organization Units in AD. I added OU=People and OU=Groups. Since Identity Management for Unix is getting deprecated, I am going to manually edit the Unix attributes via the Attribute Editor tab of the user properties. This is well documented here. Essentially you need to set the values for gidNumber for groups and uidNumber, gidNumber, loginShell and unixHomeDirectory for users.

Add some users to the People OU, also creating one for LDAP bind. Add a group for those users.

Client configuration

On the RPi client, we'll be using SSSD for authentication.

$> sudo apt install sssd python3-sss sssd-tools ldap-utils

I symlinked /usr/bin/python to '/usr/bin/python3' because reasons, and that caused some errors installing SSSD which is dumb, so if anyone is in a similar situation, temporarily run ln -sf /usr/bin/python2 /usr/bin/python, re-attempt to install SSSD. Then do ln -sf /usr/bin/python3 /usr/bin/python again. I needed that for some CloudFlare script to run...

At this point it may be good to ensure connectivity to the AD server.

$> ldapsearch -v -x -H ldaps://<ldap server>:636 -b dc=ldap,dc=example,dc=com -D 'CN=<bind user cn>,OU=People,dc=ldap,dc=example,dc=com' -W 'cn=Some Other User'

Export your CA certificate in base-64 format to install on the RPi. I installed mine in /etc/ldap/certs and chmod'ed it to 600.

Edit /etc/ldap.conf. The important settings should be

base           dc=ldap,dc=example,dc=com
uri            ldaps://ldap.example.com
ldap_version   3
tls_cacertdir  /etc/ldap/certs

Edit /etc/ldap/ldap.conf. What worked for me was

BASE           dc=ldap,dc=example,dc=com
URI            ldap://ldap.example.com
TLS_REQCERT    allow
TLS_CACERT     /etc/ldap/certs/name-of-my-ca-cert.cer
SSL            start_tls

Actually I'm not even sure this last file is being used at all since when I checked in Apache Directory Studio I could only connect using LDAPS and not StartTLS...

At this point I think an encrypted connection to the AD can be attempted.

$> ldapsearch -v -H ldaps://<ldap server>:636 -b dc=ldap,dc=example,dc=com -D 'CN=<bind user cn>,OU=People,dc=ldap,dc=example,dc=com' -W 'cn=Some Other User'

Edit /etc/nsswitch.conf

passwd:      compat sss
shadow:      compat sss
services:    db files sss
netgroup:    nis sss
sudoers:     files sss

Leave the other existing entries intact.

We finally get to configuring /etc/sssd/sssd.conf. Most of my settings were sourced from this CentOS guide

$> touch /etc/sssd/sssd.conf
$> chown root:root /etc/sssd/sssd.conf
$> chmod 600 /etc/sssd/sssd.conf
$> nano /etc/sssd/sssd.conf
[sssd]
config_file_version = 2
services = nss, pam
domains = ldap.example.com

[nss]
filter_groups = root
filter_users = root
reconnection_retries = 3

[pam]
[domain/ldap.example.com]
debug_level = 1
enumerate = false
cache_credentials = true
min_id = 100
# just in case, if the AD is IPv6-only
lookup_family_order = ipv6_first
id_provider = ldap
auth_provider = ldap
access_provider = simple
chpass_provider = ldap
ldap_id_use_start_tls = False
ldap_schema = rfc2307bis
ldap_tls_cacert = /etc/ldap/certs/name-of-my-ca-cert.cer
ldap_tls_reqcert = never
ldap_user_search_base = dc=ldap,dc=example,dc=com
ldap_group_search_base = dc=ldap,dc=example,dc=com
ldap_user_object_class = user
ldap_user_principal = userPrincipalName
ldap_user_name = sAMAccountName
ldap_user_gecos = displayName
ldap_group_object_class = group
ldap_group_name = sAMAccountName
ldap_user_home_directory = unixHomeDirectory
ldap_uri = ldaps://ldap.example.com:636
ldap_default_bind_dn = CN=<bind cn>,OU=People,DC=ldap,DC=example,DC=com
ldap_default_authtok_type = obfuscated_password
ldap_default_authtok = replaceme
simple_allow_groups = <the group for unix users>

For details on what each entry does: RTM. Then to obfuscate the bind dn password run

$> sss_obfuscate -d ldap.example.com -f /etc/sssd/sssd.conf

And it should replace the ldap_default_authtok entry in /etc/sssd/sssd.conf.

Now SSSD can be started

$> service sssd start

In my case the service failed to start with some obscure error about being unable to convert the obfuscated password back to plain-text. And changing ldap_authtok_type to password and ldap_default_authtok to the plain-text password still gave the same error. The reason for that turned out to be due to some stupid python2 vs python3 (did I mention I hate python?) problem preventing sss_obfuscate from running correctly the first time and cache_credentials = true in sssd.conf. Some bogus value was generated by sss_obfuscate and it remained in the cache.

$> rm -rf /var/lib/sss/db/*
$> service sssd start
$> echo victory, finally

You can check that everything works by running

$> id someusername

And it should return some information on that AD user. Now you should be able to ssh into the RPi with your AD users.

Outstanding issues

Permission denied (publickey)

...or not. In my case I disabled password login, so some extra steps are needed. The default AD schema doesn't have any entry for SSH public keys, and this discussion suggests modifying the registry to allow modifications to the AD schema. I don't feel that comfortable doing that as it may lead to unwanted consequences were the server to be upgraded to Windows Server 2016 so caution is advised.

At the bottom of the discussion however one user suggests using some other built-in AD field. Since I'm now using that altSecurityIdentities field, it seems like an acceptable solution. It is as simple as adding your SSH public key to the altSecurityIdentities field, and editing /etc/sssd/sssd.conf

services = nss, pam, ssh, sudo
ldap_user_ssh_public_key = altSecurityIdentities

Edit /etc/ssh/sshd_config

AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
AuthorizedKeysCommandUser root

Restart SSSD and SSHD

...aaand it doesn't work. For now I simply manually added the authorized_keys to the user's home profile and called it a day. Other issues I'm currently having is that sudo won't work as passwords are also not being synced or something. I'll leave fixing that to another day however as I've already spent a lot of time on this. I suspect the password problem has something to do with Identity Management for Unix being deprecated (and me not installing it for that reason).