diff --git a/decisions/2026-06-26-authentik-sso-deploy.md b/decisions/2026-06-26-authentik-sso-deploy.md new file mode 100644 index 0000000..8a9f105 --- /dev/null +++ b/decisions/2026-06-26-authentik-sso-deploy.md @@ -0,0 +1,84 @@ +--- +date: 2026-06-26 +type: decision +tags: [dttb, sso, authentik, oidc, mfa, security] +--- + +# authentik — SSO/IdP для home lab (LXC 144) + +> **Статус:** платформа развёрнута и здорова, пилот OIDC на Open WebUI + Gitea работает (серверная часть). Остался один ручной шаг Олега — первый вход + enrollment 2FA (см. ниже). +> **Домен:** https://auth.dttb.ru · **Контейнер:** LXC 144 (10.0.0.144) + +## Зачем +Единый вход (SSO) + обязательная 2FA на сервисы home lab. Self-hosted IdP, без облака — в линию с уходом от big-tech [[project_deapple_migration]]. + +## Ключевое архитектурное решение: «2FA на всё, но через нужную дверь» +Олег хотел завести **все** сервисы за SSO с 2FA. Лобовой «всё за forward-auth» отвергнут — сломал бы не-браузерные клиенты (которых у нас много). Принято разделение: + +| Схема | Для чего | Почему | +|---|---|---| +| **OIDC/SAML** (вход в веб-морду через authentik+2FA, машинные пути живут штатно) | сервисы с родной поддержкой SSO: Gitea, Nextcloud, Proxmox, Portainer, Open WebUI, Grafana, Home Assistant | не ломает API, git push, WebDAV, мобилки | +| **Forward-auth** (outpost + advanced-config сниппет в NPM) | голые дашборды без логина / на Basic Auth (german, KasmVNC) | NPM не имеет родного auth-поля | +| **Родной 2FA** | Proxmox (встроенный TOTP/WebAuthn), NPM | не закрывать себе путь восстановления через IdP | +| **Не за SSO вообще** | API (OmniRoute omni:20128/v1), webhooks (bot.dttb.ru), не-HTTP (RustDesk, IMAP/SMTP, Matrix federation), Vaultwarden (свой мастер-пароль+2FA) | forward-auth их убьёт / антипаттерн | + +**Почему forward-auth-везде плох именно у нас:** Nextcloud (мобилка/WebDAV/**rclone-bisync KB-синк**), Gitea (git push), OmniRoute API (openclaw/german/swarmclaw/open-webui/code-server), bot webhooks, Mailcow IMAP/SMTP, RustDesk 21115-21119, Home Assistant/Matrix/Plex клиенты — всё это не проходит SSO-редирект. + +## Развёртывание (что сделано) + +### Контейнер LXC 144 +- Debian 12, unprivileged + nesting/keyctl, onboot=1 +- 2 vCPU / 4 GB / swap 2 GB / rootfs 20 GB на storage `work` (local-lvm забит 94%) +- IP статика **10.0.0.144/24**, gw 10.0.0.1, **nameserver 1.1.1.1** (против FakeIP при pull с ghcr — урок [[2026-06-22-open-webui-deploy]]) +- root-пароль LXC: см. credentials +- Docker 29.6 + compose (official get.docker.com) + +### Стек (официальный compose, `/opt/authentik/`) +- `ghcr.io/goauthentik/server:2026.5.3` — **server + worker + postgresql:16-alpine** +- ⚠️ **2026.5.3 ушёл от Redis** — теперь postgres-backed cache (django_postgres_cache). Compose БЕЗ redis. Проще. +- AVX-граблю (как Mongo для UniFi [[2026-06-15-unifi-controller-homelab]]) authentik **не задевает** — Python/PG/нет Mongo. +- `.env`: `PG_PASS`, `AUTHENTIK_SECRET_KEY` (сгенерированы), `AUTHENTIK_BOOTSTRAP_PASSWORD`/`_EMAIL`, порты 9000/9443. Бэкап секретов — в самом `.env` контейнера. +- Миграции БД при первом старте ~3 мин (health 503 в это время — норма, не паниковать). + +### Домен auth.dttb.ru +- **Публичная A-запись** добавлена на Spaceweb: `auth → 176.62.183.186` (нет wildcard — у каждого поддомена своя запись). +- NPM proxy host **id 41** → `10.0.0.144:9000`, **LE cert id 133**, Force SSL + HTTP/2 + WSS. +- Локально/в NetBird `*.dttb.ru` = 10.0.0.195 (wildcard на роутере) — SSO работает и внутри. + +### 2FA — обязательна на уровне IdP +Стейдж `default-authentication-mfa-validation` переведён `not_configured_action: skip → configure`, `configuration_stages = [TOTP-setup, WebAuthn-setup]`. Любой вход без устройства **принуждает** к установке TOTP или passkey. Действует на ВСЕ OIDC-логины (они идут через default-authentication-flow). + +### Пилот OIDC (работает серверно) +| Сервис | authentik app/slug | client_id | redirect_uri | как подключён | +|---|---|---|---|---| +| **Open WebUI** (chat.dttb.ru, LXC 142) | `open-webui` | `1G7PLkPU…` | `https://chat.dttb.ru/oauth/oidc/callback` | контейнер пересоздан с OAuth env, скрипт `/root/recreate-owui.sh`. Локальный логин СОХРАНЁН (`ENABLE_LOGIN_FORM` не трогали), `OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true` | +| **Gitea** (git.dttb.ru, LXC 136) | `gitea` | `AYl8jNZv…` | `https://git.dttb.ru/user/oauth2/authentik/callback` | auth source «authentik» (id 1) через `gitea admin auth add-oauth`. **ROOT_URL изменён** `http://10.0.0.189:3000/ → https://git.dttb.ru/` (иначе callback не совпадал). Бэкап `app.ini.bak-preauthentik-20260626`. git push/SSH не затронуты | + +Секреты client_secret — в credentials. + +## ⚠️ Остался ручной шаг Олега (1 раз) +SSO-вход нельзя докрутить headless — нужен браузер Олега: +1. Зайти на **https://auth.dttb.ru**, логин `akadmin` / пароль (см. credentials). +2. Система **сама предложит установить 2FA** (TOTP — отсканировать QR в Google Authenticator/2FAS, или passkey). Установить. +3. Проверить вход через SSO: на chat.dttb.ru кнопка «Continue with authentik», на git.dttb.ru «Sign in with authentik». +4. (Опц.) создать личного пользователя `oleg` вместо akadmin, akadmin оставить как break-glass. + +## Плюсы / минусы +**Плюсы:** единый вход + 2FA на все совместимые сервисы; централизованное управление (можно выдавать семье/клиентам скоуп-доступ); forward-auth прикроет голые панели; self-hosted; журнал входов. +**Минусы/риски (и митигация):** +- **SPOF/lockout:** упал authentik → нет SSO-входа. → критичную инфру (Proxmox/NPM/Vaultwarden) НЕ гейтим, у сервисов сохраняем родной admin-логин как fallback. +- **Публичный IdP = поверхность атаки.** → обязательная 2FA (включена), сильные пароли. Опц. позже: geo/fail2ban, ограничить admin LAN-only. +- **Лок единственного админа** при кривом MFA-flow. → recovery через API-токен (минует flow) и `ak shell` (см. ниже). + +## Recovery / управление +- API-токен (минует login-flow): `claude-bootstrap` — в credentials. `curl https://auth.dttb.ru/api/v3/core/users/me/ -H "Authorization: Bearer "`. +- Сбросить пароль akadmin: `pct exec 144 -- bash -c "cd /opt/authentik && echo 'akadmin ' | docker compose exec -T server ak change_password akadmin"` (или через `ak shell`). +- Снять обязательную 2FA (если залочило): PATCH стейджа `f3808685-…` `not_configured_action=skip` через API-токен. +- Логи: `cd /opt/authentik && docker compose logs server|worker`. +- Обновление: бампить `AUTHENTIK_TAG` в `/opt/authentik/.env` → `docker compose pull && up -d`. + +## Spaceweb DNS — найден read-метод API +К [[../projects/dttb/spaceweb-dns]]: метод чтения зоны = **`info`** (`params {domain}`), возвращает все записи с `index`/`category`. Существующие методы: `editMain`, `editMx`, `editTxt`, `info`. Добавление одной A-записи `editMain {action:"add",name,type:"A",value,prefix:""}` — безопасно (ломает зону только цикл). + +## Дальше (отдельными задачами, по согласованию) +Полный OIDC-роллаут: Proxmox (realm OpenID Connect), Nextcloud (app `user_oidc`/`sociallogin`), Portainer, Home Assistant, Grafana. Forward-auth demo на german.dttb.ru (Basic Auth → outpost). См. раздел «нужная дверь» выше. diff --git a/projects/dttb/credentials.md b/projects/dttb/credentials.md index 02ee90d..cdddd00 100644 --- a/projects/dttb/credentials.md +++ b/projects/dttb/credentials.md @@ -156,6 +156,20 @@ cd /var/lib/rustdesk-api && /usr/bin/rustdesk-api reset-admin-pwd | systemd | `hermes-dashboard.service` = `hermes dashboard --host 0.0.0.0 --port 9119 --skip-build --no-open` | | ⚠️ Грабля | **БЕЗ `--insecure`!** `--insecure` отключает cookie-gate (включает легаси `_SESSION_TOKEN`) → login проходит, но всё внутри 401. Бинд `0.0.0.0` без `--insecure` = `auth_required=True` + принимает любой Host (для NPM-домена). См. [[../../decisions/2026-06-18-german-hermes-agent-deploy]] | +## authentik SSO/IdP (LXC 144) + +| Параметр | Значение | +|----------|----------| +| URL | https://auth.dttb.ru (NPM #41 → 10.0.0.144:9000, LE cert id133) | +| LXC root | `10.0.0.144` — root / `Authentik!2026-dttb` (LAN only, без WAN SSH) | +| Admin панель | `akadmin` / `Auth0leg!2026-dttb` (bootstrap-пароль). **2FA обязательна** — при первом входе предложит TOTP/passkey | +| Email admin | `it5870@yandex.ru` | +| API-токен | `claude-bootstrap` = `z53t4jfarH69EBYuJJbY0olaak79Sf67W1EqVCCM6NVHXbQDAAuyXHfVP4VZ` (не истекает, минует login-flow — для управления/recovery) | +| Стек | `/opt/authentik/` — `.env` хранит `PG_PASS` и `AUTHENTIK_SECRET_KEY` (сгенерированы рандомом, бэкап только в `.env` контейнера) | +| OIDC Open WebUI | app `open-webui`, client_id `1G7PLkPUSCEK4EFyULcDbqBnADrRNnswXOHFOeEF`, secret `2vpQldlISZDGyQaTQeVZ070XkA879a0TaMCeYIPQaA0ln116sQqJNzj9AjSMjvTz4yFTXw89V0wGb5yMP1CfqVCE0UehcvI9RsgCtjrFaSp0lrDD1NCwp9SrDGtfcF2A` | +| OIDC Gitea | app `gitea`, client_id `AYl8jNZvJF7jh4c2nPhm1nRtD2XwkUK0DPwnvQ9e`, secret `UwsqG97S5REcuSgQLFQUHGp0JDKScR7fSIuIminNaZoVKca2JQzbb0PebePeBeaQhFKPjJOlu3kEmEEzod0oGtIArHKH492SnUBMO5aa5FgnAGjGzm9BB4RRYJo7wEMQ` | +| Recovery | сброс admin-пароля `ak change_password akadmin`; снять обяз. 2FA — PATCH стейджа `f3808685-…` `not_configured_action=skip` через API-токен. См. [[../../decisions/2026-06-26-authentik-sso-deploy]] | + ## SSH-ключи и доступы | Хост | Порт | Метод | diff --git a/projects/dttb/npm-proxy-hosts.md b/projects/dttb/npm-proxy-hosts.md index b013f71..53e5e25 100644 --- a/projects/dttb/npm-proxy-hosts.md +++ b/projects/dttb/npm-proxy-hosts.md @@ -9,7 +9,7 @@ tags: [dttb, npm] > **NPM LXC:** 103 (10.0.0.195) > **Панель:** https://npm.dttb.ru > -> Последнее обновление: 2026-06-26 (добавлен german.dttb.ru → Hermes Dashboard LXC 141) +> Последнее обновление: 2026-06-26 (добавлен auth.dttb.ru → authentik SSO/IdP LXC 144) --- @@ -17,7 +17,7 @@ tags: [dttb, npm] | Всего хостов | С SSL | Без SSL | Активных | |--------------|-------|---------|----------| -| 23 | 19 | 4 | 23 | +| 24 | 20 | 4 | 24 | --- @@ -54,6 +54,7 @@ tags: [dttb, npm] | 36 | `unifi.dttb.ru` | 10.0.0.196:8443 (HTTPS) | ✅ Let's Encrypt | ✅ | ✅ | ✅ | **UniFi Network Application** (LXC 140) | | 39 | `chat.dttb.ru` | 10.0.0.142:3000 | ✅ Let's Encrypt (id129) | ✅ | ✅ | ✅ | **Open WebUI** (LXC 142) — веб-клиент поверх OmniRoute | | 40 | `german.dttb.ru` | 10.0.0.141:9119 | ✅ Let's Encrypt (id130) | ✅ | ✅ | ✅ | **Hermes Dashboard** (LXC 141) — веб-панель German; basic_auth `oleg`, см. credentials | +| 41 | `auth.dttb.ru` | 10.0.0.144:9000 | ✅ Let's Encrypt (id133) | ✅ | ✅ | ✅ | **authentik SSO/IdP** (LXC 144) — единый вход + 2FA. См. [[../../decisions/2026-06-26-authentik-sso-deploy]] | --- @@ -94,6 +95,7 @@ location /.well-known/matrix/client { | 10.0.0.112 | 8840 | ip.dttb.ru | | 10.0.0.141 | 9119 | german.dttb.ru (Hermes Dashboard) | | 10.0.0.142 | 3000 | chat.dttb.ru (Open WebUI) | +| 10.0.0.144 | 9000 | auth.dttb.ru (authentik SSO/IdP) | | 10.0.0.155 | 8123 | home.dttb.ru | | 10.0.0.169 | 8080 | office.dttb.ru | | 10.0.0.179 | 8080, 20128 | ai.dttb.ru, omni.dttb.ru | diff --git a/projects/dttb/proxmox-inventory.md b/projects/dttb/proxmox-inventory.md index b3fa331..f27bcea 100644 --- a/projects/dttb/proxmox-inventory.md +++ b/projects/dttb/proxmox-inventory.md @@ -9,7 +9,7 @@ tags: [dttb, proxmox] > **Основная нода:** pve (10.0.0.250) — описана ниже > **Вторая нода (standalone):** pve (10.0.0.147) — отдельный хост i3-2100/15GB/SSD+1.8TB HDD, см. [[proxmox-pve-147]] (VM 100 ZimaOS, LXC 101 второй NPM) > -> Последнее обновление: 2026-06-23 (добавлен LXC 143 amnezia-panel — Amnezia Web Panel, control-plane VPN-нод) +> Последнее обновление: 2026-06-26 (добавлен LXC 144 authentik — SSO/IdP, auth.dttb.ru) --- @@ -18,8 +18,8 @@ tags: [dttb, proxmox] | Тип | Всего | Запущено | Остановлено | |-----|-------|----------|-------------| | QEMU VM | 15 | 5 | 10 | -| LXC | 25 | 15 | 10 | -| **Итого** | **40** | **20** | **20** | +| LXC | 26 | 16 | 10 | +| **Итого** | **41** | **21** | **20** | --- @@ -262,6 +262,22 @@ tags: [dttb, proxmox] --- +### LXC 144 — authentik (SSO/IdP) +| Параметр | Значение | +|----------|----------| +| Статус | 🟢 running | +| IP | 10.0.0.144 (LAN, статика, nameserver 1.1.1.1) | +| ОС/рантайм | Debian 12, unprivileged + nesting/keyctl, Docker 29.6 + compose | +| Ресурсы | 2 vCPU / 4 GB / swap 2 GB / 20 GB (rootfs на `work`, local-lvm забит 94%) | +| Стек | `/opt/authentik/` — `ghcr.io/goauthentik/server:2026.5.3`: **server + worker + postgresql:16** (⚠️ 2026.5.3 без Redis, postgres-backed cache) | +| Веб | **https://auth.dttb.ru** (NPM #41 → `:9000`, LE cert id133, Force SSL+HTTP/2+WSS) — публично + LAN/NetBird | +| Авторизация | admin `akadmin` (пароль + API-токен `claude-bootstrap` в credentials). **Обязательная 2FA** (TOTP/WebAuthn) на уровне IdP | +| Пилот OIDC | Open WebUI (chat.dttb.ru), Gitea (git.dttb.ru). Критичную инфру (Proxmox/NPM/Vaultwarden/Nextcloud) НЕ трогали | +| Tags | sso, idp, security | +| Назначение | **authentik — SSO/IdP для home lab.** OIDC для совместимых сервисов + forward-auth для голых панелей. AVX не требует. См. [[../../decisions/2026-06-26-authentik-sso-deploy]] | + +--- + ## 🔴 Остановленные LXC | VMID | Имя | Назначение | diff --git a/projects/dttb/spaceweb-dns.md b/projects/dttb/spaceweb-dns.md index e61edce..2a8fb59 100644 --- a/projects/dttb/spaceweb-dns.md +++ b/projects/dttb/spaceweb-dns.md @@ -13,6 +13,9 @@ tags: [dttb, dns] - editMain params: {domain, action:"add"/"edit", name, type:"A", value, prefix:"", index(edit)} - editMx params: {domain, subDomain:"", action:"add"/"edit", priority, value:"host.", index(edit)} - editTxt params: {domain, action:"add"/"edit", subDomain:"@"/..., value, index(edit)} +- **Чтение зоны: метод `info`** params {domain} (опц. type:"A") → список записей name/value/index/category (zoneMain|subdom). Методы JSON-RPC: editMain, editMx, editTxt, info. Читать перед add (взять index, не угадывать). +- Добавить одну A-запись поддомена: `editMain {action:"add", name:"", type:"A", value:"176.62.183.186", prefix:""}` → result:true. Безопасно (ломает зону только цикл editMain). Так добавлен auth.dttb.ru 2026-06-26. +- ⚠️ LE HTTP-01 после add: подожди истечения negative-cache (SOA minimum dttb.ru = 600с) — иначе certbot ловит NXDOMAIN (LE кеширует его ~10 мин от первой попытки). - Капча после 2-3 запросов подряд — новая сессия сбрасывает