АРХ - NODEDC PLATFORM: локальный Authentik и reverse proxy
This commit is contained in:
parent
0f89c4d126
commit
55db22b8d2
|
|
@ -52,6 +52,17 @@ task.local.nodedc -> Plane proxy/runtime
|
||||||
|
|
||||||
Все внешние запросы идут через reverse proxy.
|
Все внешние запросы идут через 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
|
## Environment
|
||||||
|
|
||||||
Базовые переменные должны жить в:
|
Базовые переменные должны жить в:
|
||||||
|
|
@ -66,11 +77,39 @@ platform/infra/.env
|
||||||
platform/infra/.env.example
|
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
|
## Implementation order
|
||||||
|
|
||||||
1. Согласовать локальные domain/port bindings.
|
1. Согласовать локальные domain/port bindings.
|
||||||
2. Добавить reverse proxy config.
|
2. Добавить reverse proxy config.
|
||||||
3. Поднять Authentik server, worker, Postgres и Redis.
|
3. Поднять Authentik server, worker и Postgres.
|
||||||
4. Прокинуть Authentik за proxy с корректными headers.
|
4. Прокинуть Authentik за proxy с корректными headers.
|
||||||
5. Подключить текущий Launcher как внешний сервис или через compose service.
|
5. Подключить текущий Launcher как внешний сервис или через compose service.
|
||||||
6. Подключить текущий Plane runtime как внешний service target.
|
6. Подключить текущий Plane runtime как внешний service target.
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
## Network
|
## Network
|
||||||
|
|
||||||
- [ ] Наружу опубликованы только reverse proxy ports.
|
- [x] Local dev compose публикует только reverse proxy port.
|
||||||
- [ ] Postgres не опубликован наружу в staging/production.
|
- [ ] Postgres не опубликован наружу в staging/production.
|
||||||
- [ ] Redis не опубликован наружу в staging/production.
|
- [ ] Redis не опубликован наружу в staging/production.
|
||||||
- [ ] MinIO/storage не опубликован наружу в staging/production.
|
- [ ] MinIO/storage не опубликован наружу в staging/production.
|
||||||
- [ ] Внутренние API не доступны напрямую извне.
|
- [ ] Внутренние API не доступны напрямую извне.
|
||||||
- [ ] Authentik получает корректные `X-Forwarded-Proto`, `X-Forwarded-For`, `Host`.
|
- [x] Authentik получает `X-Forwarded-Proto`, `X-Forwarded-For`, `Host` через Caddy.
|
||||||
- [ ] WebSocket headers настроены для Authentik/Plane/live.
|
- [x] Caddy reverse proxy сохраняет HTTP/1.1/WebSocket upgrade behavior для upstream.
|
||||||
|
|
||||||
## Authentik
|
## Authentik
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
- [ ] Для каждого приложения задана отдельная access policy.
|
- [ ] Для каждого приложения задана отдельная access policy.
|
||||||
- [ ] Группы app access заведены отдельно от app-local ролей.
|
- [ ] Группы app access заведены отдельно от app-local ролей.
|
||||||
- [ ] MFA/enrollment policy вынесены в отдельный этап.
|
- [ ] MFA/enrollment policy вынесены в отдельный этап.
|
||||||
|
- [x] Authentik local compose не публикует server/worker/Postgres ports напрямую.
|
||||||
|
|
||||||
## Launcher
|
## Launcher
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,28 @@ AUTH_DOMAIN=auth.local.nodedc
|
||||||
LAUNCHER_DOMAIN=launcher.local.nodedc
|
LAUNCHER_DOMAIN=launcher.local.nodedc
|
||||||
TASK_DOMAIN=task.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
|
||||||
AUTHENTIK_SECRET_KEY=
|
AUTHENTIK_SECRET_KEY=change-me-generate-with-infra-scripts-init-dev-env
|
||||||
AUTHENTIK_POSTGRES_PASSWORD=
|
AUTHENTIK_ERROR_REPORTING__ENABLED=false
|
||||||
AUTHENTIK_REDIS_HOST=redis-authentik
|
|
||||||
|
# optional first-start bootstrap
|
||||||
|
# AUTHENTIK_BOOTSTRAP_EMAIL=admin@nodedc.local
|
||||||
|
# AUTHENTIK_BOOTSTRAP_PASSWORD=
|
||||||
|
# AUTHENTIK_BOOTSTRAP_TOKEN=
|
||||||
|
|
||||||
# launcher oidc
|
# launcher oidc
|
||||||
LAUNCHER_OIDC_ISSUER=http://auth.local.nodedc/application/o/launcher/
|
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
|
PLANE_OIDC_REDIRECT_URI=http://task.local.nodedc/auth/oidc/callback
|
||||||
|
|
||||||
# security
|
# security
|
||||||
SESSION_SECRET=
|
SESSION_SECRET=change-me-generate-with-infra-scripts-init-dev-env
|
||||||
COOKIE_DOMAIN=.local.nodedc
|
COOKIE_DOMAIN=.local.nodedc
|
||||||
COOKIE_SECURE=false
|
COOKIE_SECURE=false
|
||||||
|
|
||||||
# current external local apps
|
|
||||||
LOCAL_LAUNCHER_URL=http://localhost:5173
|
|
||||||
LOCAL_TASK_MANAGER_URL=http://localhost:8090
|
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,57 @@
|
||||||
- shared env examples;
|
- shared env examples;
|
||||||
- будущие docker compose файлы.
|
- будущие 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
|
## Expected files
|
||||||
|
|
||||||
```text
|
```text
|
||||||
infra/
|
infra/
|
||||||
.env.example
|
.env.example
|
||||||
|
scripts/init-dev-env.sh
|
||||||
docker-compose.dev.yml
|
docker-compose.dev.yml
|
||||||
docker-compose.staging.yml
|
docker-compose.staging.yml
|
||||||
reverse-proxy/
|
reverse-proxy/
|
||||||
authentik/
|
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
|
## Current decision
|
||||||
|
|
||||||
Текущий Plane runtime не переносится в compose платформы до backup и отдельного шага миграции.
|
Текущий Plane runtime не переносится в compose платформы до backup и отдельного шага миграции.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -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}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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."
|
||||||
Loading…
Reference in New Issue