Aller au contenu

Authentik (+ Traefik & Crowdsec)

Ce guide vous explique comment déployer Authentik dans Docker, protégé derrière le reverse proxy Traefik et le bouclier de sécurité CrowdSec.

Pourquoi cette architecture ?

  • Surface d’exposition minimale : seuls les ports 80 (HTTP) et 443 (HTTPS) de Traefik sont ouverts sur Internet, la base PostgreSQL, Redis et les conteneurs Authentik restent cantonnés au réseau interne Docker.

  • Certificats TLS sans effort : Traefik obtient et renouvelle automatiquement les certificats Let’s Encrypt, vous n’avez plus à gérer la couche HTTPS manuellement.

  • Protection active des services : CrowdSec surveille les journaux d’accès de Traefik. À la moindre tentative d’attaque (scan, brute-force…), l’adresse IP fautive est bannie automatiquement pour une durée configurable.

En suivant ce guide, vous disposerez donc :

  • d’un SSO moderne avec Authentik;

  • d’un HTTPS entièrement automatisé;

  • d’un pare-feu dynamique qui réagit en temps réel aux menaces.

Installation via Docker

Installez le docker-compose et générez le mot de passe de la base de données et la clé secrète de Authentik en suivant la partie Preparation# de la documentation officielle.

Configuration Docker

Je fournis ici des exemples de fichiers de configuration à adapter :

Fichier .env

N'oubliez pas de générer le mot de passe de la base de données et la clé secrète de Authentik
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env

Exemple de fichier .env avec notifications SMTP :

# Les secrets
PG_PASS=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AUTHENTIK_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxx

# LOG des erreurs
AUTHENTIK_ERROR_REPORTING__ENABLED=true

# Version cible d’Authentik
AUTHENTIK_TAG=2025.6.0 

#########################
# NOTIFICATIONS SMTP
#########################

# SMTP Host Emails are sent to
AUTHENTIK_EMAIL__HOST=mail.domaine.fr
AUTHENTIK_EMAIL__PORT=587
# Optionally authenticate (don't add quotation marks to your password)
AUTHENTIK_EMAIL__USERNAME=smtp@domaine.fr
AUTHENTIK_EMAIL__PASSWORD=xxxxxxxxx
# Use StartTLS
AUTHENTIK_EMAIL__USE_TLS=true
# Use SSL
AUTHENTIK_EMAIL__USE_SSL=false
AUTHENTIK_EMAIL__TIMEOUT=10
# Email address authentik will send from, should have a correct @domain
AUTHENTIK_EMAIL__FROM=authentik@domaine.fr

Fichier docker-compose.yaml

Voici un exemple complet et fonctionnel du fichier docker-compose.yaml. Il permet de déployer les services suivants :

  • Traefik comme reverse proxy qui s’occupe de gérer les connexions web (HTTP/HTTPS) et les certificats de sécurité TLS grâce à Let's Encrypt;

  • Authentik pour la gestion de l’authentification avec PostgreSQL comme base de données et Redis pour la gestion des files de tâches (cache);

  • CrowdSec pourra aussi y être connecté pour analyser les logs de Traefik et détecter les comportements suspects. Ce fichier configure les volumes nécessaires, notamment pour que CrowdSec puisse lire les journaux d’accès générés par Traefik.

