docs(deploy): .env.example + secrets.md, проброс OpenIddict env в compose (P0-8)
deploy/.env.example — все required/опц. переменные (POSTGRES_PASSWORD, REGISTRY, *_TAG, OPENIDDICT_ISSUER/CERT_PASSWORD, FM_* бэкапа, Cors/RateLimiting/MoySklad). docs/secrets.md — таблица переменных, где живут секреты (SMTP в БД, сертификаты в volume), ротация, гигиена. compose: api получает OpenIddict__Issuer (за прокси обязателен) и OpenIddict__CertPassword из .env. compose config валиден. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
5b981dd34b
commit
45326281f9
43
deploy/.env.example
Normal file
43
deploy/.env.example
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# food-market — пример переменных окружения для деплоя.
|
||||
#
|
||||
# Скопировать в deploy/.env и заполнить значениями (.env в .gitignore — НЕ коммитить).
|
||||
# cp deploy/.env.example deploy/.env && $EDITOR deploy/.env
|
||||
#
|
||||
# docker-compose читает deploy/.env автоматически. Описание секретов и ротация —
|
||||
# docs/secrets.md. Ключи OpenIddict — docs/openiddict-keys.md.
|
||||
|
||||
# ─── Реестр образов и теги (docker-compose) ──────────────────────────────────
|
||||
# Откуда тянуть образы. Локальный registry на stage — 127.0.0.1:5001 (см. CLAUDE/memory).
|
||||
REGISTRY=127.0.0.1:5001
|
||||
API_TAG=latest
|
||||
WEB_TAG=latest
|
||||
PUBLIC_TAG=latest
|
||||
|
||||
# ─── База данных (ОБЯЗАТЕЛЬНО) ───────────────────────────────────────────────
|
||||
# Пароль пользователя food_market в Postgres-контейнере. Подставляется и в
|
||||
# POSTGRES_PASSWORD контейнера БД, и в ConnectionStrings__Default API.
|
||||
# Сгенерировать: openssl rand -base64 24
|
||||
POSTGRES_PASSWORD=CHANGE_ME_strong_db_password
|
||||
|
||||
# ─── OpenIddict / выдача токенов ─────────────────────────────────────────────
|
||||
# Публичный URL админки = issuer токенов (обязателен за nginx-прокси).
|
||||
OPENIDDICT_ISSUER=https://admin.food-market.kz/
|
||||
# Пароль PFX-сертификатов подписи/шифрования. Пусто = без пароля (self-signed
|
||||
# генерируется автоматически в App_Data, если файлов нет). Подробности — docs/openiddict-keys.md.
|
||||
OPENIDDICT_CERT_PASSWORD=
|
||||
|
||||
# ─── Бэкап (systemd food-market-backup.*) ────────────────────────────────────
|
||||
# Переопределения для скрипта бэкапа. По умолчанию совпадают с compose — можно не задавать.
|
||||
# FM_BACKUP_DIR=/opt/food-market-data/backups
|
||||
# FM_UPLOADS_DIR=/opt/food-market-data/uploads
|
||||
# FM_BACKUP_RETENTION_DAYS=30
|
||||
|
||||
# ─── Прочее (опционально, переопределяет appsettings.json) ───────────────────
|
||||
# CORS-origins фронта (если отличается от зашитых в appsettings). Индексируется с 0:
|
||||
# Cors__AllowedOrigins__0=https://admin.food-market.kz
|
||||
# Антибрутфорс на /connect/token и /api/auth/signup (дефолты 5/мин, 20/час):
|
||||
# RateLimiting__Enabled=true
|
||||
# RateLimiting__PerMinute=5
|
||||
# RateLimiting__PerHour=20
|
||||
# Интеграция МойСклад (по умолчанию боевой api.moysklad.ru):
|
||||
# MoySklad__BaseUrl=https://api.moysklad.ru/api/remap/1.2/
|
||||
|
|
@ -29,6 +29,11 @@ services:
|
|||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: Production
|
||||
ConnectionStrings__Default: Host=postgres;Port=5432;Database=food_market;Username=food_market;Password=${POSTGRES_PASSWORD:-food_market_dev}
|
||||
# Публичный issuer токенов — обязателен за прокси, иначе берётся из запроса
|
||||
# (или дефолт localhost из appsettings, что неверно для прод).
|
||||
OpenIddict__Issuer: ${OPENIDDICT_ISSUER:-https://admin.food-market.kz/}
|
||||
# Пароль PFX-сертификатов OpenIddict (пусто = сертификаты без пароля).
|
||||
OpenIddict__CertPassword: ${OPENIDDICT_CERT_PASSWORD:-}
|
||||
# Host port mapping: pick free ports on existing stage server (80/443 taken by
|
||||
# legacy nginx, 5000/5002/5005 taken by legacy .NET apps).
|
||||
ports:
|
||||
|
|
|
|||
52
docs/secrets.md
Normal file
52
docs/secrets.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Секреты и переменные окружения
|
||||
|
||||
Все секреты задаются через `deploy/.env` (в `.gitignore`, **не коммитится**).
|
||||
Шаблон со всеми переменными — `deploy/.env.example`. docker-compose читает `.env`
|
||||
автоматически из каталога запуска (`deploy/`).
|
||||
|
||||
```bash
|
||||
cp deploy/.env.example deploy/.env
|
||||
$EDITOR deploy/.env # заполнить значения
|
||||
chmod 600 deploy/.env # ограничить доступ
|
||||
```
|
||||
|
||||
## Перечень
|
||||
|
||||
| Переменная | Обяз. | Назначение | Где используется | Как получить |
|
||||
|---|:---:|---|---|---|
|
||||
| `POSTGRES_PASSWORD` | ✅ | пароль БД `food_market` | контейнер postgres + `ConnectionStrings__Default` API | `openssl rand -base64 24` |
|
||||
| `REGISTRY` | ✅ | реестр образов | image-ссылки в compose | стейдж: `127.0.0.1:5001` |
|
||||
| `API_TAG` / `WEB_TAG` / `PUBLIC_TAG` | ✅ | теги образов | image-ссылки | тег из CI / `latest` |
|
||||
| `OPENIDDICT_ISSUER` | ✅(прод) | публичный issuer токенов | API `OpenIddict__Issuer` | публичный URL админки, напр. `https://admin.food-market.kz/` |
|
||||
| `OPENIDDICT_CERT_PASSWORD` | — | пароль PFX-сертификатов | API `OpenIddict__CertPassword` | свой пароль или пусто (self-signed без пароля) |
|
||||
| `FM_BACKUP_DIR` / `FM_UPLOADS_DIR` / `FM_BACKUP_RETENTION_DAYS` | — | параметры бэкапа | `food-market-backup.sh` | дефолты совпадают с compose |
|
||||
| `Cors__AllowedOrigins__N` | — | CORS-origins | API | переопределяет `appsettings.json` |
|
||||
| `RateLimiting__*` | — | антибрутфорс лимиты | API | дефолты 5/мин, 20/час |
|
||||
| `MoySklad__BaseUrl` | — | база API МойСклад | API | дефолт боевой `api.moysklad.ru` |
|
||||
|
||||
> `__` (двойное подчёркивание) — разделитель секций конфигурации .NET
|
||||
> (`OpenIddict__Issuer` ≡ `OpenIddict:Issuer`).
|
||||
|
||||
## Где ещё живут секреты
|
||||
|
||||
- **SMTP (отправка писем)** — НЕ в env. Хранятся в БД (`platform_settings`),
|
||||
правятся из SuperAdmin-консоли (раздел «Платформа → SMTP»). Перечитываются на
|
||||
каждой отправке без рестарта (см. `MailKitEmailSender`).
|
||||
- **Сертификаты OpenIddict** — PFX в volume `api-data` (`/app/App_Data`). Генерируются
|
||||
self-signed при отсутствии. Можно принести свои — см. [openiddict-keys.md](openiddict-keys.md).
|
||||
- **Учётки БД/Forgejo на сервере** — вне репозитория (см. приватные заметки оператора).
|
||||
|
||||
## Ротация
|
||||
|
||||
| Секрет | Как ротировать | Влияние |
|
||||
|---|---|---|
|
||||
| `POSTGRES_PASSWORD` | `ALTER USER food_market PASSWORD '…'`, обновить `.env`, `docker compose up -d` | рестарт API |
|
||||
| OpenIddict-сертификаты | заменить/удалить PFX, рестарт API | все токены инвалидируются — повторный логин |
|
||||
| SMTP-пароль | через SuperAdmin-консоль | без рестарта |
|
||||
|
||||
## Гигиена
|
||||
|
||||
- `deploy/.env` — права `600`, владелец — пользователь деплоя.
|
||||
- Не логировать значения секретов. Serilog настроен без дампа окружения.
|
||||
- При утечке — ротировать затронутый секрет (таблица выше) и пересоздать токены.
|
||||
- Проверка, что секреты не утекли в git: `git ls-files | grep -E '\.env$'` должен быть пуст.
|
||||
Loading…
Reference in a new issue