feat(security): Authelia — SSO для домашних сервисов (envoy-internal) #54

Closed
hermes wants to merge 23 commits from feat/authelia into main
hermes commented 2026-09-19 20:40:24 +00:00 (Migrated from git.grachevko.ru)

Поднимает Authelia — SSO для домашних сервисов, которые пойдут через envoy-internal. Порядок согласован ранее: сначала Authelia, потом Hindsight (второй MR).

Что в PR

файл что делает
authelia/ks.yaml Flux Kustomization (dependsOn на cloudnative-pg, dragonfly-operator в database и external-secrets-stores; healthChecks на HelmRelease)
app/helmrelease.yaml Authelia на app-template (5.2.1): конфиг в ConfigMap, три реплики, uid 1000, read-only корневая ФС, сервис authelia:9091, HTTPRoute sso.<домен> на envoy-internal
app/postgres.yaml CNPG Cluster/postgres: instances: 3, 1 ГиБ, SC proxmox-ssd
app/dragonfly.yaml Dragonfly/dragonfly под сессии: 1 реплика, --maxmemory из лимита, пароль из секрета
app/externalsecret.yaml Vault kv/authelia → Secret authelia (три ключа + users_database.yml)
app/externalsecret-dragonfly.yaml генератор ESO Password/dragonfly + ExternalSecret/dragonfly (refreshInterval: 0)

Своих ocirepository.yaml и httproute.yaml нет: источник чарта — общий flux-system/app-template, маршрут — в route.internal того же HelmRelease (как у firecrawl).

Где что хранится (три разных места, не одно)

  • Пользователи и argon2-хеши — users_database.yml. У Authelia два бэкенда первого фактора — file и ldap (официальная JSON-схема v4.39), SQL-бэкенда нет; файл не «лишний», а единственный вариант без LDAP-каталога.
  • Postgres — не про пользователей, а про состояние: authentication_logs (попытки по username), identity_verification (токены подтверждения), totp_configurations, webAuthn/u2f, user_preferences, encryption, migrations (по миграциям internal/storage/migrations/postgres v4.39.24), позже — таблицы OIDC (consent/PAR/device code/claims) и regulation.
  • Сессии — Dragonfly (session.redis), не Postgres.

Поэтому и ФС БД — 1 ГиБ: там несколько десятков строк, а не данные, которые растут с пользователями.

Почему app-template, а не официальный чарт Authelia

Так было в плане и это подтверждается фактами: сам чарт в README заявляет «No stability guarantees — Anything may change in any release including a breaking change» (ломающие релизы 0.5/0.9/0.10/0.11), а его значения — свой диалект поверх конфига Authelia. С app-template конфиг — обычный configuration.yml, а реплик можно держать три.

Проверки

  • Конфиг Authelia — официальная JSON-схема v4.39 через jsonschema: 0 ошибок.
  • Values — values.schema.json установленного app-template (тег из main): 0 ошибок.
  • flate test all — 72 passed; flate build all + разбор рендера: 3 реплики, uid/fsGroup 1000, readOnlyRootFilesystem: true, /tmp — tmpfs, каждый AUTHELIA_*_FILE указывает внутрь смонтированного тома, Service/authelia:9091, HTTPRoute/authelia → authelia:9091.
  • Все 8 файлов сверены байт-в-байт с веткой; удалённые отдают 404.

Решения, которые стоит видеть в ревью

  1. Три реплики — Authelia stateless (сессии в Dragonfly, пользователи в файле, состояние в Postgres).
  2. Секретов в конфиге нет: только env AUTHELIA_*_FILE, файлы — из секретов ESO/CNPG/генератора.
  3. Notifier не пишет на диск: у Authelia ровно два провайдера (filesystem/smtp, «must configure exactly one»); выбран filesystem с файлом в tmpfs (/tmp, emptyDir medium: Memory), стартовая проверка включена.
  4. uid 1000 + readOnlyRootFilesystem: entrypoint.sh v4.39.24 ветку chown -R ${PUID}:${PGID} /config берёт только под root, при id -u != 0 — просто exec authelia.
  5. Пароль Dragonfly не ротируется сам (refreshInterval: 0): генератор ESO stateless, оператор Dragonfly за Secret'ами не следит; ротация — руками (удалить секрет → reloader перекатит обе стороны).
  6. Файл пользователей read-only: смена пароля в портале не заработает (только обновление Vault + рестарт пода). Если самообслуживание нужно — файл на PVC, скажи, добавлю.
  7. Защита маршрутов — отдельным MR (SecurityPolicy + ReferenceGrant вместе с первым защищённым маршрутом).

После мёржа

  1. Vault kv/authelia — уже создан, ESO подхватит после flux reconcile.
  2. DNS — уже есть: :resolve sso.grachevko.ru на rb5009-gw → 192.168.40.11. Остаточная A-запись sso.grachevko.ru A 192.168.1.2 (комментарий «old cluster h1») предложена к удалению отдельно — сейчас её перебивает CNAME.
  3. Проверка: три пода postgres, под dragonfly, три пода authelia; вход на https://sso.<домен> (TOTP — при первом входе).
