Using OpenLDAP for Single Sign On (SSO) at home

Following on from some of my findings and decisions in Becoming Self-sufficient and IT Resilient in 2017. Part 3 I decided to do some reading and digging around Identity Management options.

Ultimately it looks like I'll end up implementing a full domain at home with the following:

  • Samba4 Domain Controller
  • OpenLDAP as a directory service (users, groups)
  • Kerberos for authentication
  • Gluu as an additional layer to enable me to act as an OpenID and SAML provider for applications such as GitLab that support it for SSO

All of these parts will take a while to pull together so, in the interest of time, I thought I'd build a quick proof-of-concept using just OpenLDAP.

The idea here is to have two machines, one acting as the directory service and one as a 'client'. I should be able to ssh into the client machine using a username/password combination that it hasn't been setup with and needs to query / authenticate from the central directory.

Diagram

Setup

I spun up two containers on my Proxmox host running Ubuntu Server 16.04, one for the client and one for the ldap server.

In addition I've got a local apt-cacher-ng container running which really helps with minimising round trips to the internet for packages.

Some of the key variables I'm using everywhere:

  • Domain: xmansion.local

Server: auth.xmansion.local

I've used the following:

  • 4 vCores
  • 8GB RAM
  • 60GB HDD
# Point at local apt-cacher (ignore if you don't have one)
echo 'Acquire::http { Proxy: "http://apt.xmansion.local:3142"; };' | sudo tee /etc/apt/apt.conf.d/01proxy

# Update
apt-get update && apt-get -y upgrade && apt-get -y dist-upgrade  

LDAP

First up we will install Open LDAP to act as our Account Management system (usernames, groups etc.).

Key references:

sudo apt-get install -y slapd ldap-utils

# Reconfigure to get domain right
dpkg-reconfigure slapd  

We'll now add some nodes to the LDAP database for the domain:

  • a node called People (to store users)
  • a node called Groups (to store groups)
  • a group called admins
  • a user called james

I'll create an ldif file to hold the details and then we'll load it into the database.

nano ~/add_content.ldif

# file: add_content.ldif
# ---
dn: ou=People,dc=xmansion,dc=local  
objectClass: organizationalUnit  
ou: People

dn: ou=Groups,dc=xmansion,dc=local  
objectClass: organizationalUnit  
ou: Groups

dn: cn=admins,ou=Groups,dc=xmansion,dc=local  
objectClass: posixGroup  
cn: admins  
gidNumber: 5000

dn: uid=james,ou=People,dc=xmansion,dc=local  
objectClass: inetOrgPerson  
objectClass: posixAccount  
objectClass: shadowAccount  
uid: james  
sn: veitch  
givenName: James  
cn: James Veitch  
displayName: James Veitch  
uidNumber: 10000  
gidNumber: 5000  
userPassword: password  
gecos: James Veitch  
loginShell: /bin/bash  
homeDirectory: /home/james  

We'll now load this file into the database

ldapadd -x -D cn=admin,dc=xmansion,dc=local -W -f ~/add_content.ldif  
...
adding new entry "ou=People,dc=xmansion,dc=local"  
adding new entry "ou=Groups,dc=xmansion,dc=local"  
adding new entry "cn=admins,ou=Groups,dc=xmansion,dc=local"  
adding new entry "uid=james,ou=People,dc=xmansion,dc=local"  

To check the user has been created run ldapsearch -x -LLL -b dc=xmansion,dc=local 'uid=james' cn gidNumber and you should get a nice response.

TLS

For the purposes of the PoC I'm going to ignore indexing, replication, ACLs etc. for the moment and just focus on securing the traffic between client and server using StartTLS. As such we'll need to create our own Certificate Authority and sign some certs.

sudo apt-get install -y gnutls-bin ssl-cert  
sudo certtool --generate-privkey \  
    --bits 4096 \
    --outfile /etc/ssl/private/cakey.pem

Create the details in a tmp file for the Certificate Authority

sudo nano /etc/ssl/ca.info  
...
cn = xmansion  
ca  
cert_signing_key  

Now create the self-signed root cert

