# Секреты и переменные окружения Все секреты задаются через `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` | | `Telegram__BotToken` | — | токен Telegram-бота для alert'ов и owner-сводки | `OwnerDailySummaryJob`, `DiskMonitoringJob` | bot @BotFather | | `Telegram__BotUsername` | — | username бота (без @) для deep-link'ов в notify | `TelegramBindingController` | у бота в Telegram | | `Authentication__Google__ClientId` / `__ClientSecret` | — | OAuth Google SSO (Sprint 20 scaffold) | API `ExternalAuthController` | см. `docs/sso.md` | | `Authentication__Microsoft__ClientId` / `__ClientSecret` | — | OAuth Microsoft SSO (Sprint 20 scaffold) | API `ExternalAuthController` | см. `docs/sso.md` | | `Monitoring__DiskPaths` | — | CSV mount-paths для disk-monitor (default `/opt,/var/lib/docker`) | `DiskMonitoringJob` (Sprint 20) | список mount'ов хоста | | `Monitoring__DiskMinFreeBytes` | — | порог alert'a (default 1 GB) | `DiskMonitoringJob` | в байтах | | `Monitoring__DiskAlertCooldownHours` | — | антиспам для disk-alert (default 6h) | `DiskMonitoringJob` | в часах | | `Monitoring__SuperAdminTelegramChatIds` | — | CSV chat-id'ы для disk/perf alert'ов | `DiskMonitoringJob`, `nightly-perf-check.sh` | chat-id юзера | | `Cleanup__DraftDays` / `__OrgAuditLogDays` / `__RevokedRefreshTokenDays` | — | retention для cleanup-job'ов (default 30 / 90 / 7) | `HousekeepingJobs` (Sprint 20) | в днях | | `Hangfire__Retention__StockMovementDays` / `__AuditLogDays` | — | retention для prune'ов | `HousekeepingJobs` | в днях | | `Hangfire__Cron__*` | — | переопределение cron-расписания jobs | `HangfireJobsConfigurator` | стандартный 5-полевой cron | | `Maintenance__VacuumTopN` | — | сколько таблиц VACUUM ANALYZE еженедельно (default 5) | `DatabaseMaintenanceJobs` (Sprint 20) | int | | `App__PublicBaseUrl` | — | публичный URL админки (для email-link'ов на GDPR-export) | `OrgExportJob` (Sprint 22) | напр. `https://admin.food-market.kz` | | `Storage__Type` | — | `local` (default, `/uploads` volume) или `minio` | `StorageBootstrap` | строка | | `Storage__Minio__Endpoint` / `__AccessKey` / `__SecretKey` / `__Bucket` | — | конфиг MinIO/S3 если Type=minio | `MinioObjectStorage` | у провайдера S3 | | `PUBLIC_GA_ID` / `PUBLIC_YM_ID` | — | Google Analytics 4 / Yandex.Metrika ID на marketing-сайте (Sprint 20) | Astro `BaseLayout.astro` | см. `docs/analytics.md` | > `__` (двойное подчёркивание) — разделитель секций конфигурации .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$'` должен быть пуст.