Поднимает Authelia — SSO для домашних сервисов, которые пойдут через `envoy-internal`. Порядок согласован ранее: сначала Authelia, потом Hindsight (второй MR). ## Что в PR | файл | что делает | |---|---| | `authelia/ks.yaml` | Flux Kustomization (`dependsOn` на `cloudnative-pg`, `dragonfly-operator` в `database` и `external-secrets-stores`; `healthChecks` на HelmRelease) | | `app/helmrelease.yaml` | Authelia на **app-template** (5.2.1): конфиг в ConfigMap, три реплики, uid 1000, read-only корневая ФС, сервис `authelia:9091`, HTTPRoute `sso.<домен>` на `envoy-internal` | | `app/postgres.yaml` | CNPG `Cluster/postgres`: `instances: 3`, **1 ГиБ**, SC `proxmox-ssd` | | `app/dragonfly.yaml` | `Dragonfly/dragonfly` под сессии: 1 реплика, `--maxmemory` из лимита, пароль из секрета | | `app/externalsecret.yaml` | Vault `kv/authelia` → Secret `authelia` (три ключа + `users_database.yml`) | | `app/externalsecret-dragonfly.yaml` | генератор ESO `Password/dragonfly` + `ExternalSecret/dragonfly` (`refreshInterval: 0`) | Своих `ocirepository.yaml` и `httproute.yaml` нет: источник чарта — общий `flux-system/app-template`, маршрут — в `route.internal` того же HelmRelease (как у firecrawl). ## Где что хранится (три разных места, не одно) - **Пользователи и argon2-хеши — `users_database.yml`.** У Authelia два бэкенда первого фактора — `file` и `ldap` (официальная JSON-схема v4.39), SQL-бэкенда нет; файл не «лишний», а единственный вариант без LDAP-каталога. - **Postgres — не про пользователей, а про состояние:** `authentication_logs` (попытки по username), `identity_verification` (токены подтверждения), `totp_configurations`, webAuthn/u2f, `user_preferences`, `encryption`, `migrations` (по миграциям `internal/storage/migrations/postgres` v4.39.24), позже — таблицы OIDC (consent/PAR/device code/claims) и regulation. - **Сессии — Dragonfly** (`session.redis`), не Postgres. Поэтому и ФС БД — 1 ГиБ: там несколько десятков строк, а не данные, которые растут с пользователями. ## Почему app-template, а не официальный чарт Authelia Так было в плане и это подтверждается фактами: сам чарт в README заявляет «**No stability guarantees** — Anything may change in any release including a breaking change» (ломающие релизы 0.5/0.9/0.10/0.11), а его значения — свой диалект поверх конфига Authelia. С app-template конфиг — обычный `configuration.yml`, а реплик можно держать три. ## Проверки - Конфиг Authelia — официальная JSON-схема `v4.39` через `jsonschema`: **0 ошибок**. - Values — `values.schema.json` установленного app-template (тег из `main`): **0 ошибок**. - `flate test all` — **72 passed**; `flate build all` + разбор рендера: 3 реплики, uid/fsGroup 1000, `readOnlyRootFilesystem: true`, `/tmp` — tmpfs, каждый `AUTHELIA_*_FILE` указывает внутрь смонтированного тома, `Service/authelia:9091`, `HTTPRoute/authelia` → `authelia:9091`. - Все 8 файлов сверены байт-в-байт с веткой; удалённые отдают 404. ## Решения, которые стоит видеть в ревью 1. **Три реплики** — Authelia stateless (сессии в Dragonfly, пользователи в файле, состояние в Postgres). 2. **Секретов в конфиге нет**: только env `AUTHELIA_*_FILE`, файлы — из секретов ESO/CNPG/генератора. 3. **Notifier не пишет на диск**: у Authelia ровно два провайдера (`filesystem`/`smtp`, «must configure exactly one»); выбран `filesystem` с файлом в tmpfs (`/tmp`, `emptyDir medium: Memory`), стартовая проверка включена. 4. **uid 1000 + `readOnlyRootFilesystem`**: `entrypoint.sh` v4.39.24 ветку `chown -R ${PUID}:${PGID} /config` берёт только под root, при `id -u != 0` — просто `exec authelia`. 5. **Пароль Dragonfly не ротируется сам** (`refreshInterval: 0`): генератор ESO stateless, оператор Dragonfly за Secret'ами не следит; ротация — руками (удалить секрет → reloader перекатит обе стороны). 6. **Файл пользователей read-only**: смена пароля в портале не заработает (только обновление Vault + рестарт пода). Если самообслуживание нужно — файл на PVC, скажи, добавлю. 7. **Защита маршрутов** — отдельным MR (`SecurityPolicy` + `ReferenceGrant` вместе с первым защищённым маршрутом). ## После мёржа 1. Vault `kv/authelia` — **уже создан**, ESO подхватит после `flux reconcile`. 2. DNS — **уже есть**: `:resolve sso.grachevko.ru` на `rb5009-gw` → `192.168.40.11`. Остаточная A-запись `sso.grachevko.ru A 192.168.1.2` (комментарий «old cluster h1») предложена к удалению отдельно — сейчас её перебивает CNAME. 3. Проверка: три пода `postgres`, под `dragonfly`, три пода `authelia`; вход на `https://sso.<домен>` (TOTP — при первом входе).

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
grachevko/home-ops!54
No description provided.