iac/apps/auth-flow/CONFIGURATION.md

163 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Конфигурация проекта auth-flow-frontend
Документ описывает способы конфигурирования микрофронтенда аутентификации `auth-flow-frontend` (React + webpack), а также все переменные сборки, деплоя и рантайма.
## Способы конфигурирования
В отличие от бэкенд-сервисов, приложение **не читает `.env` и не использует dotenv**. Это статический фронтенд, собираемый webpack, поэтому конфигурация распределена по трём уровням:
1. **Сборка (build-time).** Переменная `ENDPOINT` определяет окружение. Её значение подставляется в код на этапе сборки через `webpack.DefinePlugin` (`webpack.config.ts`) — заменяет обращения `process.env.ENDPOINT` и `process.env.IS_DEV` на строковые литералы. Выбор режима (`development`/`production`) и флага `isDev` выполняется в `webpack/build.config.ts`.
2. **Установка зависимостей.** Пакеты `@sarex-team/*` тянутся из приватного npm-реестра (`.npmrc` → `nexus.infra.sarex.io`). Для доступа нужен токен `NPM_NEXUS_TOKEN`.
3. **Рантайм (runtime).** Параметры OIDC-провайдера — `authority` и `client_id` — читаются из `localStorage` (`src/config/zitadel.ts`) по ключам `STORAGE.AUTHORITY` и `STORAGE.CLIENT_ID` из `@sarex-team/sdk-js`. Их задаёт хостовое приложение, а не сборка.
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (dev) | `npm run dev``ENDPOINT=local webpack serve`. Dev-сервер на `https://localhost:9000` |
| Локально (build) | `npm run build``webpack --config webpack.config.ts` (по умолчанию `ENDPOINT=prod`, см. `build.config.ts`) |
| Docker | `Dockerfile`: build-args `ENDPOINT` и `NPM_NEXUS_TOKEN`; сборка dist → отдача через nginx |
| Kubernetes (Helm) | `.helm/values.yaml` (чарт `universal-chart`): блок `services.frontend`, `global.env` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: `workflow.rules` (ветка/тег → `STAND`, `ENDPOINT`, `CHART_VERSION`), `BUILD_ARGS`, `HELM_SET_ARGS` |
## Переменные сборки (build-time)
Подставляются в код на этапе сборки; в рантайме это уже константы.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ENDPOINT` | enum | `prod``build.config.ts`, если не задана) | Окружение сборки: `local`/`stage`/`prod`/`preprod`/`contour`. Определяет `mode` (`development` для `local`, иначе `production`) и `isDev` |
| `IS_DEV` | bool | — (вычисляется) | `true`, если `ENDPOINT === 'local'`. Включает dev-роуты (`/login`, `/logout`, `/`). Задаётся автоматически через `DefinePlugin`, вручную указывать не нужно |
| `NPM_NEXUS_TOKEN` | string | — | Токен авторизации в приватном npm-реестре `@sarex-team` (`.npmrc`). Обязателен для `npm i` |
> `mode` по окружениям (`webpack/build.config.ts`): `local` → `development`, `stage`/`prod`/`preprod`/`contour` → `production`. Неизвестное значение `ENDPOINT` приводит к ошибке сборки.
## Переменные рантайма (localStorage)
Читаются в браузере во время работы приложения; задаются хостовым приложением, не сборкой.
| Ключ | Источник | Назначение |
| --- | --- | --- |
| `STORAGE.AUTHORITY` | `@sarex-team/sdk-js` | URL issuer'а Zitadel (`authority` OIDC). Обязателен — при отсутствии `src/config/zitadel.ts` бросает `Error("Authority or client ID is not set")` |
| `STORAGE.CLIENT_ID` | `@sarex-team/sdk-js` | `client_id` OIDC-клиента. Обязателен (та же проверка) |
| `sarex_logout` (`LOGOUT_STORAGE_KEY`) | `src/config/logout.ts` | Состояние логаута между вкладками (`{ logoutAt, owner, reason }`). Снимается только валидным токеном в `setTokensInfo` |
| access / refresh / id токены | `storage` из `@sarex-team/sdk-js` | Устанавливаются в `setTokensInfo` (`storage.setAccessToken`/`setRefreshToken`/`setIdentityToken`) после успешного колбэка |
## Конфигурация OIDC (Zitadel)
Задаётся в `src/config/zitadel.ts` (`configZitadel: ZitadelConfig`), клиент создаётся через `createZitadelAuth`.
| Параметр | Значение | Назначение |
| --- | --- | --- |
| `authority` | из `localStorage` (`STORAGE.AUTHORITY`) | Issuer Zitadel |
| `client_id` | из `localStorage` (`STORAGE.CLIENT_ID`) | Идентификатор клиента |
| `response_type` | `code` | Authorization Code Flow |
| `scope` | `openid profile email offline_access urn:zitadel:iam:user:metadata` | Запрашиваемые области |
| `redirect_uri` | `${window.location.origin}/auth/callback` | URL возврата после логина |
| `post_logout_redirect_uri` | `${window.location.origin}/login` | URL после логаута |
| `redirectMethod` | `replace` | Замена записи в истории браузера |
| `revokeTokensOnSignout` | `false` | Не отзывать токены при выходе |
| `automaticSilentRenew` | `false` | Фоновое обновление токенов выключено |
| `validateSubOnSilentRenew` | `false` | — |
| `silentRequestTimeoutInSeconds` | `100` | Таймаут silent-запроса |
## Роуты приложения
Определены в `src/config/urls.ts`, диспетчеризация в `src/App.tsx`.
| Роут | Константа | Доступность | Назначение |
| --- | --- | --- | --- |
| `/auth/callback` | `CALLBACK` | всегда | Обработка OIDC-колбэка (по умолчанию для неизвестных путей) |
| `/auth/error` | `ERROR` | всегда | Страница ошибки аутентификации |
| `/login` | `LOGIN` | только dev | Dev-страница входа |
| `/logout` | `LOGOUT` | только dev | Dev-страница выхода |
| `/` | `HOME` | только dev | Dev-навигация |
> В production разрешены только `/auth/callback` и `/auth/error` (`ALLOWED_PATHS`); в dev дополнительно `/login`, `/logout`, `/` (`ALLOWED_PATHS_DEV`). Неразрешённый путь заменяется на `/auth/callback` (`history.replaceState`).
## Сборка (webpack)
`webpack.config.ts` + `webpack/build.config.ts`.
| Параметр | Значение | Примечание |
| --- | --- | --- |
| `entry` | `src/index.tsx` | Точка входа |
| `output.path` | `dist/` | |
| `output.filename` | `index.js` | |
| `output.publicPath` | `/` (dev) или `/auth/callback/` (prod) | Зависит от `isDev` |
| loader | `esbuild-loader`, target `es2015` | Для `.tsx?/.jsx?` |
| `devServer` | `https`, `port: 9000`, `hot`, `historyApiFallback`, `open` | Только dev |
| plugins | `HtmlWebpackPlugin` (`public/index.html`), `DefinePlugin` (`ENDPOINT`, `IS_DEV`) | |
Node-версия для разработки: `v20.0.0` (`.nvmrc`; в `package.json` заявлено `v20.0.0`, реальная база образа — `node:20`).
## Docker
`Dockerfile` — двухстадийная сборка.
| Стадия | База | Действия |
| --- | --- | --- |
| build | `cr.yandex/crp3ccidau046kdj8g9q/node:20` | `npm i` (с `NPM_NEXUS_TOKEN`), `npm run build` (с `ENDPOINT`) |
| runtime | `cr.yandex/crp3ccidau046kdj8g9q/nginx:latest` | Копирует `/app/dist/``/dist/`, `nginx/nginx.conf``/etc/nginx/nginx.conf` |
Build-args: `ENDPOINT`, `NPM_NEXUS_TOKEN`.
## Nginx
`nginx/nginx.conf` — отдача статики и healthcheck.
| Локация | Поведение |
| --- | --- |
| `= /auth/callback/index.js` | `alias /dist/index.js` |
| `^~ /auth/callback` | `try_files $uri $uri/ /index.html`; заголовки `Cache-Control: no-store,...`, кеш отключён |
| `= /ping` | `200 {"result": "ok"}` (healthcheck) |
`listen 80`, `root /dist`, логи в stdout/stderr, `gzip on`.
## Helm-чарт (`.helm/values.yaml`)
Деплой через зонтичный чарт `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`, версия `0.1.7`; `Chart.yaml` приложения — `auth-flow-frontend` `1.0.0`). Значения задаются с ключами по окружениям (`_default`/`stage`/`preprod`/`production`).
| Параметр | Значение | Назначение |
| --- | --- | --- |
| `global.env` | `stage` (`_default` в файле) | Активное окружение чарта |
| `services.frontend.enabled` | `true` | Включение сервиса |
| `deployment.name._default` | `auth-flow-frontend` | Имя деплоймента |
| `deployment.replicaCount` | `_default: 1`, `production: 2` | Число реплик |
| `deployment.port._default` | `80` | Порт контейнера |
| `deployment.revisionHistoryLimit._default` | `5` | Хранимые ревизии |
| `deployment.resources.requests` | `memory: 128Mi`, `cpu: 100m` | Реквесты ресурсов |
| `deployment.probes.liveness/readiness` | `httpGet` `/` : `80` | Пробы |
| `image.name._default` | `cr.yandex/crp3ccidau046kdj8g9q/auth-flow-frontend` | Образ |
| `image.pullPolicy._default` | `IfNotPresent` | |
| `imagePullSecrets.name._default` | `dockerhub` (enabled `false`) | Секрет реестра |
| `service` | `ClusterIP`, port/targetPort `80`, portName `http`, имя `auth-flow-frontend-service` | Service |
| `envs` | `[]` | Переменные окружения контейнера (пусто) |
| `volumes._default` | `[]` | Тома |
| `commitSha`/`gitlabUri`/`gitlabJobUrl`/`owner` | заполняются из CI (`owner` по умолчанию `team-abc`) | Метаданные |
## CI (`.gitlab-ci.yml`)
Подключает общие шаблоны `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml` ref `apps-business`).
Базовые переменные: `SERVICE_NAME=auth-flow-frontend`, `DOCKERFILE_PATH=./Dockerfile`, `CI_TRIGGER_SOURCE=app`.
Переключение окружения по `workflow.rules`:
| Условие | STAND | ENDPOINT | CHART_VERSION | K8S_HUSTLER_BRANCH |
| --- | --- | --- | --- | --- |
| `merge_request_event` | — | — | — (`ENABLE_BUILD_IMAGE=false`) | — |
| ветка `stage` | `stage` | `stage` | `0.0.1-stage` | `universal-chart-stage` |
| тег (`CI_COMMIT_TAG`) | `production` | `prod` | `0.0.1-prod` | `universal-chart-production` |
> Правило для ветки `master` → `preprod` присутствует, но **закомментировано**. `NAMESPACE` для всех окружений — `platform`, `RELEASE_NAME`/`CHART_NAME` — `${SERVICE_NAME}`.
`BUILD_ARGS` прокидывают `--build-arg ENDPOINT=<env>` и `--build-arg NPM_NEXUS_TOKEN=${NPM_NEXUS_TOKEN}`. `HELM_SET_ARGS` устанавливают `universal-chart.services.frontend.image.name.<env>`, `global.env`, а также `commitSha`, `gitlabUri`, `gitlabJobUrl`, `owner`.
## Замечания и потенциальные проблемы
- **Обязательные runtime-параметры.** Если в `localStorage` нет `AUTHORITY` или `CLIENT_ID`, `src/config/zitadel.ts` бросает ошибку при инициализации — приложение не стартует. Эти значения должен положить хостовый сервис до загрузки микрофронтенда.
- **Нет `.env`.** Приложение не читает dotenv; `process.env.ENDPOINT`/`IS_DEV` существуют только на этапе сборки (замена через `DefinePlugin`). Значение `ENDPOINT` задаётся только через CLI/`--build-arg`/CI.
- **publicPath в prod** — `/auth/callback/`: приложение обслуживается nginx под префиксом `/auth/callback`, что согласовано с `redirect_uri` OIDC.
- **`silentRenew` отключён** намеренно (`automaticSilentRenew: false`) — обновление токенов не выполняется в фоне.