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).