sudo certtool --generate-self-signed \  
    --load-privkey /etc/ssl/private/cakey.pem \
    --template /etc/ssl/ca.info \
    --outfile /etc/ssl/certs/cacert.pem

Create server private key

sudo certtool --generate-privkey \  
    --bits 4096 \
    --outfile /etc/ssl/private/auth.xmansion.local_slapd_key.pem

Create server information file

sudo nano /etc/ssl/auth.xmansion.local.info  
...
organization = xmansion  
cn = auth.xmansion.local  
tls_www_server  
encryption_key  
signing_key  
expiration_days = 3650  

Create the server's certificate

sudo certtool --generate-certificate \  
    --load-privkey /etc/ssl/private/auth.xmansion.local_slapd_key.pem \
    --load-ca-certificate /etc/ssl/certs/cacert.pem \
    --load-ca-privkey /etc/ssl/private/cakey.pem \
    --template /etc/ssl/auth.xmansion.local.info \
    --outfile /etc/ssl/certs/auth.xmansion.local_slapd_cert.pem

Change the permissions and owner

sudo chgrp openldap /etc/ssl/private/auth.xmansion.local_slapd_key.pem  
sudo chmod 0640 /etc/ssl/private/auth.xmansion.local_slapd_key.pem  
sudo gpasswd -a openldap ssl-cert  

Restart the service

sudo systemctl restart slapd.service  

Make LDAP aware of the certificate

nano ~/certinfo.ldif

# file: certinfo.ldif
# ---
dn: cn=config  
add: olcTLSCACertificateFile  
olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem  
-
add: olcTLSCertificateFile  
olcTLSCertificateFile: /etc/ssl/certs/auth.xmansion.local_slapd_cert.pem  
-
add: olcTLSCertificateKeyFile  
olcTLSCertificateKeyFile: /etc/ssl/private/auth.xmansion.local_slapd_key.pem  

Load the file to the database

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f ~/certinfo.ldif  

Now modify the config

sudo nano /etc/default/slapd  
...

SLAPD_SERVICES="ldap:/// ldapi:///"  

We now have an OpenLDAP server complete with a single user called james which should be queryable from the client over StartTLS.

Client

Configuring the client is actually fairly straightforward.

sudo apt-get install -y libnss-ldap ldap-utils  
sudo auth-client-config -t nss -p lac_ldap  
sudo pam-auth-update  

NB: Remember to use ldap:// as opposed to ldapi:// when configuring (using StartTLS).

Now modify the /etc/ldap/ldap.conf config file

sudo nano /etc/ldap/ldap.conf  
...
BASE dc=xmansion,dc=local  
URI ldap://auth.xmansion.local  

Check all working with a couple of queries (increasing in complexity). Using the correct password for james results in an authentication success.

# Show all
ldapsearch -x  
...
# Specify server host and look for user
ldapwhoami -vvv -h auth.xmansion.local -D "uid=james,ou=People,dc=xmansion,dc=local" -x -W  
...
# Use default (no specified host) and look for user
ldapwhoami -vvv -D "uid=james,ou=People,dc=xmansion,dc=local" -x -W  
...
# Try with StartTLS
ldapwhoami -vvv -D "uid=james,ou=People,dc=xmansion,dc=local" -x -W -Z  

You'll notice that the last query failed... This is because we're using a self-signed certificate and need to add it as a trusted cert. This is fairly straightforward thanks to Bai from StackOverflow.

# create 'extra' directory
sudo mkdir /usr/share/ca-certificates/extra

# pipe the previous saved .pem cert across and
# convert to x509 so we can use it. This is a bit
# hacky and should probably be done differently in
# production...
ssh [email protected] 'cat /etc/ssl/certs/cacert.pem' \  
    | openssl x509 -inform PEM \
    -out /usr/share/ca-certificates/extra/auth.xmansion.local.crt

# Now add it in the resulting config screen
sudo dpkg-reconfigure ca-certificates

# Try again with StartTLS
ldapwhoami -vvv -D "uid=james,ou=People,dc=xmansion,dc=local" -x -W -Z  

You should now be able to run ssh [email protected] and login to the client machine from anywhere.

Key references

James Veitch

Read more posts by this author.