docs: add auth stack + main protected PR workflow
This commit is contained in:
201
docs/auth-stack.md
Normal file
201
docs/auth-stack.md
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
67
docs/gitea-pr-main-protege.md
Normal file
67
docs/gitea-pr-main-protege.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Workflow Git/Gitea — main protégé (PR only)
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
Éviter toute casse de `main` : on travaille **toujours** via branche + Pull Request.
|
||||||
|
|
||||||
|
## 1) Démarrer propre (local)
|
||||||
|
en bash :
|
||||||
|
|
||||||
|
git fetch origin --prune
|
||||||
|
git checkout main
|
||||||
|
git reset --hard origin/main
|
||||||
|
git clean -fd
|
||||||
|
|
||||||
|
## 2) Créer une branche
|
||||||
|
|
||||||
|
git checkout -b fix/ma-modif
|
||||||
|
|
||||||
|
## 3) Modifier, tester, commit
|
||||||
|
|
||||||
|
npm test
|
||||||
|
git add -A
|
||||||
|
git commit -m "Mon changement"
|
||||||
|
|
||||||
|
## 4) Push (création branche distante)
|
||||||
|
|
||||||
|
git push -u origin fix/ma-modif
|
||||||
|
|
||||||
|
## 5) Créer la Pull Request (UI Gitea)
|
||||||
|
|
||||||
|
Gitea → repository → Pull Requests → New Pull Request
|
||||||
|
|
||||||
|
base : main
|
||||||
|
compare : fix/ma-modif
|
||||||
|
|
||||||
|
Si “je ne vois pas de PR”
|
||||||
|
|
||||||
|
Vérifie d’abord qu’il y a un diff réel :
|
||||||
|
|
||||||
|
git log --oneline origin/main..HEAD
|
||||||
|
|
||||||
|
Si la commande ne sort rien : ta branche ne contient aucun commit différent → PR inutile/invisible.
|
||||||
|
|
||||||
|
## 6) Conflits
|
||||||
|
|
||||||
|
Ne merge pas en local vers main (push refusé si main protégé).
|
||||||
|
On met à jour la branche de PR :
|
||||||
|
|
||||||
|
Option A (simple) : merge main dans la branche
|
||||||
|
|
||||||
|
git fetch origin
|
||||||
|
git merge origin/main
|
||||||
|
# résoudre conflits
|
||||||
|
npm test
|
||||||
|
git push
|
||||||
|
|
||||||
|
Option B (plus propre) : rebase
|
||||||
|
|
||||||
|
git fetch origin
|
||||||
|
git rebase origin/main
|
||||||
|
# résoudre conflits, puis:
|
||||||
|
npm test
|
||||||
|
git push --force-with-lease
|
||||||
|
|
||||||
|
## 7) Merge
|
||||||
|
|
||||||
|
Toujours depuis l’UI de la Pull Request (ou via un mainteneur).
|
||||||
|
|
||||||
Reference in New Issue
Block a user