feat(vault): migre vault.opytex.org vers stacks/

Première stack migrée vers le nouveau modèle. Le nom du dossier est
conservé à l'identique : il détermine le nom du projet Compose
(vaultopytexorg) et donc le préfixe des volumes, ce qui permet de
reprendre les données existantes.

- env_file : les 22 variables non sensibles, en clair et diffables
- secrets.env.yaml : ADMIN_TOKEN et SSO_CLIENT_SECRET, chiffrés
- env_file: .env supprimé ; les deux secrets passent par ${VAR:?} pour
  échouer franchement si `sops exec-env` est oublié

Corrections au passage :
- priority=10 sur le router principal. Sans elle Traefik la déduisait de
  la longueur de la règle (23), contre 26 sur le router /admin : trois
  caractères de marge avant que /admin ne perde le forward auth.
- backup.enable sur le volume, qui n'était couvert par aucune sauvegarde.
  À compléter dans MANUAL_VOLUMES : un label n'agit pas sur un volume
  déjà créé.
- version d'image figée (1.35.7) au lieu de latest, détectable par Renovate
- security_opt: no-new-privileges

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit was merged in pull request #1.
This commit is contained in:
2026-08-12 16:38:34 +02:00
parent d619f165f0
commit 4aacd902f1
3 changed files with 166 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
# ============================================================
# Vaultwarden — vault.opytex.org
# ============================================================
# Déploiement :
# sops exec-env secrets.env.yaml 'docker compose up -d'
#
# Le nom du dossier détermine le nom du projet Compose (`vaultopytexorg`,
# les points étant retirés) et donc le préfixe des volumes. Le conserver
# à l'identique est ce qui permet de reprendre les données existantes.
#
# Configuration non sensible : env_file (versionné, en clair).
# Secrets : secrets.env.yaml (chiffré), injectés par `sops exec-env`.
services:
vaultwarden:
# Version en dur, jamais via une variable : c'est ce qui permet à Renovate
# de détecter les montées de version et d'ouvrir une PR.
image: vaultwarden/server:1.35.7
container_name: vaultwarden
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- vaultwarden_data:/data
env_file:
- env_file
environment:
# Les deux seules valeurs sensibles. `${VAR:?}` fait échouer le
# démarrage si `sops exec-env` a été oublié, au lieu de recréer le
# conteneur avec des valeurs vides.
#
# Régénérer le token admin en hash argon2 :
# docker run --rm -it vaultwarden/server:1.35.7 /vaultwarden hash --preset owasp
ADMIN_TOKEN: ${ADMIN_TOKEN:?}
SSO_CLIENT_SECRET: ${SSO_CLIENT_SECRET:?}
networks:
- traefik-proxy
- smtp
labels:
- traefik.enable=true
- traefik.docker.network=traefik-proxy
# --- Router principal (UI + API clients Bitwarden) ---
# `priority` explicite : sans elle, Traefik la déduit de la longueur de
# la règle — 23 pour Host(`vault.opytex.org`), contre 26 forcés sur le
# router /admin. Trois caractères de marge seulement : un domaine plus
# long ferait passer ce router devant, et /admin perdrait le forward auth.
- traefik.http.routers.vaultwarden.entrypoints=web-secure
- traefik.http.routers.vaultwarden.rule=Host(`vault.opytex.org`)
- traefik.http.routers.vaultwarden.priority=10
- traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt
- traefik.http.routers.vaultwarden.service=vaultwarden
- traefik.http.routers.vaultwarden.middlewares=crowdsec@file
# --- /admin : CrowdSec + forward auth Authentik ---
# Porte de secours si le SSO tombe (SSO_ONLY=true côté env_file).
- traefik.http.routers.vaultwarden-admin.entrypoints=web-secure
- traefik.http.routers.vaultwarden-admin.rule=Host(`vault.opytex.org`) && PathPrefix(`/admin`)
- traefik.http.routers.vaultwarden-admin.priority=26
- traefik.http.routers.vaultwarden-admin.tls.certresolver=letsencrypt
- traefik.http.routers.vaultwarden-admin.service=vaultwarden
- traefik.http.routers.vaultwarden-admin.middlewares=crowdsec@file,authentik@file
# --- Callback Authentik (outpost) ---
- traefik.http.routers.vaultwarden-outpost.entrypoints=web-secure
- traefik.http.routers.vaultwarden-outpost.rule=Host(`vault.opytex.org`) && PathPrefix(`/outpost.goauthentik.io/`)
- traefik.http.routers.vaultwarden-outpost.priority=25
- traefik.http.routers.vaultwarden-outpost.tls.certresolver=letsencrypt
- traefik.http.routers.vaultwarden-outpost.service=vaultwarden-outpost-svc
- traefik.http.services.vaultwarden.loadbalancer.server.port=80
- traefik.http.services.vaultwarden-outpost-svc.loadbalancer.server.url=http://authentik:9000
volumes:
# ATTENTION : les labels de volume ne s'appliquent qu'à la CRÉATION. Le volume
# `vaultopytexorg_vaultwarden_data` existe déjà et n'héritera PAS de ce label :
# il faut l'ajouter à MANUAL_VOLUMES dans backup.conf.
vaultwarden_data:
labels:
backup.enable: "true"
networks:
traefik-proxy:
external: true
smtp:
external: true