TechSomething

SSO with lldap, Authelia and Nginx

Scope: #

I wanted to play with a (lightweight) directory service and an identity access management solution to be able to manage the access to some of my sites.

Software: #

lldap: #

lldap
is a lightweight implementation of ldap, lacks some features (like ldaps or clustering) but is ok for my needs right now.
Has many example config file for compatible services.

Authelia: #

Authelia
is a IAM and is layer between your applications/users and ldap.
It has a nice portal and allows you user to configure their devices.

Nginx: #

my reverse proxy of choice, from nginx I can choose which site needs to be authenticated before accessing.

docker-compose: #

I’ve used docker-compose for lldap and Authelia,
pre-reqs:

#create the user for your service:
useradd -u 50000 -U -M -s /bin/false docker_ldap

#create the folder for the local mappings for docker:
mkdir -p /data/lldap /data/authelia

#change the permission on the folders:
chown -R 50000:50000 /data/lldap
chown -R 50000:50000 /data/authelia

the docker-compose.yml:

services:
lldap:
image: nitnelave/lldap:stable
# Change this to the user:group you want.
user: “50000:50000”
ports:
# For LDAP
- “3890:3890”
# For the web front-end
- “17170:17170”
volumes:
- “/data/lldap:/data”
environment:
- LLDAP_JWT_SECRET=YOUR_SECRET
- LLDAP_LDAP_USER_PASS=YOUR_PASS
- LLDAP_LDAP_BASE_DN=dc=example,dc=com

authelia:
image: authelia/authelia
container_name: authelia
volumes:
- /data/authelia:/config
user: “50000:50000”
ports:
- “9091:9091”
restart: unless-stopped
healthcheck:
disable: true
environment:
- TZ=Europe/Rome

you’ll have to add the Authelia configfile in /data/authelia/configuration.yml
which should look something like this (without comments):

---
theme: auto
jwt_secret: 123107213701371937937
default_redirection_url: https://auth.example.com/
default_2fa_method: “totp”
server:
host: 0.0.0.0
port: 9091
path: “”
asset_path: /config/assets/
read_buffer_size: 4096
write_buffer_size: 4096
enable_pprof: false
enable_expvars: false
disable_healthcheck: false
tls:
key: “”
certificate: “”
client_certificates: []
headers:
csp_template: “”

log:
level: debug
format: text
file_path: /config/authelia.log

telemetry:
metrics:
enabled: false
address: tcp://0.0.0.0:9959

totp:
disable: false
issuer: auth.example.com
algorithm: sha1
digits: 6
period: 30
skew: 1
secret_size: 32

webauthn:
disable: false
timeout: 60s
display_name: Authelia
attestation_conveyance_preference: indirect
user_verification: preferred

ntp:
address: “time.cloudflare.com:123”
version: 4
max_desync: 3s
disable_startup_check: false
disable_failure: false

authentication_backend:
password_reset:
disable: false
refresh_interval: 1m
ldap:
implementation: custom
url: ldap://lldap:3890
timeout: 5s
start_tls: false
base_dn: dc=example,dc=com
username_attribute: uid
additional_users_dn: ou=people
users_filter: (&({username_attribute}={input})(objectClass=person))
additional_groups_dn: ou=groups
groups_filter: (member={dn})
group_name_attribute: cn
mail_attribute: mail
display_name_attribute: displayName
user: uid=admin,ou=people,dc=example,dc=com
password: ‘password’

password_policy:
standard:
enabled: false
min_length: 8
max_length: 0
require_uppercase: true
require_lowercase: true
require_number: true
require_special: true
zxcvbn:
enabled: false
min_score: 3

access_control:
default_policy: deny
rules:
- domain: ‘public.example.com’
policy: bypass

- domain: ‘www.example.com’
policy: two_factor

session:
name: authelia_session
domain: example.com
same_site: lax
secret: insecure_session_secret
expiration: 1h
inactivity: 5m
remember_me_duration: 1M

regulation:
max_retries: 3
find_time: 2m
ban_time: 5m

storage:
encryption_key: 123123123123123123123123123123123123123123123
local:
path: /config/db.sqlite3

notifier:
disable_startup_check: true

smtp:
host: smtp.mail.domain
port: 587
timeout: 5s
username: auth.examplecom@mail.domain
password: password
sender: “auth.example.com <auth.examplecom@mail.domain>
identifier: Auth_examplecom
subject:[auth.example.com] {title}
startup_check_address: check@test.domain
disable_require_tls: false
disable_html_emails: false

tls:
skip_verify: false
minimum_version: TLS1.2
...

Notes:
see “default_policy: deny” this means that if you don’t create a rule for your site (or a rule with a wildcard) then you’ll receive a 403 “Access Denied” after the authentication, ask me how I know :D

lldap has it’s own config (I had to write this from scratch since the container won’t create the correct defaults:

ldap_port = 3890
http_port = 17170

jwt_secret =123123123123123123
ldap_base_dn = “dc=example,dc=com”
ldap_user_dn = “admin”
ldap_user_pass = “password”
database_url = “sqlite:///data/users.db?mode=rwc”
key_file = “/data/private_key”

[smtp_options]
enable_password_reset=true
server=“smtp.mail.domain”
port=587
tls_required=true
user=“auth.examplecom@mail.domain”
password=“password”
from=“LLDAP Admin <auth.examplecom@mail.domain>”
reply_to=“Do not reply <noreply@examplecom>”

start the container and access lldap’s web interface on port 17170 with user admin and password what-you-set, then you’ll be able to create other users.

Nginx: #

this is really everything you need to know:
https://www.authelia.com/integration/proxies/nginx/

I’ve put all Authelia’s files in a dedicated config folder and linked them in there,
REMEMBER to create the rules for your site in Authelia’s config.

My nginx config:


#auth.example.com
server {
listen 80;
server_name auth.example.com;
return 301 https://$server_name$request_uri;
#LOGS:
access_log /var/log/nginx/auth.example.com_access.log;
error_log /var/log/nginx/auth.example.com_error.log;
}

server {
listen 443 ssl http2;
server_name auth.example.com;
#SSL:
ssl on;
ssl_certificate /etc/letsencrypt/live/auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.example.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
#LOGS:
access_log /var/log/nginx/auth.example.com_access.log;
error_log /var/log/nginx/auth.example.com_error.log;
location / {
proxy_pass http://192.168.43.170:9091;
include /etc/nginx/conf.d/authelia/proxy.conf;
}
}

#www.example.com
server {
listen 80;
server_name www.example.com;
return 301 $scheme://$server_name$request_uri;
#LOGS:
access_log /var/log/nginx/www.example.com_access.log;
error_log /var/log/nginx/www.example.com_error.log;
}

server {
listen 443 ssl http2;
server_name www.example.com;
#SSL:
ssl on;
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
#LOGS:
access_log /var/log/nginx/www.example.com_access.log;
error_log /var/log/nginx/www.example.com_error.log;
#
#authelia:
include /etc/nginx/conf.d/authelia/authelia-location.conf;
#
location / {
include /etc/nginx/conf.d/authelia/proxy.conf;
include /etc/nginx/conf.d/authelia/authelia-authrequest.conf;
root /var/www/example.com;
}
}

Authelia rules examples: #

in this example inly the users in the group “www_site_users” will be able to access the site www.example.com using the 2 factor authentication, the admin users in the group “www_site_admins” will not be able to access any site of example.com:

    - domain: ‘www.example.com’
policy: two_factor
subject: ‘group:www_site_users’

- domain:*.example.com’
policy: deny
subject: ‘group:www_site_admins