[105-4][@ant] refactor: свернуть CoopID-overlay'и в единый docker-compose и перенести authentik_db+coop_domain_db в существующий postgres — чтобы весь стек поднимался одной командой docker compose up -d, как того требует прод-деплой через плейбук, без отдельного контейнера postgres
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -128,10 +128,11 @@ const envVarsSchema = z.object({
|
||||
.transform(v => (v ? [...new Set(v.split(',').map(s => s.trim()).filter(Boolean))] : []))
|
||||
.pipe(z.array(z.string().url({ message: 'Каждый элемент BLOCKCHAIN_RPC_LIST — валидный URL' }))),
|
||||
CHAIN_ID: z.string().min(1, { message: 'Не должно быть пустым' }),
|
||||
// coop_domain_db (CoopID, Story 1.4): отдельная БД в coop-postgres (Story 1.1).
|
||||
// coop_domain_db (CoopID, Story 1.4): отдельная БД в общем сервисе postgres.
|
||||
// Пароль — значением или файлом (*_FILE приоритетнее; путь /run/secrets/... в контейнере).
|
||||
// Дефолт-порт 5532 = host-маппинг существующего postgres (PG_HOST_PORT) для запуска вне контейнера.
|
||||
COOP_DOMAIN_DB_HOST: z.string().default('127.0.0.1'),
|
||||
COOP_DOMAIN_DB_PORT: z.coerce.number().default(5632),
|
||||
COOP_DOMAIN_DB_PORT: z.coerce.number().default(5532),
|
||||
COOP_DOMAIN_DB_USERNAME: z.string().default('coop_app_user'),
|
||||
COOP_DOMAIN_DB_DATABASE: z.string().default('coop_domain_db'),
|
||||
COOP_DOMAIN_DB_PASSWORD: z.string().optional(),
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
# Overlay CoopID: authentik OIDC Provider (per-coop) + выделенный postgres:16.
|
||||
#
|
||||
# Запуск вместе с базовым стеком:
|
||||
# bash scripts/coopid-gen-secrets.sh # один раз, генерирует infra/coopid/secrets/
|
||||
# docker compose -f docker-compose.yaml -f docker-compose.authentik.yml -f docker-compose.edge.yml up -d
|
||||
#
|
||||
# Существующий сервис postgres (18, БД voskhod) намеренно не используется:
|
||||
# смена его образа на 16 сделала бы data dir нечитаемым. Две новые БД
|
||||
# (authentik_db + coop_domain_db) живут в отдельном coop-postgres c ролевой
|
||||
# изоляцией. Redis не дублируем — authentik работает в monoredis, DB-индекс 1.
|
||||
# Подробности: infra/coopid/README.md
|
||||
|
||||
services:
|
||||
coop-postgres:
|
||||
image: postgres:16
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/coop_pg_superuser_password
|
||||
secrets:
|
||||
- coop_pg_superuser_password
|
||||
- coop_pg_authentik_password
|
||||
- coop_pg_app_password
|
||||
volumes:
|
||||
- coop_postgres_data:/var/lib/postgresql/data
|
||||
- ./infra/coopid/postgres/init:/docker-entrypoint-initdb.d:ro
|
||||
ports:
|
||||
- "127.0.0.1:${COOP_PG_HOST_PORT:-5632}:5432"
|
||||
healthcheck:
|
||||
# Не pg_isready: он не проверяет существование БД и маскирует упавший init-скрипт.
|
||||
test: ["CMD-SHELL", "psql -U postgres -d authentik_db -c 'select 1' >/dev/null 2>&1 && psql -U postgres -d coop_domain_db -c 'select 1' >/dev/null 2>&1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/server:2026.2
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment: &authentik-env
|
||||
AUTHENTIK_SECRET_KEY: file:///run/secrets/authentik_secret_key
|
||||
AUTHENTIK_POSTGRESQL__HOST: coop-postgres
|
||||
AUTHENTIK_POSTGRESQL__PORT: 5432
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik_db
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik_user
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: file:///run/secrets/coop_pg_authentik_password
|
||||
AUTHENTIK_REDIS__HOST: monoredis
|
||||
# controller использует DB 0; при шаринге одного redis несколькими коопами — развести индексы.
|
||||
AUTHENTIK_REDIS__DB: ${AUTHENTIK_REDIS_DB:-1}
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD: file:///run/secrets/authentik_bootstrap_password
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN: file:///run/secrets/authentik_bootstrap_token
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
|
||||
AUTHENTIK_DISABLE_UPDATE_CHECK: "true"
|
||||
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: "true"
|
||||
# Подставляется blueprint'ом coopid-password-policy в headers-mapping вебхука.
|
||||
COOPID_WEBHOOK_TOKEN: ${COOPID_WEBHOOK_TOKEN:-}
|
||||
volumes: &authentik-volumes
|
||||
- ./infra/coopid/authentik/blueprints:/blueprints/custom:ro
|
||||
secrets: &authentik-secrets
|
||||
- authentik_secret_key
|
||||
- authentik_bootstrap_password
|
||||
- authentik_bootstrap_token
|
||||
- coop_pg_authentik_password
|
||||
ports:
|
||||
- "127.0.0.1:${AUTHENTIK_HOST_PORT:-9008}:9000"
|
||||
depends_on:
|
||||
coop-postgres:
|
||||
condition: service_healthy
|
||||
monoredis:
|
||||
condition: service_started
|
||||
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:2026.2
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment: *authentik-env
|
||||
volumes: *authentik-volumes
|
||||
secrets: *authentik-secrets
|
||||
depends_on:
|
||||
coop-postgres:
|
||||
condition: service_healthy
|
||||
monoredis:
|
||||
condition: service_started
|
||||
|
||||
# Аддитивное расширение сервиса из базового compose: ключ подписи
|
||||
# participant_certificate и vault-ключ кооператива монтируются в controller
|
||||
# (читаются CryptoService начиная со Stories 1.7–1.8).
|
||||
coopback:
|
||||
environment:
|
||||
AUTH_V2_WEBHOOK_TOKEN_FILE: /run/secrets/authentik_webhook_token
|
||||
AUTH_V2_SESSION_BINDING_SECRET_FILE: /run/secrets/auth_v2_session_binding_secret
|
||||
AUTHENTIK_INTERNAL_URL: http://authentik-server:9000
|
||||
secrets:
|
||||
- coop_cert_key
|
||||
- coop_vault_key
|
||||
- coop_pg_app_password
|
||||
- authentik_webhook_token
|
||||
- auth_v2_session_binding_secret
|
||||
|
||||
secrets:
|
||||
coop_pg_superuser_password:
|
||||
file: ./infra/coopid/secrets/coop_pg_superuser_password
|
||||
coop_pg_authentik_password:
|
||||
file: ./infra/coopid/secrets/coop_pg_authentik_password
|
||||
coop_pg_app_password:
|
||||
file: ./infra/coopid/secrets/coop_pg_app_password
|
||||
authentik_secret_key:
|
||||
file: ./infra/coopid/secrets/authentik_secret_key
|
||||
authentik_bootstrap_password:
|
||||
file: ./infra/coopid/secrets/authentik_bootstrap_password
|
||||
authentik_bootstrap_token:
|
||||
file: ./infra/coopid/secrets/authentik_bootstrap_token
|
||||
authentik_webhook_token:
|
||||
file: ./infra/coopid/secrets/authentik_webhook_token
|
||||
auth_v2_session_binding_secret:
|
||||
file: ./infra/coopid/secrets/auth_v2_session_binding_secret
|
||||
coop_cert_key:
|
||||
file: ./infra/coopid/secrets/coop_cert_key
|
||||
coop_vault_key:
|
||||
file: ./infra/coopid/secrets/coop_vault_key
|
||||
|
||||
volumes:
|
||||
coop_postgres_data:
|
||||
@@ -1,46 +0,0 @@
|
||||
# Overlay CoopID edge: caddy (внешний TLS 1.3) + crowdsec.
|
||||
# Применяется ТОЛЬКО вместе с docker-compose.authentik.yml (caddy проксирует
|
||||
# на authentik-server). Внутри docker-сети трафик plain HTTP, внешний TLS
|
||||
# терминирует caddy. В Story 1.1 crowdsec только разбирает access-логи caddy;
|
||||
# активный bouncer (блокировки) — Story 9.2.
|
||||
|
||||
services:
|
||||
caddy:
|
||||
image: caddy:2.11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# localhost → self-signed (внутренний CA caddy); реальный домен → Let's Encrypt.
|
||||
COOPID_DOMAIN: ${COOPID_DOMAIN:-localhost}
|
||||
ports:
|
||||
# Прод с реальным доменом: CADDY_BIND=0.0.0.0, порты 80/443 — иначе ACME
|
||||
# HTTP-01 challenge недостижим снаружи и Let's Encrypt не выдаст сертификат.
|
||||
- "${CADDY_BIND:-127.0.0.1}:${CADDY_HTTP_PORT:-8088}:80"
|
||||
- "${CADDY_BIND:-127.0.0.1}:${CADDY_HTTPS_PORT:-8443}:443"
|
||||
volumes:
|
||||
- ./infra/coopid/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
- caddy_logs:/var/log/caddy
|
||||
depends_on:
|
||||
- authentik-server
|
||||
- coopback
|
||||
|
||||
crowdsec:
|
||||
image: crowdsecurity/crowdsec:v1.7.8
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
COLLECTIONS: "crowdsecurity/caddy crowdsecurity/http-cve"
|
||||
volumes:
|
||||
- ./infra/coopid/crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
|
||||
- crowdsec_db:/var/lib/crowdsec/data
|
||||
- crowdsec_config:/etc/crowdsec
|
||||
- caddy_logs:/var/log/caddy:ro
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
caddy_logs:
|
||||
crowdsec_db:
|
||||
crowdsec_config:
|
||||
@@ -46,8 +46,23 @@ services:
|
||||
POSTGRES_DB: voskhod
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql
|
||||
# init-скрипт CoopID выполняется ТОЛЬКО при пустом data dir: на свежей
|
||||
# машине создаёт authentik_db + coop_domain_db с ролевой изоляцией. На уже
|
||||
# инициализированном томе БД заводятся вручную (см. infra/coopid/README.md).
|
||||
- ./infra/coopid/postgres/init:/docker-entrypoint-initdb.d:ro
|
||||
secrets:
|
||||
# пароли прикладных ролей CoopID — init-скрипт читает их из /run/secrets.
|
||||
- coop_pg_authentik_password
|
||||
- coop_pg_app_password
|
||||
ports:
|
||||
- "127.0.0.1:${PG_HOST_PORT:-5532}:5432"
|
||||
healthcheck:
|
||||
# authentik стартует только после готовности обеих БД CoopID; pg_isready
|
||||
# их бы не проверил и замаскировал недоинициализированный том.
|
||||
test: ["CMD-SHELL", "psql -U postgres -d authentik_db -c 'select 1' >/dev/null 2>&1 && psql -U postgres -d coop_domain_db -c 'select 1' >/dev/null 2>&1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
coopback:
|
||||
build:
|
||||
@@ -69,6 +84,14 @@ services:
|
||||
- "0.0.0.0:${COOPBACK_HOST_PORT:-2998}:2998"
|
||||
working_dir: /app
|
||||
command: pnpm --filter @coopenomics/controller run dev
|
||||
# CoopID: ключ подписи participant_certificate (Stories 1.7–1.8), vault-ключ
|
||||
# кооператива, пароль роли coop_domain_db, токены вебхука и session_binding.
|
||||
secrets:
|
||||
- coop_cert_key
|
||||
- coop_vault_key
|
||||
- coop_pg_app_password
|
||||
- authentik_webhook_token
|
||||
- auth_v2_session_binding_secret
|
||||
|
||||
cooparser:
|
||||
build:
|
||||
@@ -124,7 +147,120 @@ services:
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
|
||||
# ── CoopID: per-coop OIDC (authentik) ──────────────────────────────────────
|
||||
# Данные authentik живут отдельной БД authentik_db в общем сервисе postgres
|
||||
# (роль authentik_user, ролевая изоляция от coop_domain_db). Redis — общий
|
||||
# monoredis, DB-индекс 1 (controller сидит в индексе 0).
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/server:2026.2
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment: &authentik-env
|
||||
AUTHENTIK_SECRET_KEY: file:///run/secrets/authentik_secret_key
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgres
|
||||
AUTHENTIK_POSTGRESQL__PORT: 5432
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik_db
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik_user
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: file:///run/secrets/coop_pg_authentik_password
|
||||
AUTHENTIK_REDIS__HOST: monoredis
|
||||
AUTHENTIK_REDIS__DB: ${AUTHENTIK_REDIS_DB:-1}
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD: file:///run/secrets/authentik_bootstrap_password
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN: file:///run/secrets/authentik_bootstrap_token
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
|
||||
AUTHENTIK_DISABLE_UPDATE_CHECK: "true"
|
||||
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: "true"
|
||||
# Подставляется blueprint'ом coopid-password-policy в headers-mapping вебхука.
|
||||
COOPID_WEBHOOK_TOKEN: ${COOPID_WEBHOOK_TOKEN:-}
|
||||
volumes: &authentik-volumes
|
||||
- ./infra/coopid/authentik/blueprints:/blueprints/custom:ro
|
||||
secrets: &authentik-secrets
|
||||
- authentik_secret_key
|
||||
- authentik_bootstrap_password
|
||||
- authentik_bootstrap_token
|
||||
- coop_pg_authentik_password
|
||||
ports:
|
||||
- "127.0.0.1:${AUTHENTIK_HOST_PORT:-9008}:9000"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
monoredis:
|
||||
condition: service_started
|
||||
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:2026.2
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment: *authentik-env
|
||||
volumes: *authentik-volumes
|
||||
secrets: *authentik-secrets
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
monoredis:
|
||||
condition: service_started
|
||||
|
||||
# ── CoopID edge: внешний TLS 1.3 (caddy) + разбор access-логов (crowdsec) ───
|
||||
caddy:
|
||||
image: caddy:2.11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# localhost → self-signed (внутренний CA caddy); реальный домен → Let's Encrypt.
|
||||
COOPID_DOMAIN: ${COOPID_DOMAIN:-localhost}
|
||||
ports:
|
||||
# Прод с реальным доменом: CADDY_BIND=0.0.0.0, порты 80/443 — иначе ACME
|
||||
# HTTP-01 challenge недостижим снаружи и Let's Encrypt не выдаст сертификат.
|
||||
- "${CADDY_BIND:-127.0.0.1}:${CADDY_HTTP_PORT:-8088}:80"
|
||||
- "${CADDY_BIND:-127.0.0.1}:${CADDY_HTTPS_PORT:-8443}:443"
|
||||
volumes:
|
||||
- ./infra/coopid/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
- caddy_logs:/var/log/caddy
|
||||
depends_on:
|
||||
- authentik-server
|
||||
- coopback
|
||||
|
||||
crowdsec:
|
||||
image: crowdsecurity/crowdsec:v1.7.8
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
COLLECTIONS: "crowdsecurity/caddy crowdsecurity/http-cve"
|
||||
volumes:
|
||||
- ./infra/coopid/crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
|
||||
- crowdsec_db:/var/lib/crowdsec/data
|
||||
- crowdsec_config:/etc/crowdsec
|
||||
- caddy_logs:/var/log/caddy:ro
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
# Все секреты CoopID — file-based из infra/coopid/secrets/ (каталог в .gitignore).
|
||||
# На свежей машине: bash scripts/coopid-gen-secrets.sh. На prod раскладывает плейбук.
|
||||
secrets:
|
||||
coop_pg_authentik_password:
|
||||
file: ./infra/coopid/secrets/coop_pg_authentik_password
|
||||
coop_pg_app_password:
|
||||
file: ./infra/coopid/secrets/coop_pg_app_password
|
||||
authentik_secret_key:
|
||||
file: ./infra/coopid/secrets/authentik_secret_key
|
||||
authentik_bootstrap_password:
|
||||
file: ./infra/coopid/secrets/authentik_bootstrap_password
|
||||
authentik_bootstrap_token:
|
||||
file: ./infra/coopid/secrets/authentik_bootstrap_token
|
||||
authentik_webhook_token:
|
||||
file: ./infra/coopid/secrets/authentik_webhook_token
|
||||
auth_v2_session_binding_secret:
|
||||
file: ./infra/coopid/secrets/auth_v2_session_binding_secret
|
||||
coop_cert_key:
|
||||
file: ./infra/coopid/secrets/coop_cert_key
|
||||
coop_vault_key:
|
||||
file: ./infra/coopid/secrets/coop_vault_key
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
postgres_data:
|
||||
minio_data:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
caddy_logs:
|
||||
crowdsec_db:
|
||||
crowdsec_config:
|
||||
|
||||
+63
-35
@@ -1,63 +1,91 @@
|
||||
# CoopID — инфраструктура per-coop (Story 1.1)
|
||||
|
||||
Стек OIDC-аутентификации кооператива: authentik 2026.2 (server + worker),
|
||||
выделенный postgres:16 с двумя БД, caddy (внешний TLS 1.3) и crowdsec.
|
||||
Подключается к базовому дев-стеку двумя аддитивными overlay-файлами —
|
||||
существующие сервисы (`postgres` 18/voskhod, `monoredis`, `coopback`, `desktop`)
|
||||
не изменяются и не пересоздаются.
|
||||
Стек OIDC-аутентификации кооператива встроен в **основной** `docker-compose.yaml`
|
||||
монорепы: authentik 2026.2 (server + worker), caddy (внешний TLS 1.3) и crowdsec.
|
||||
Отдельный postgres не поднимается — данные authentik и доменные данные CoopID
|
||||
живут **двумя отдельными БД в существующем сервисе `postgres`**:
|
||||
|
||||
- `authentik_db` — роль `authentik_user` (данные authentik);
|
||||
- `coop_domain_db` — роль `coop_app_user` (vaults, audit, кэши — миграции V2.4.x).
|
||||
|
||||
Ролевая изоляция: подключиться к чужой БД может только её владелец (и суперюзер).
|
||||
Redis — общий `monoredis` (authentik в DB-индексе 1, controller в 0).
|
||||
|
||||
Весь стек поднимается **одной командой** — никаких overlay `-f`-цепочек.
|
||||
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
# 1. Секреты (один раз; идемпотентно)
|
||||
# 1. Секреты (один раз; идемпотентно — существующие не перезаписывает)
|
||||
bash scripts/coopid-gen-secrets.sh
|
||||
|
||||
# 2. Весь стек с overlays
|
||||
docker compose -f docker-compose.yaml -f docker-compose.authentik.yml -f docker-compose.edge.yml up -d
|
||||
# 2. Весь стек
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Чтобы не повторять `-f`-цепочку, можно добавить в `.env`:
|
||||
|
||||
```
|
||||
COMPOSE_FILE=docker-compose.yaml:docker-compose.authentik.yml:docker-compose.edge.yml
|
||||
```
|
||||
|
||||
## Состав
|
||||
## Состав (в docker-compose.yaml)
|
||||
|
||||
| Сервис | Образ | Назначение |
|
||||
|---|---|---|
|
||||
| `coop-postgres` | postgres:16 | Две БД: `authentik_db` (роль `authentik_user`) и `coop_domain_db` (роль `coop_app_user`); ролевая изоляция — подключение только владельцу |
|
||||
| `postgres` | postgres:18 | Общий postgres. Кроме `voskhod` держит `authentik_db` и `coop_domain_db` (создаются init-скриптом на свежем томе либо вручную — см. ниже) |
|
||||
| `authentik-server` | ghcr.io/goauthentik/server:2026.2 | OIDC Provider; UI/API на :9000 внутри сети |
|
||||
| `authentik-worker` | ghcr.io/goauthentik/server:2026.2 | Фоновые задачи authentik |
|
||||
| `caddy` | caddy:2.11 | Внешний HTTPS (TLS 1.3 min): `/api/coopback/*` → controller, остальное → authentik; JSON access-log |
|
||||
| `crowdsec` | crowdsecurity/crowdsec:v1.7.8 | Разбор access-логов caddy (активный bouncer — Story 9.2) |
|
||||
|
||||
Redis отдельно не поднимается: authentik использует существующий `monoredis`
|
||||
(DB-индекс 1; controller сидит в индексе 0 по умолчанию).
|
||||
## Две БД в существующем postgres
|
||||
|
||||
`infra/coopid/postgres/init/01-init.sh` смонтирован в `/docker-entrypoint-initdb.d`
|
||||
и заводит роли+БД **только при пустом data dir** (правило официального образа
|
||||
postgres). Поэтому:
|
||||
|
||||
- **Свежая машина / пустой том** — `docker compose up -d` создаёт обе БД сам.
|
||||
- **Уже инициализированный том** (как на текущих dev-стендах) — init-скрипт
|
||||
не запускается, БД заводятся вручную тем же SQL:
|
||||
|
||||
```bash
|
||||
AUTHPW=$(cat infra/coopid/secrets/coop_pg_authentik_password)
|
||||
APPPW=$(cat infra/coopid/secrets/coop_pg_app_password)
|
||||
docker compose exec -T postgres psql -v ON_ERROR_STOP=1 \
|
||||
-v apw="$AUTHPW" -v cpw="$APPPW" -U postgres -d postgres <<'SQL'
|
||||
CREATE ROLE authentik_user LOGIN PASSWORD :'apw';
|
||||
CREATE ROLE coop_app_user LOGIN PASSWORD :'cpw';
|
||||
CREATE DATABASE authentik_db OWNER authentik_user;
|
||||
CREATE DATABASE coop_domain_db OWNER coop_app_user;
|
||||
REVOKE CONNECT ON DATABASE authentik_db FROM PUBLIC;
|
||||
REVOKE CONNECT ON DATABASE coop_domain_db FROM PUBLIC;
|
||||
SQL
|
||||
```
|
||||
|
||||
Затем coopback на старте применит миграции `coop_domain_db` (V2.4.0/V2.4.1).
|
||||
|
||||
## Секреты
|
||||
|
||||
Все секреты — file-based Docker Secrets из `infra/coopid/secrets/` (каталог в
|
||||
`.gitignore`): `coop_cert_key` (secp256k1 PEM — подпись `participant_certificate`),
|
||||
File-based Docker Secrets из `infra/coopid/secrets/` (каталог в `.gitignore`):
|
||||
`coop_cert_key` (secp256k1 PEM — подпись `participant_certificate`),
|
||||
`coop_vault_key`, `authentik_secret_key`, bootstrap-пароль/токен `akadmin`,
|
||||
три пароля postgres. В `.env` и compose значений секретов нет; контейнеры
|
||||
читают их из `/run/secrets/*` (postgres — `*_FILE`, authentik — `file://`-схема).
|
||||
`authentik_webhook_token`, `auth_v2_session_binding_secret`, два пароля ролей
|
||||
postgres. Суперюзер postgres — inline-пароль в compose, отдельного секрета нет.
|
||||
В `.env`/compose значений секретов нет; контейнеры читают их из `/run/secrets/*`
|
||||
(postgres-роли — через init-скрипт, authentik — `file://`, coopback — `*_FILE`).
|
||||
На prod секреты раскладывает плейбук с правами `0400`.
|
||||
|
||||
## Порты (dev, INSTANCE_INDEX=1)
|
||||
## Порты (dev, mono-ai-3)
|
||||
|
||||
- `127.0.0.1:8443` — caddy HTTPS (self-signed при `COOPID_DOMAIN=localhost`)
|
||||
- `127.0.0.1:8088` — caddy HTTP
|
||||
- `127.0.0.1:9008` — authentik напрямую (мимо caddy, для отладки)
|
||||
- `127.0.0.1:5632` — coop-postgres
|
||||
- `127.0.0.1:9008` — authentik напрямую (мимо caddy, для отладки; `AUTHENTIK_HOST_PORT`)
|
||||
- `127.0.0.1:5532` — postgres (обе БД, `PG_HOST_PORT`)
|
||||
|
||||
## Проверка
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yaml -f docker-compose.authentik.yml -f docker-compose.edge.yml ps
|
||||
curl -sk --tlsv1.3 https://127.0.0.1:8443/ -o /dev/null -w '%{http_code}\n' # 2xx/3xx от authentik
|
||||
# Ролевая изоляция (ожидаемо: permission denied):
|
||||
docker compose exec coop-postgres psql -U coop_app_user -d authentik_db -c 'select 1'
|
||||
docker compose ps
|
||||
# SNI обязателен: caddy с авто-TLS для localhost без SNI отдаёт TLS internal error.
|
||||
curl -sk --tlsv1.3 --resolve localhost:8443:127.0.0.1 https://localhost:8443/ \
|
||||
-o /dev/null -w '%{http_code}\n' # 302/200 от authentik (порт = CADDY_HTTPS_PORT)
|
||||
# Ролевая изоляция (ожидаемо permission denied):
|
||||
docker compose exec postgres psql -U coop_app_user -d authentik_db -c 'select 1'
|
||||
```
|
||||
|
||||
Учётка администратора authentik: `akadmin`, пароль — в
|
||||
@@ -65,12 +93,12 @@ docker compose exec coop-postgres psql -U coop_app_user -d authentik_db -c 'sele
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Init-скрипты postgres выполняются только при пустом data dir.** Если первый
|
||||
старт coop-postgres упал на середине init (healthcheck вечно красный, БД/ролей
|
||||
нет) или вы перегенерировали pg-пароли при живом volume — пересоздайте том:
|
||||
`docker compose ... stop coop-postgres && docker compose ... rm -f coop-postgres
|
||||
&& docker volume rm <project>_coop_postgres_data`, затем `up -d` заново.
|
||||
Ротация паролей живой БД делается `ALTER ROLE`, не перегенерацией секрета.
|
||||
- **Init-скрипт postgres выполняется только при пустом data dir.** На живом томе
|
||||
заводите БД вручную (см. блок выше). Ротация паролей ролей — `ALTER ROLE`, не
|
||||
перегенерацией секрета.
|
||||
- **Прод с реальным доменом:** задайте `COOPID_DOMAIN`, `CADDY_BIND=0.0.0.0`,
|
||||
`CADDY_HTTP_PORT=80`, `CADDY_HTTPS_PORT=443` — ACME HTTP-01 должен быть
|
||||
достижим снаружи на 80/443.
|
||||
- **authentik на postgres:18:** официальная поддержка на pg16, но pg18 как
|
||||
сервер обратносовместим (Django+psycopg). На dev/testnet общий postgres
|
||||
используется сознательно — единый стек одной командой важнее версии-в-версию.
|
||||
|
||||
@@ -45,11 +45,12 @@ if ! grep -q '^COOPID_WEBHOOK_TOKEN=' "$ROOT/.env" 2>/dev/null; then
|
||||
printf '\n# Webhook-токен authentik→coopback (= infra/coopid/secrets/authentik_webhook_token)\nCOOPID_WEBHOOK_TOKEN=%s\n' "$(cat "$SECRETS_DIR/authentik_webhook_token")" >> "$ROOT/.env"
|
||||
echo " + COOPID_WEBHOOK_TOKEN добавлен в .env"
|
||||
fi
|
||||
# postgres: file-секреты в plain compose — bind-mount с хостовыми правами,
|
||||
# а init-скрипты официального образа выполняются под uid 999 (postgres) —
|
||||
# поэтому пароли postgres world-readable. Только для dev; prod-права — плейбук.
|
||||
gen 0444 coop_pg_superuser_password rand_pass
|
||||
# postgres: пароли прикладных ролей CoopID (authentik_user, coop_app_user).
|
||||
# Суперюзер postgres использует inline-пароль из docker-compose.yaml — отдельный
|
||||
# секрет ему не нужен. file-секреты в plain compose монтируются bind-mount'ом с
|
||||
# хостовыми правами, а init-скрипты официального образа выполняются под uid 999
|
||||
# (postgres) — поэтому пароли world-readable. Только dev; prod-права (0400) — плейбук.
|
||||
gen 0444 coop_pg_authentik_password rand_pass
|
||||
gen 0444 coop_pg_app_password rand_pass
|
||||
|
||||
echo "Готово. Дальше: docker compose -f docker-compose.yaml -f docker-compose.authentik.yml -f docker-compose.edge.yml up -d"
|
||||
echo "Готово. Дальше: docker compose up -d (весь стек одной командой)."
|
||||
|
||||
Reference in New Issue
Block a user