services:
  ################################################################
  # Traefik (reverse proxy + Let's Encrypt)
  ################################################################
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    command:
      # --- Entrypoints (HTTP :80, HTTPS :443) ---
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"

      # --- API/Dashboard (optionnel) ---
      - "--api.dashboard=true"

      # --- Configuration du resolver Let's Encrypt (ACME) ---
      - "--certificatesresolvers.myresolver.acme.email=EMAIL@DOMAINE.FR"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"

      # --- Activation du provider Docker ---
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"

      # --- LOG au format JSON pour parser CrowdSec ---
      - "--accesslog.filepath=/var/log/traefik/access.log"   # chemin dans le conteneur
      - "--accesslog.format=json"                            # format le plus simple à parser

    ports:
      - "80:80"
      - "443:443"
    volumes:
      # Monte acme.json en lecture/écriture (pour stocker les certificats)
      - ./acme.json:/letsencrypt/acme.json
      # Accès en lecture seule au socket Unix Docker (pour lire les labels et accès docker)
      - /var/run/docker.sock:/var/run/docker.sock:ro
      # Monte le dossier de LOG sur l'hôte (pour parser Crowdsdec)
      - /var/log/traefik:/var/log/traefik

    networks:
      - authentik_net

  ################################################################
  # PostgreSQL
  ################################################################
  postgresql:
    image: docker.io/library/postgres:16-alpine
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - database:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${PG_PASS:?database password required}
      POSTGRES_USER: ${PG_USER:-authentik}
      POSTGRES_DB: ${PG_DB:-authentik}
    env_file:
      - .env
    networks:
      - authentik_net

  ################################################################
  # Redis
  ################################################################
  redis:
    image: docker.io/library/redis:alpine
    command: --save 60 1 --loglevel warning
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 3s
    volumes:
      - redis:/data
    networks:
      - authentik_net

  ################################################################
  # Authentik Server
  ################################################################
  server:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG}
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
    volumes:
      - ./media:/media
      - ./custom-templates:/templates
    env_file:
      - .env
    depends_on:
      postgresql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - authentik_net
    labels:
      # On active explicitement la publication via Traefik
      - "traefik.enable=true"

      # Redirection HTTP -> HTTPS
      - "traefik.http.routers.authentikserver-web.rule=Host(`FQDN`)"
      - "traefik.http.routers.authentikserver-web.entrypoints=web"
      - "traefik.http.routers.authentikserver-web.middlewares=redirect-to-https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"

      # Routage HTTPS vers le port 9000 interne
      - "traefik.http.routers.authentikserver.rule=Host(`FQDN`)"
      - "traefik.http.routers.authentikserver.entrypoints=websecure"
      - "traefik.http.routers.authentikserver.tls=true"
      - "traefik.http.routers.authentikserver.tls.certresolver=myresolver"
      - "traefik.http.services.authentikserver.loadbalancer.server.port=9000"

  ################################################################
  # Authentik Worker
  ################################################################
  worker:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG}
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
    user: root
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./media:/media
      - ./certs:/certs
      - ./custom-templates:/templates
    env_file:
      - .env
    depends_on:
      postgresql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - authentik_net

volumes:
  database:
    driver: local
  redis:
    driver: local

networks:
  authentik_net:
    driver: bridge

Lancement

1) Avant de démarrer les conteneurs, exécutez touch acme.json && chmod 600 acme.json dans le même répertoire que le docker-compose afin de fournir à Traefik un fichier ACME déjà présent et restreint en lecture/écriture root. C’est dans ce fichier protégé qu’il enregistre sa clé de compte et les certificats Let’s Encrypt.

2) Y'a plus qu'à lancer !

docker compose pull
docker compose up -d

Securisation Crowdsec

1) Dans le fichier /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml, décommentez la ligne DOCKER-USERdans la section iptables_chains.

2) Traefik écrit son access-log JSON dans le dossier monté /var/log/traefik sur l’hôte. CrowdSec lit ce fichier grâce à /etc/crowdsec/acquis.yaml

Exemple de fichier acquis.yaml :

#Generated acquisition file - wizard.sh (service: ssh) / files : 
journalctl_filter:
 - _SYSTEMD_UNIT=ssh.service
labels:
  type: syslog
---
# Lecture des LOG Traefik (format JSON)
filenames:
  - /var/log/traefik/access.log
labels:
  type: traefik

3) La collection crowdsecurity/traefik détecte les bruteforce sur Authentik.

cscli collection install crowdsecurity/traefik

4) Le bouncer pare-feu bloque automatiquement l’IP (tous ports) pendant 4 h par défaut.

Configuration Authentik

Configuration initiale

Pour lancer l'assistant de configuration, naviguez à l'adresse http://IP_ou_FQDNx/if/flow/initial-setup/

Provider

Suivez la doc officielle qui est complète et régulièrement mise à jour pour configurer vos providers !

https://docs.goauthentik.io/integrations/services/

Notification

  • Notifications transport
  • Notification rules personnalisées.

Références

https://une-tasse-de.cafe/blog/goauthentik/