Cela fait un moment que j’utilise Authelia pour faire de l’authentification à mes applications qui n’en proposent pas, cela reste beaucoup plus joli qu’un simple auth-basic.
Cela fait également un moment que cet article est commencé, mais au vu des sujets déjà présents sur le net, je ne voyais pas l’utilité d’en ajouter un nouveau, surtout qu’à ce moment, j’estimais n’avoir aucune plus-value. Au final, ayant beaucoup pratiqué authelia, j’ai appris quelques trucs écrient nulle-part ailleurs, donc je me lance enfin.
Qu’est ce que Authelia
Authelia est un logiciel permettant d’ajouter une authentification au niveau du reverse proxy, plutôt pratique pour sécuriser des applications qui n’en ont pas de base. Il permet de faire de l’authentification simple et double facteur, avec notamment TOTP, Duo ou Yubikey.
Si vous avez en plus un ldap, il est possible de l’utiliser pour populer vos utilisateurs.
Comme dit, authelia vient s’installer entre le reverse et vos applications, il fait donc partie de la classe middleware, cela veut dire qu’il n’y a aucune modification à apporter à vos applications. Voici un léger schéma de l’architecture :
Installation
Nous utiliserons Traefik comme reverse proxy, mais pour changer un peu, nous ferons une installation manuelle de notre stack, pas de docker ou kubernetes. Pour cela, nous installons une VM sous ubuntu en local, en redirigeant le nom de domaine *.traefik.local sur celle-ci.
Pour les applications, nous utiliserons caddy server. En fait, c’est surtout que j’utilise la même machine que mes tests caddy, comme ça, c’est plus simple.
traefik
Installation
Pour installer traefik, nous récupérons le binaire :
$ wget https://github.com/traefik/traefik/releases/download/v2.5.6/traefik_v2.5.6_linux_amd64.tar.gz
$ tar xzvf traefik_v2.5.6_linux_amd64.tar.gz
$ cp traefik /usr/local/bin/traefik
Pour utiliser traefik, nous lui créons un utilisateur, un reverse n’a aucunement besoin d’être exécuté en root :
$ useradd --system traefik
Et voilà, c’est fait, pas de dépendances puisque c’est du Go.
Configuration
Nous allons partir sur une configuration simple, pour ceci nous créons un répertoire /etc/traefik/conf.d
:
$ mkdir -p /etc/traefik/conf.d
$ chown root:traefik -R /etc/traefik
$ chmod g+w -R /etc/traefik
Nous créons également le répertoire qui accueillera les logs :
$ mkdir -p /var/log/traefik && chown traefik:traefik /var/log/traefik
Puis nous créons un fichier /etc/traefik/traefik.yml
, nous partons sur une configuration simple
accesslog:
filePath: "/var/log/traefik/traefik-access.log"
api:
insecure: false
dashboard: true
debug: false
log:
level: "INFO"
filePath: "/var/log/traefik/traefik.log"
providers:
file:
directory: /etc/traefik/conf.d/
watch: true
entryPoints:
web:
address: ":8080"
http:
redirections:
entryPoint:
scheme: https
to: websecure
websecure:
address: ":8443"
serverstransport:
insecureskipverify: true
certificatesResolvers:
letsencrypt:
acme:
email: "xataz@traefik.local"
caServer: "https://acme-v02.api.letsencrypt.org/directory"
storage: "/etc/traefik/acme.json"
keyType: "EC384"
tlsChallenge: {}
Création du service
Pour finir, il ne manque qu’un service systemd pour le démarrer correctement, pour ceci, nous créons un fichier /etc/systemd/system/traefik.service
:
[Unit]
Description = Traefik Daemon
After = syslog.target network.target
[Service]
User = traefik
Group = traefik
Type = simple
ExecStart = /usr/local/bin/traefik
TimeoutStopSec = 20
KillMode = process
Restart = on-failure
WorkingDirectory = /etc/traefik
[Install]
WantedBy = multi-user.target
On reload la configuration de systemd, et on lance le service :
$ systemctl daemon-reload
$ systemctl enable --now traefik
Created symlink /etc/systemd/system/multi-user.target.wants/traefik.service → /etc/systemd/system/traefik.service.
Création d’un router traefik
Pour commencer, nous allons ajouter un router pour accéder au dashboard de traefik, pour ceci, nous créons le fichier /etc/traefik/conf.d/traefik.yml
:
http:
routers:
traefik:
rule: "Host(`traefik.traefik.local`)"
entryPoints:
- "websecure"
service: "api@internal"
tls:
certResolver: letsencrypt
puis on peux directement tester via notre navigateur avec https://traefik.traefik.local:8443 (Si vous êtes en local, vous aurez une erreur de certificat)
authelia
Installation
L’installation d’authelia est vraiment simple. Tout comme traefik c’est du Go, donc un seul binaire, cependant authelia à besoin de redis pour la gestion des sessions, et d’un backend SQL. Pour notre installation nous utiliserons sqlite, qui est largement suffisant pour une installation personnelle.
On commence donc par installer redis :
$ apt install redis
Puis on installe authelia :
$ wget https://github.com/authelia/authelia/releases/download/v4.33.1/authelia-v4.33.1-linux-amd64.tar.gz
$ tar xzvf authelia-v4.33.1-linux-amd64.tar.gz
$ cp authelia-linux-amd64 /usr/local/bin/authelia
On crée l’utilisateur ainsi que ses répertoires :
$ useradd --system authelia
$ mkdir -p /etc/authelia /var/lib/authelia /var/log/authelia
$ chown root:authelia /etc/authelia
$ chown authelia: /var/lib/authelia /var/log/authelia
Et voilà pour l’installation.
Configuration
Nous allons faire une configuration minimal, je vous laisse regarder la documentation officiel pour les options, mais c’est plutôt clair, pour ceci, nous créons le fichier /etc/authelia/configuration.yml
:
server:
host: 0.0.0.0
port: 9091
theme: dark
server:
read_buffer_size: 4096
write_buffer_size: 4096
path: ""
jwt_secret: XXXXXXXXXXXXXXXXXXXXXXx
default_redirection_url: https://traefik.local:8443
totp:
issuer: traefik.local
period: 30
skew: 1
authentication_backend:
disable_reset_password: false
refresh_interval: 5m
file:
path: /etc/authelia/users.yml
password:
algorithm: argon2id
iterations: 1
key_length: 32
salt_length: 16
memory: 64
parallelism: 8
access_control:
default_policy: deny
rules:
- domain: traefik.traefik.local
subject: "group:admins"
policy: one_factor
session:
name: authelia_session
domain: traefik.local
same_site: lax
secret: XXXXXXXXXXXXXXXXXXXXXXXXX
expiration: 1h
inactivity: 5m
remember_me_duration: 1M
redis:
host: localhost
port: 6379
#password: authelia
database_index: 0
maximum_active_connections: 8
minimum_idle_connections: 0
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
storage:
encryption_key: XXXXXXXXXXXXXXXXXXXX
local:
path: /var/lib/authelia/db.sqlite3
notifier:
disable_startup_check: false
filesystem:
filename: /var/lib/authelia/notification.txt
Nous allons hashé un mot de passe pour nos utilisateurs, pour ce test, nous utiliserons le super mot de passe password
pour tous nos utilisateurs :
$ authelia hash-password password
Password hash: $argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c
Puis nous allons créer notre fichier contenant les utilisateurs, comme indiqué dans la configuration, nous le nommerons /etc/authelia/users.yml
, nous y ajouterons un admin et 5 utilisateurs :
users:
admin:
displayname: "admin"
password: "$argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c"
email: admin@traefik.local
groups:
- admins
user1:
displayname: "user1"
password: "$argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c"
email: user1@traefik.local
groups:
- users
user2:
displayname: "user2"
password: "$argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c"
email: user2@traefik.local
groups:
- users
user3:
displayname: "user3"
password: "$argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c"
email: user3@traefik.local
groups:
- users
user4:
displayname: "user4"
password: "$argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c"
email: user4@traefik.local
groups:
- users
user5:
displayname: "user5"
password: "$argon2id$v=19$m=65536,t=1,p=8$TXJLbFRjYjBhbFhFUFdRVA$Dn4U0j0mu2vgb+PCtFFpOm2SAmeoS0mwuLM+vZGka+c"
email: user5@traefik.local
groups:
- users
Création du service
Nous allons également ajouter un service systemd, nous créons donc un fichier vim /etc/systemd/system/authelia.service
:
[Unit]
Description = Authelia Daemon
After = syslog.target network.target
[Service]
User = authelia
Group = authelia
Type = simple
ExecStart = /usr/local/bin/authelia --config /etc/authelia/configuration.yml
TimeoutStopSec = 20
KillMode = process
Restart = on-failure
WorkingDirectory = /var/lib/authelia
[Install]
WantedBy = multi-user.target
Puis on lance le service :
$ systemctl daemon-reload
$ systemctl enable --now authelia
Created symlink /etc/systemd/system/multi-user.target.wants/authelia.service → /etc/systemd/system/authelia.service.
Configuration de traefik
Maintenant que nous avons authelia qui tourne et qui est fonctionnel, il nous reste à faire la configuration de traefik, nous allons créer un fichier /etc/traefik/conf.d/authelia.yml
:
http:
middlewares:
sso:
forwardAuth:
address: "http://localhost:9091/api/verify?rd=https://sso.traefik.local:8443/"
trustForwardHeader: true
authResponseHeaders:
- Remote-User
- Remote-Groups
- Remote-Name
- Remote-Email
services:
sso:
loadBalancer:
servers:
- url: "http://localhost:9091"
routers:
sso:
rule: "Host(`sso.traefik.local`)"
entryPoints:
- "websecure"
service: "sso@file"
tls:
certResolver: letsencrypt
Normalement, à partir de maintenant, vous avez accès une jolie page d’authetification sur http://sso.traefik.local:8080.
Caddy
Installation
Pour installer caddy, c’est très simple, nous utiliserons le repo de caddy :
$ apt install -y debian-keyring debian-archive-keyring apt-transport-https
$ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | tee /etc/apt/trusted.gpg.d/caddy-stable.asc
$ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
$ apt update && apt install caddy
Configuration
Nous allons créer des répertoires dans /opt, pour 5 applications :
$ for i in 1 2 3 4 5; do mkdir -p /opt/caddy/app${i} && echo "Ceci est l'application n°${i}" > /opt/caddy/app${i}/index.html; done
$ chown -R caddy:caddy /opt/caddy
Puis nous allons editer le fichier /etc/caddy/Caddyfile
:
:9001 {
root * /opt/caddy/app1
file_server
}
:9002 {
root * /opt/caddy/app2
file_server
}
:9003 {
root * /opt/caddy/app3
file_server
}
:9004 {
root * /opt/caddy/app4
file_server
}
:9005 {
root * /opt/caddy/app5
file_server
}
Puis on relance caddy :
systemctl restart caddy
À partir de maintenant, vous avez 5 applications qui vous affichent le numéro de celle-ci.
Configuration de traefik
Cependant, le but étant de pouvoir y accéder avec une authentification, nous créons donc /etc/traefik/conf.d/apps.yml
:
http:
services:
app1:
loadBalancer:
servers:
- url: "http://localhost:9001"
app2:
loadBalancer:
servers:
- url: "http://localhost:9002"
app3:
loadBalancer:
servers:
- url: "http://localhost:9003"
app4:
loadBalancer:
servers:
- url: "http://localhost:9004"
app5:
loadBalancer:
servers:
- url: "http://localhost:9005"
routers:
app1:
rule: "Host(`app1.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app1@file"
tls:
certResolver: letsencrypt
app2:
rule: "Host(`app2.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app2@file"
tls:
certResolver: letsencrypt
app3:
rule: "Host(`app3.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app3@file"
tls:
certResolver: letsencrypt
app4:
rule: "Host(`app4.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app4@file"
tls:
certResolver: letsencrypt
app5:
rule: "Host(`app5.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app5@file"
tls:
certResolver: letsencrypt
Coté traefik, le simple fait d’ajouter le middlewares au router suffit pour lui dire qu’il va devoir passer par authelia.
Amusons nous
Dans cette partie, nous verrons comment configurer nos applications par l’exemple.
Sécurisation de traefik
Traefik étant un dashboard utile pour les administrateurs, seuls le groupe admins doit y avoir accès. Il suffit d’ajouter le middleware à la configuration du router, c’est à dire dans le fichier /etc/traefik/conf.d/traefik.yml
:
http:
routers:
traefik:
rule: "Host(`traefik.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "api@internal"
tls:
certResolver: letsencrypt
Coté authelia on ne fait rien, car on l’avait déjà configuré.
Maintenant, si vous accédez à https://traefik.traefik.local:9443, vous serez redirigé vers https://sso.traefik.local:9443 pour vous authentifier, seul le couple admin/password fonctionnera, les autres utilisateurs n’aurons pas accès.
Sécurisons app1
Nous avons déjà correctement configuré traefik pour toutes les applications, donc pas besoin d’y retourner.
Nous allons ici configurer app1 pour qu’il soit accessible par tous les utilisateurs, nous modifions le fichier /etc/authelia/configuration.yml
et plus particulièrement la partie access_control.rules
:
rules:
- domain: app1.traefik.local
subject:
- "group:admins"
- "group:users"
policy: one_factor
Et il suffit de redémarrer authelia :
$ systemctl restart authelia
Sécurisons app2 et app3
Ici, nous allons en une seul règle, sécuriser les app2 et 3 pour seulement user2 et user3 :
rules:
- domain: ["app2.traefik.local", "app3.traefik.local"]
subject:
- "user:user2"
- "user:user3"
policy: one_factor
Et nous redémarrons.
Sécurisons app4
Pour app4, nous allons l’autoriser que pour user4, mais nous allons activer l’authentification à double facteur :
rules:
- domain: app4.traefik.local
subject:
- "user:user4"
policy: two_factor
Et comme à chaque modification, on relance authelia.
Dans ce cas, et dans le cas d’une première authentification, il vous sera envoyé un mail ou une notification dans le fichier de notification, avec un lien dans ce genre-là : https://sso.traefik.local:8443/one-time-password/register?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJBdXRoZWxpYSIsImV4cCI6MTY0MjIwNzE0MywiaWF0IjoxNjQyMjA2ODQzLCJqdGkiOiJkNmQ3MWUxNS03NTlhLTExZWMtYjQxNC01MjU0MDBlMzg3ZTkiLCJhY3Rpb24iOiJSZWdpc3RlclRPVFBEZXZpY2UiLCJ1c2VybmFtZSI6InVzZXI0In0.8-N5QVWhXezrETrqYbL-dTsLdmlVh5ibfvghBIeQhJQ
Celui-ci vous permettra d’avoir le Qrcode afin de l’enregistrer dans votre application de TOTP.
Laissons app5 ouvert
Nous pouvons également laisser ouvert l’accès, sans authentification, ce qui permet par exemple d’ajouter le middleware sso par défaut à toutes les applications.
rules:
- domain: app5.traefik.local
policy: bypass
Rediriger la même url vers 2 services différents en fonction de l’utilisateur
Pour ce dernier exemple, nous allons depuis l’url https://app.traefik.local:9443 vers app1 ou app2 en fonction de l’utilisateur.
Nous ajoutons donc une règle à authelia :
rules:
- domain: app.traefik.local
subject:
- "user:user1"
- "user:user2"
policy: one_factor
Puis nous allons avoir une petite configuration niveau traefik, dans le fichier /etc/traefik/conf.d/apps.yml
.
Nous commençons par rajouter un service, qui pointera sur un router :
services:
app:
loadBalancer:
servers:
- url: "https://app.traefik.local:8443"
Il faut évidemment que le domaine app.traefik.local soit connu du serveur.
Puis nous créons 2 routers :
routers:
app:
rule: "Host(`app.traefik.local`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app@file"
tls:
certResolver: letsencrypt
app-user1:
rule: "Host(`app.traefik.local`) && Headers(`Remote-User`,`user1`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app1@file"
tls:
certResolver: letsencrypt
app-user2:
rule: "Host(`app.traefik.local`) && Headers(`Remote-User`,`user2`)"
entryPoints:
- "websecure"
middlewares:
- "sso@file"
service: "app2@file"
tls:
certResolver: letsencrypt
Normalement à partir de là, user1 devrait accéder à app1 et user2 à app2.
Cependant là, je pense qu’il faut quelques explications Pour faire ceci, il n’y a pas de condition
if
sous traefik, donc nous devons passer par les headers. Authelia fourni plusieurs headers (Remote-User, Remote-Group etc …). Authelia étant un middleware, c’est l’application derrière le reverse qui reçoit ce header, mais notre application ne sais pas gérer directement ceci, et traefik n’a à ce moment aucun connaissance de l’existance de ce header. L’astuce revient donc à repasser par traefik après authelia, en retapant directement sur lui-même, afin de lui transmettre l’header. Traefik refait un check de l’authentification, et valide donc celle-ci.
Conclusion
Je pense que je vous ai appris tout ce que je pouvais, et que maintenant vous n’avez plus aucune raison de continuer à utiliser auth_basic. Bien évidemment, il est possible d’utiliser authelia avec nginx ou HAProxy.
Si le sujet vous interesse, je ne peux que vous conseillez d’aller voir la documentation officiel.
Ressource
- Documentation Authelia : https://www.authelia.com/docs/
- Documentation Traefik : https://doc.traefik.io/traefik/