# Auth Stack — LLDAP + Authelia + Redis (DSM 7.3 / Synology DS220+)

## Objectif
Fournir une pile d’authentification robuste (anti-lockout) pour protéger des services web via reverse-proxy :
- Annuaire utilisateurs : **LLDAP**
- Portail / SSO / MFA : **Authelia**
- Cache/sessions (optionnel selon config) : **Redis**
- Exposition publique : **Reverse proxy** (Synology / Nginx / Traefik) vers Authelia

---

## Architecture

### Composants
- **LLDAP**
  - UI admin (HTTP) : `127.0.0.1:17170`
  - LDAP : `127.0.0.1:3890`
  - Base : sqlite dans `/volume2/docker/auth/data/lldap`

- **Authelia**
  - API/portal : `127.0.0.1:9091`
  - Stockage : sqlite dans `/volume2/docker/auth/data/authelia/db.sqlite3`
  - Accès externe : via reverse proxy -> `https://auth.<domaine>`

- **Redis**
  - Local uniquement : `127.0.0.1:6379`
  - (peut servir plus tard à sessions/rate-limit selon config)

### Exposition réseau (principe de sécurité)
- Tous les services **bindés sur 127.0.0.1** (loopback NAS)
- Seul le **reverse proxy** expose `https://auth.<domaine>` vers `127.0.0.1:9091`

---

## Fichiers de référence

### 1) docker-compose.auth.yml
- Déploie redis + lldap + authelia.
- Recommandation DSM : **network_mode: host** + bind sur localhost.
  - Supprime les aléas “bridge + DNS + subnets”
  - Évite les timeouts LDAP sporadiques.

### 2) /volume2/docker/auth/compose/.env
Variables attendues :

#### LLDAP
- `LLDAP_JWT_SECRET=...` (random 32+)
- `LLDAP_KEY_SEED=...` (random 32+)
- `LLDAP_LDAP_USER_PASS=...` (mot de passe admin LLDAP)

#### Authelia
- `AUTHELIA_JWT_SECRET=...` (utilisé ici comme source pour reset_password)
- `AUTHELIA_SESSION_SECRET=...`
- `AUTHELIA_STORAGE_ENCRYPTION_KEY=...`

> Ne jamais committer `.env`. Stocker dans DSM / secrets.

### 3) /volume2/docker/auth/config/authelia/configuration.yml
- LDAP address en mode robuste : `ldap://127.0.0.1:3890`
- Cookie domain : `archicratie.trans-hands.synology.me`
- `authelia_url` : `https://auth.archicratie.trans-hands.synology.me`
- `default_redirection_url` : service principal (ex: gitea)

---

## Procédures opératoires

### Restart safe (redémarrage propre)
en bash :
cd /volume2/docker/auth/compose
sudo docker compose --env-file .env -f docker-compose.auth.yml down --remove-orphans
sudo docker compose --env-file .env -f docker-compose.auth.yml up -d --force-recreate

### Tests santé (sans dépendances DSM)
curl -fsS http://127.0.0.1:17170/ >/dev/null && echo "LLDAP UI OK"
curl -fsS http://127.0.0.1:9091/api/health && echo "AUTHELIA LOCAL OK"
curl -kfsS https://auth.archicratie.trans-hands.synology.me/api/health && echo "AUTHELIA HTTPS OK"

### Test TCP LDAP :
sudo docker run --rm --network host nicolaka/netshoot:latest sh -lc 'nc -vz -w2 127.0.0.1 3890'

### Rotate secrets (rotation)

# Principes :

Rotation = redémarrage forcé d’Authelia (sessions invalidées)

Rotation de LLDAP_KEY_SEED est sensible : peut affecter chiffrement des mots de passe.

# Procédure conseillée :

Sauvegarder DBs :

/volume2/docker/auth/data/lldap/users.db

/volume2/docker/auth/data/authelia/db.sqlite3

Changer d’abord secrets Authelia (AUTHELIA_SESSION_SECRET, AUTHELIA_STORAGE_ENCRYPTION_KEY)

docker compose up -d --force-recreate authelia

Vérifier /api/health + login.

Reset admin LLDAP (break-glass)

# Si tu perds le mot de passe admin :

Activer temporairement LLDAP_FORCE_LDAP_USER_PASS_RESET=true dans l’environnement LLDAP

Redémarrer LLDAP une seule fois

Désactiver immédiatement après.

⚠️ Ne jamais laisser ce flag en permanence : il force le reset à chaque boot.

## Checklist anti-lockout (indispensable)
### 1) Accès direct local (bypass)

LLDAP UI accessible en local : http://127.0.0.1:17170

Authelia health local : http://127.0.0.1:9091/api/health

### 2) Règle Authelia : domaine auth en bypass

Dans configuration.yml :
access_control:
  rules:
    - domain: "auth.<domaine>"
      policy: bypass

But : pouvoir charger le portail même si les règles des autres domaines cassent.

### 3) Route de secours reverse-proxy

Prévoir une route non protégée (ou protégée différemment) pour pouvoir corriger :

ex: https://admin.<domaine>/ ou un vhost interne LAN-only.

### 4) Fenêtre privée pour tester

Toujours tester login/authelia dans un onglet privé pour éviter cookies “fantômes”.

## Troubleshooting (ce qu’on a rencontré et résolu)
### A) YAML/Compose cassé (tabs, doublons)

# Symptômes :

mapping key "ports" already defined

found character that cannot start any token

# Fix :

supprimer tabs

supprimer doublons (volumes/ports/networks)

valider : docker compose ... config

### B) Substitution foireuse des variables dans healthcheck

# Problème :

$VAR évalué par compose au parse-time

# Fix :

utiliser $$VAR dans CMD-SHELL si nécessaire.

### C) /config monté read-only

# Symptômes :

chown: /config/... Read-only file system

# Fix :

monter /config en :rw si Authelia doit écrire des backups/keys.

### D) Timeouts LDAP aléatoires en bridge

# Symptômes :

dial tcp <ip>:3890: i/o timeout

IP Docker “surprise” (subnet 192.168.32.0/20 etc.)

# Fix robuste DSM :

passer en network_mode: host + bind 127.0.0.1

Authelia -> ldap://127.0.0.1:3890

### E) “Authelia OK mais Gitea redemande login”

# Normal :

tant que Gitea n’est pas configuré en OIDC vers Authelia, ce n’est pas du SSO.

Authelia protège l’accès, mais ne crée pas de session Gitea.

