АРХ - NODEDC PLATFORM: локальный Authentik и reverse proxy

This commit is contained in:
Codex 2026-05-04 10:17:04 +03:00
parent 0f89c4d126
commit 55db22b8d2
9 changed files with 327 additions and 13 deletions

View File

@ -52,6 +52,17 @@ task.local.nodedc -> Plane proxy/runtime
Все внешние запросы идут через reverse proxy.
На этом этапе reverse proxy реализуется через Caddy, а Authentik запускается за ним без прямой публикации host ports.
Текущие приложения подключаются как внешние upstream:
```text
launcher.local.nodedc -> host.docker.internal:5173
task.local.nodedc -> host.docker.internal:8090
```
Это сохраняет Launcher и Plane в их текущих репозиториях и runtime-папках.
## Environment
Базовые переменные должны жить в:
@ -66,11 +77,39 @@ platform/infra/.env
platform/infra/.env.example
```
Для генерации локальных secrets:
```bash
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
./infra/scripts/init-dev-env.sh
```
Скрипт создает `platform/infra/.env`, выставляет права `600` и не перезаписывает существующий файл.
## Start commands
```bash
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
docker compose --env-file infra/.env -f infra/docker-compose.dev.yml up -d
```
Проверка:
```bash
docker compose --env-file infra/.env -f infra/docker-compose.dev.yml ps
curl -I -H 'Host: auth.local.nodedc' http://127.0.0.1/
curl -I -H 'Host: task.local.nodedc' http://127.0.0.1/
```
## Authentik version note
Официальный compose Authentik для текущей ветки 2026.2 использует PostgreSQL, `server` и `worker`. Redis, указанный в раннем ТЗ как ожидаемый сервис, в актуальном официальном compose не используется. Если позже будет выбран старый pinned Authentik или отдельная HA-схема, Redis надо вернуть отдельной задачей.
## Implementation order
1. Согласовать локальные domain/port bindings.
2. Добавить reverse proxy config.
3. Поднять Authentik server, worker, Postgres и Redis.
3. Поднять Authentik server, worker и Postgres.
4. Прокинуть Authentik за proxy с корректными headers.
5. Подключить текущий Launcher как внешний сервис или через compose service.
6. Подключить текущий Plane runtime как внешний service target.

View File

@ -2,13 +2,13 @@
## Network
- [ ] Наружу опубликованы только reverse proxy ports.
- [x] Local dev compose публикует только reverse proxy port.
- [ ] Postgres не опубликован наружу в staging/production.
- [ ] Redis не опубликован наружу в staging/production.
- [ ] MinIO/storage не опубликован наружу в staging/production.
- [ ] Внутренние API не доступны напрямую извне.
- [ ] Authentik получает корректные `X-Forwarded-Proto`, `X-Forwarded-For`, `Host`.
- [ ] WebSocket headers настроены для Authentik/Plane/live.
- [x] Authentik получает `X-Forwarded-Proto`, `X-Forwarded-For`, `Host` через Caddy.
- [x] Caddy reverse proxy сохраняет HTTP/1.1/WebSocket upgrade behavior для upstream.
## Authentik
@ -17,6 +17,7 @@
- [ ] Для каждого приложения задана отдельная access policy.
- [ ] Группы app access заведены отдельно от app-local ролей.
- [ ] MFA/enrollment policy вынесены в отдельный этап.
- [x] Authentik local compose не публикует server/worker/Postgres ports напрямую.
## Launcher

View File

@ -3,10 +3,28 @@ AUTH_DOMAIN=auth.local.nodedc
LAUNCHER_DOMAIN=launcher.local.nodedc
TASK_DOMAIN=task.local.nodedc
# proxy
PLATFORM_HTTP_PORT=80
LOCAL_LAUNCHER_UPSTREAM=host.docker.internal:5173
LOCAL_TASK_MANAGER_UPSTREAM=host.docker.internal:8090
# authentik image
AUTHENTIK_IMAGE=ghcr.io/goauthentik/server
AUTHENTIK_TAG=2026.2.2
# authentik database
PG_DB=authentik
PG_USER=authentik
PG_PASS=change-me-generate-with-infra-scripts-init-dev-env
# authentik
AUTHENTIK_SECRET_KEY=
AUTHENTIK_POSTGRES_PASSWORD=
AUTHENTIK_REDIS_HOST=redis-authentik
AUTHENTIK_SECRET_KEY=change-me-generate-with-infra-scripts-init-dev-env
AUTHENTIK_ERROR_REPORTING__ENABLED=false
# optional first-start bootstrap
# AUTHENTIK_BOOTSTRAP_EMAIL=admin@nodedc.local
# AUTHENTIK_BOOTSTRAP_PASSWORD=
# AUTHENTIK_BOOTSTRAP_TOKEN=
# launcher oidc
LAUNCHER_OIDC_ISSUER=http://auth.local.nodedc/application/o/launcher/
@ -21,10 +39,6 @@ PLANE_OIDC_CLIENT_SECRET=
PLANE_OIDC_REDIRECT_URI=http://task.local.nodedc/auth/oidc/callback
# security
SESSION_SECRET=
SESSION_SECRET=change-me-generate-with-infra-scripts-init-dev-env
COOKIE_DOMAIN=.local.nodedc
COOKIE_SECURE=false
# current external local apps
LOCAL_LAUNCHER_URL=http://localhost:5173
LOCAL_TASK_MANAGER_URL=http://localhost:8090

View File

@ -8,19 +8,57 @@
- shared env examples;
- будущие docker compose файлы.
На нулевом этапе здесь фиксируется только каркас. Рабочий `docker-compose.dev.yml` создается отдельным этапом после согласования ports/domains и стратегии подключения текущих Launcher/Plane runtime.
Первый local dev слой проксирует текущие локальные приложения без физического переноса репозиториев:
- `auth.local.nodedc` -> `authentik-server:9000`;
- `launcher.local.nodedc` -> `host.docker.internal:5173`;
- `task.local.nodedc` -> `host.docker.internal:8090`.
Authentik построен по актуальной официальной Docker Compose схеме 2026.2: PostgreSQL 16, server и worker. Redis для Authentik в этой версии официального compose не используется.
## Expected files
```text
infra/
.env.example
scripts/init-dev-env.sh
docker-compose.dev.yml
docker-compose.staging.yml
reverse-proxy/
authentik/
```
## Local start
1. Add local domains to `/etc/hosts`:
```text
127.0.0.1 auth.local.nodedc
127.0.0.1 launcher.local.nodedc
127.0.0.1 task.local.nodedc
```
2. Generate local secrets:
```bash
./infra/scripts/init-dev-env.sh
```
3. Start infra:
```bash
docker compose --env-file infra/.env -f infra/docker-compose.dev.yml up -d
```
4. Check services:
```bash
docker compose --env-file infra/.env -f infra/docker-compose.dev.yml ps
curl -I -H 'Host: auth.local.nodedc' http://127.0.0.1/
```
Generated Authentik bootstrap credentials are stored only in `infra/.env`.
## Current decision
Текущий Plane runtime не переносится в compose платформы до backup и отдельного шага миграции.

35
infra/authentik/README.md Normal file
View File

@ -0,0 +1,35 @@
# Authentik Local Bootstrap
This directory stores local Authentik bootstrap assets for NODE.DC.
## Current scope
The first infra pass runs Authentik from the official Docker Compose shape for the 2026.2 release line:
- PostgreSQL 16;
- authentik server;
- authentik worker;
- no Redis service in the current official compose template;
- Caddy reverse proxy in front of Authentik and current local apps.
## Bootstrap variables
For a first local install, put these variables in `infra/.env`:
```bash
AUTHENTIK_BOOTSTRAP_EMAIL=admin@nodedc.local
AUTHENTIK_BOOTSTRAP_PASSWORD=<local generated password>
AUTHENTIK_BOOTSTRAP_TOKEN=<local generated token>
```
These are read only on first startup. Do not commit `infra/.env`.
## Future blueprint work
Later phases should add reproducible configuration for:
- NODE.DC Launcher Application/Provider;
- NODE.DC Task Manager Application/Provider;
- groups and policies;
- admin service token scope;
- exports or blueprints for repeatable setup.

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,95 @@
name: nodedc-platform
services:
reverse-proxy:
image: docker.io/library/caddy:2-alpine
restart: unless-stopped
env_file:
- path: .env
required: false
ports:
- "${PLATFORM_HTTP_PORT:-80}:80"
volumes:
- ./reverse-proxy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
depends_on:
authentik-server:
condition: service_started
extra_hosts:
- "host.docker.internal:host-gateway"
postgresql-authentik:
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
env_file:
- path: .env
required: false
environment:
POSTGRES_DB: ${PG_DB:-authentik}
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
POSTGRES_USER: ${PG_USER:-authentik}
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
volumes:
- authentik-database:/var/lib/postgresql/data
authentik-server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2.2}
command: server
restart: unless-stopped
env_file:
- path: .env
required: false
environment:
AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:?database password required}
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS: ${AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS:-127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,::1/128}
depends_on:
postgresql-authentik:
condition: service_healthy
expose:
- "9000"
- "9443"
shm_size: 512mb
volumes:
- authentik-data:/data
- ./authentik/custom-templates:/templates
authentik-worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2.2}
command: worker
restart: unless-stopped
user: root
env_file:
- path: .env
required: false
environment:
AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:?database password required}
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
depends_on:
postgresql-authentik:
condition: service_healthy
shm_size: 512mb
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- authentik-data:/data
- authentik-certs:/certs
- ./authentik/custom-templates:/templates
volumes:
authentik-database:
authentik-data:
authentik-certs:
caddy-data:
caddy-config:

View File

@ -0,0 +1,27 @@
{
auto_https off
}
http://{$AUTH_DOMAIN:auth.local.nodedc} {
reverse_proxy authentik-server:9000 {
header_up Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote_host}
}
}
http://{$LAUNCHER_DOMAIN:launcher.local.nodedc} {
reverse_proxy {$LOCAL_LAUNCHER_UPSTREAM:host.docker.internal:5173} {
header_up Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote_host}
}
}
http://{$TASK_DOMAIN:task.local.nodedc} {
reverse_proxy {$LOCAL_TASK_MANAGER_UPSTREAM:host.docker.internal:8090} {
header_up Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-For {remote_host}
}
}

64
infra/scripts/init-dev-env.sh Executable file
View File

@ -0,0 +1,64 @@
#!/usr/bin/env sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
INFRA_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
ENV_FILE="$INFRA_DIR/.env"
if [ -f "$ENV_FILE" ]; then
echo "Refusing to overwrite existing $ENV_FILE" >&2
exit 1
fi
rand() {
openssl rand -base64 "$1" | tr -d '\n'
}
cat > "$ENV_FILE" <<EOF
# domains
AUTH_DOMAIN=auth.local.nodedc
LAUNCHER_DOMAIN=launcher.local.nodedc
TASK_DOMAIN=task.local.nodedc
# proxy
PLATFORM_HTTP_PORT=80
LOCAL_LAUNCHER_UPSTREAM=host.docker.internal:5173
LOCAL_TASK_MANAGER_UPSTREAM=host.docker.internal:8090
# authentik image
AUTHENTIK_IMAGE=ghcr.io/goauthentik/server
AUTHENTIK_TAG=2026.2.2
# authentik database
PG_DB=authentik
PG_USER=authentik
PG_PASS=$(rand 36)
# authentik core
AUTHENTIK_SECRET_KEY=$(rand 60)
AUTHENTIK_ERROR_REPORTING__ENABLED=false
AUTHENTIK_BOOTSTRAP_EMAIL=admin@nodedc.local
AUTHENTIK_BOOTSTRAP_PASSWORD=$(rand 36)
AUTHENTIK_BOOTSTRAP_TOKEN=$(rand 36)
# launcher oidc
LAUNCHER_OIDC_ISSUER=http://auth.local.nodedc/application/o/launcher/
LAUNCHER_OIDC_CLIENT_ID=
LAUNCHER_OIDC_CLIENT_SECRET=
LAUNCHER_OIDC_REDIRECT_URI=http://launcher.local.nodedc/auth/callback
# plane oidc
PLANE_OIDC_ISSUER=http://auth.local.nodedc/application/o/task-manager/
PLANE_OIDC_CLIENT_ID=
PLANE_OIDC_CLIENT_SECRET=
PLANE_OIDC_REDIRECT_URI=http://task.local.nodedc/auth/oidc/callback
# security
SESSION_SECRET=$(rand 48)
COOKIE_DOMAIN=.local.nodedc
COOKIE_SECURE=false
EOF
chmod 600 "$ENV_FILE"
echo "Created $ENV_FILE"
echo "Open $ENV_FILE to read the generated local akadmin bootstrap credentials."