đ Authentification centralisĂ©e avec Authelia et LLDAP
Introduction
Les futures applications que nous installerons nécessiteront une authentification. Afin de faciliter la création ou la suppression de comptes utilisateurs, nous allons mettre une authentification centralisée.
Pour cela nous nous appuierons sur :
- L'annuaire léger LLDAP qui contiendra la base des comptes utilisateur
- Le portail IAM Authelia permettant de fournir une solution d'authentification multi-facteur et unique par le biais du SSO.
Préparation
olivier@ds01:/mnt/nfsdatas$ mkdir stack-sso && chown olivier: stack-sso
olivier@ds01:/mnt/nfsdatas$ cd stack-sso
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir -p config/authelia
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir -p config/lldap/ssl
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir env
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir -p log/authelia
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir -p secrets/authelia
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir -p secrets/lldap
olivier@ds01:/mnt/nfsdatas/stack-sso$ mkdir -p data/{redis,data}
olivier@ds01:/mnt/nfsdatas/stack-sso$ tree -ld
.
âââ config
â  âââ authelia
â  âââ lldap
â  âââ ssl
âââ data
âââ authelia
â  âââ redis
âââ env
âââ log
â  âââ authelia
âââ secrets
âââ authelia
âââ lldap
13 directories
networks:
web:
external: true
sso:
external: true
services:
lldap:
image: nitnelave/lldap:stable
networks:
- web
- sso
volumes:
- ./config/lldap:/data
- ./secrets/lldap:/secrets
env_file:
- ./env/container-vars-lldap.env
deploy:
placement:
constraints:
- node.role == worker
restart_policy:
condition: on-failure
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.docker.network=web"
- "traefik.http.routers.lldap.rule=Host(`l.dev.quercylibre.fr`)"
- "traefik.http.routers.lldap.tls=true"
- "traefik.http.routers.lldap.tls.certresolver=letsencrypt"
# Le dashboard de LLDAP ne sera accessible qu'en local
- "traefik.http.routers.lldap.middlewares=crowdsec@file,lldap-ipallowlist"
- "traefik.http.middlewares.lldap-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.services.lldap.loadbalancer.server.port=17170"
- "traefik.http.routers.lldap.service=lldap"
authelia:
image: authelia/authelia
depends_on:
- lldap
- redis
networks:
- web
- sso
env_file:
- ./env/container-vars-authelia.env
volumes:
- "./config/authelia:/config"
- "./secrets/authelia:/secrets"
- "./log/authelia:/var/log/authelia"
- "./data/authelia:/data"
environment:
- TZ=Europe/Paris
deploy:
placement:
constraints:
- node.role == worker
restart_policy:
condition: on-failure
delay: 45s
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.docker.network=web"
- "traefik.http.routers.authelia.rule=Host(`a.dev.quercylibre.fr`)"
- "traefik.http.routers.authelia.tls=true"
- "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
- "traefik.http.routers.authelia.middlewares=crowdsec@file"
- "traefik.http.services.authelia.loadbalancer.server.port=9091"
- "traefik.http.routers.authelia.service=authelia"
redis:
image: redis:latest
networks:
- sso
volumes:
- ./data/redis:/data
deploy:
placement:
constraints:
- node.role == worker
restart_policy:
condition: on-failure
replicas: 1
J'ai mis un dĂ©lai de 45 secondes pour le reboot du conteneur Authelia car lors du lancement de la stack, le CT Authelia n'attend pas que LLDAP et Redis soient prĂȘts. Par consĂ©quent lors du premier boot, Authelia est en Ă©chec et attend 45 secondes avant de se relancer.
olivier@ds01:/mnt/nfsdatas/stack-sso$ docker network create --driver=overlay sso
Configuration de LLDAP
database_url = "sqlite:///data/users.db?mode=rwc"
# Commande pour générer la clé ci-dessous : tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1
key_seed = "O21vDuTDbXo69CimPb3G2FuyEYUuCc0E2A3UcXyUyuS2LxdtPCxKW0DiWfdkTKOs"
olivier@ds01:/mnt/nfsdatas/stack-sso$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout ./data/ssl/keyfile.key -out ./data/ssl/certfile.crt
olivier@ds01:/mnt/nfsdatas/stack-sso$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > ./secrets/lldap/JWT_SECRET
olivier@ds01:/mnt/nfsdatas/stack-sso$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "20" | head -n 1 > ./secrets/lldap/LDAP_USER_PASS
LLDAP_LDAP_BASE_DN=dc=quercylibre,dc=fr
TZ=Europe/Paris
UID=1001
GID=1001
# If using LDAPS, set enabled true and configure cert and key path
LLDAP_LDAPS_OPTIONS__ENABLED=true
LLDAP_LDAPS_OPTIONS__CERT_FILE=/data/ssl/certfile.crt
LLDAP_LDAPS_OPTIONS__KEY_FILE=/data/ssl/keyfile.key
# Secrets: lldap reads them from the specified files.
# This way, the secrets are not part of any process environment.
LLDAP_JWT_SECRET_FILE=/secrets/JWT_SECRET
LLDAP_LDAP_USER_PASS_FILE=/secrets/LDAP_USER_PASS
Configuration d'Authelia
server:
address: 'tcp://0.0.0.0:9091'
log:
level: info
format: text
file_path: /var/log/authelia/authelia.log
theme: light
totp:
algorithm: sha1
digits: 6
period: 30
skew: 1
secret_size: 32
password_policy: # Les mots de passe pourront ĂȘtre modifiĂ©s depuis Authelia mais selon les rĂšgles ci-dessous
standard:
enabled: false
min_length: 14
max_length: 0
require_uppercase: true
require_lowercase: true
require_number: true
require_special: true
zxcvbn:
enabled: false
min_score: 3
authentication_backend:
password_reset:
disable: false # Autorisation de modification des mots de passe par les utilisateurs
refresh_interval: 5m
# Configuration LDAP spécifique à LLDAP
ldap:
implementation: custom
timeout: 5s
start_tls: false
additional_users_dn: 'ou=people'
users_filter: "(&({username_attribute}={input})(objectClass=person))"
additional_groups_dn: 'ou=groups'
groups_filter: "(member={dn})"
attributes:
username: 'uid'
display_name: 'displayName'
mail: 'mail'
group_name: 'cn'
access_control:
default_policy: deny
networks:
- name: internal
networks:
- '192.168.1.0/24'
rules:
- domain:
- "cobalt.dev.quercylibre.fr" # Application d'extraction de vidéo et de son Youtubre, Instangram,...
policy: 'one_factor' # Un seul facteur d'auth si connexion depuis le réseau interne 192.168.1.0/24 déclaré plus haut
networks:
- 'internal'
- domain:
- "cobalt.dev.quercylibre.fr"
policy: 'two_factor' # Deux facteurs d'auth si connexion depuis Internet ou un autre réseau.
- domain:
- "d.dev.quercylibre.fr" # Dashboard Traefik
policy: 'two_factor'
subject:
- ['user:admin'] # Seul le compte admin aura accĂšs au dashboard Traefik en remplacement du basic auth
session:
name: authelia_session
expiration: 12h # 12 hours
inactivity: 45m # 45 minutes
remember_me: 1M # 1 month
cookies:
- domain: 'dev.quercylibre.fr'
authelia_url: 'https://a.dev.quercylibre.fr'
default_redirection_url: https://accueil.dev.quercylibre.fr
name: 'authelia_session'
same_site: 'lax'
inactivity: '5m'
expiration: '1h'
remember_me: '1d'
redis:
host: redis
port: 6379 # port for REDIS docker contianer
database_index: 0 # change this if you already use REDIS for something
regulation: # Blocage accĂšs de 15 min au bout de 3 Ă©checs d'auth en moins de 5 min.
max_retries: 3
find_time: 5m
ban_time: 15m
notifier:
smtp:
sender: "Authelia <authelia@mail.tld>" # Variable passée ici car bug si déclarée dans les variables d'env.
storage:
# Il est possible d'utiliser d'autres back-end comme MariaDB ou PGSQL.
local:
path: /data/db.sqlite3
ntp:
address: 'udp://time.cloudflare.com:123'
version: 3
max_desync: '3s'
disable_startup_check: false
disable_failure: false
PUID=1001
PGID=1001
AUTHELIA_TOTP_ISSUER=a.dev.quercylibre.fr
AUTHELIA_WEBAUTHN_DISPLAY_NAME=authelia
AUTHELIA_NOTIFIER_SMTP_ADDRESS=submission://<SERVER_MAIL>:587
AUTHELIA_NOTIFIER_SMTP_USERNAME=authelia@mail.tld
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDRESS=ldap://lldap:3890
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_BASE_DN=dc=quercylibre,dc=fr
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USER=uid=admin,ou=people,dc=quercylibre,dc=fr
# Secrets: Authelia reads them from the specified files.
# This way, the secrets are not part of any process environment.
AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE=/secrets/JWT_SECRET
AUTHELIA_SESSION_SECRET_FILE=/secrets/SESSION_SECRET
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/secrets/STORAGE_ENCRYPTION_KEY
AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/secrets/NOTIFIER_SMTP_PASSWORD
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE=/secrets/AUTHENTICATION_BACKEND_LDAP_PASSWORD
olivier@ds01:/mnt/nfsdatas/stack-sso$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > ./secrets/authelia/JWT_SECRET
olivier@ds01:/mnt/nfsdatas/stack-sso$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > ./secrets/authelia/SESSION_SECRET
olivier@ds01:/mnt/nfsdatas/stack-sso$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > ./secrets/authelia/STORAGE_ENCRYPTION_KEY
# Renseignez les mots de passe pour l'utilisateur SMT
olivier@ds01:/mnt/nfsdatas/stack-sso$ vim secrets/authelia/NOTIFIER_SMTP_PASSWORD
# Récupérez le mot de passe admin LLDAP
olivier@ds01:/mnt/nfsdatas/stack-sso$ cp secrets/LLDAP/LDAP_USER_PASS secrets/authelia/AUTHENTICATION_BACKEND_LDAP_PASSWORD
olivier@ds01:/mnt/nfsdatas/stack-sso$ chmod -R u+rwX,g-rwX,o-rwX secrets/
DĂ©ploiement de la stack
olivier@ds01:/mnt/nfsdatas/stack-sso$ docker stack deploy -c docker-stack.yml -d sso
Creating service sso_lldap
Creating service sso_authelia
Creating service sso_redis
olivier@ds01:/mnt/nfsdatas/stack-sso$ docker stack ps sso
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
hly93qjl1mcj sso_authelia.1 authelia/authelia:latest ds06 Running Running 33 minutes ago
# Le premier fail ci-dessous est liĂ© au fait qu'Authelia dĂ©marre sans attendre que LLDAP et Redis soient prĂȘts
a2g5wssbh6w2 \_ sso_authelia.1 authelia/authelia:latest ds06 Shutdown Failed 34 minutes ago "task: non-zero exit (1)"
qkuih02x16ws sso_lldap.1 nitnelave/lldap:stable ds04 Running Running 34 minutes ago
v23rog8bh9ah sso_redis.1 redis:latest ds04 Running Running 34 minutes ago
Configuration du middleware Authelia savec Traefik
http:
middlewares:
(...)
authelia:
forwardAuth:
address: 'http://authelia:9091/api/authz/forward-auth'
trustForwardHeader: true
authResponseHeaders:
- 'Remote-User'
- 'Remote-Groups'
- 'Remote-Email'
- 'Remote-Name'
DĂ©claration du middleware pour le dashboard Traefik
L'objectif est de remplacer le basic auth de Traefik par Authelia et en restreigant l'accÚs au compte admin créé sur LLDAP grùce à la rÚgle d'accÚs définie plus haut dans le fichier de configuration d'Authelia.
services:
traefik:
image: "traefik:v3.0.2"
(...)
deploy:
placement:
constraints:
- node.role == manager
restart_policy:
condition: on-failure
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard.rule=Host(`d.dev.quercylibre.fr`)"
- "traefik.http.routers.traefik-dashboard.service=api@internal"
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
# DĂ©claration du middle-ware authelia@file
- "traefik.http.routers.traefik-dashboard.middlewares=crowdsec@file,traefik-dashboard-ipallowlist,authelia@file"
- "traefik.http.middlewares.traefik-dashboard-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.services.traefik-dashboard-service.loadbalancer.server.port=8080"
(...)
On relance le service :
Il est quand mĂȘme sacrĂ©ment simple d'utiliser le middleware Authelia avec Traefik comparĂ© Ă Nginx.
Configuration des méthodes 2FA
Outil pour le 2FA
Avant de configurer le 2FA, il vous faudra avoir un outil capable de gérer le 2FA. Personnellement, j'utilise Vaultwarden dont l'extension Firefox Bitwarden est capable de gérer le TOTP et les clés d'identification. Si vous avez déjà un conffre-fort pour vos mots de passe mais qui ne gÚre pas le TOTP, vous pouvez utiliser l'extension Firefox Authenticator.
Connectez vous Ă Authelia depuis un navigateur web puis authentifiez-vous avec un compte existant sur LLDAP.
Une fois authentifié, vous devez définir une méthode 2FA. Cliquez sur "Enregistrer l'appareil" :
Ajoutez une des deux méthodes. Ici je sélectionne la méthode basée sur un mot de passe à usage unique.
Un email vous est alors envoyé avec code temporaire.
Quand le code reçu par mail est saisi, Authelia vous invite alors à suivre la procédure ci-dessous afin d'activer le 2FA basé sur le TOTP.
Une fois la procédure terminée, la méthode est activée et visible dans les réglages Authelia accessible par l'utilisateur. Il est possible de le supprimer. Il vous sera alors envoyé de nouveau un code temporaire par email afin de confirmer la suppression.
Monitoring des services avec Uptime Kuma
Nous allons monitorer :
- Le service Authelia Ă travers son URL et son port 9091
- Le service LLDAP Ă travers son URL et ses ports 17170 et 3890
- Le service Redis Ă travers son port 6379
On déclare le réseau "sso" afin de permettre à Uptime Kuma de monitorer les services comme Redis.
services:
uptime-kuma:
image: louislam/uptime-kuma:1
volumes:
- ./uptime-kuma-data:/app/data
networks:
- web
- sso # Ici
(...)
networks:
web:
external: true
sso: # Et ici
external: true
On relance le service.