Панель и Keycloak¶
Отказы веб-консоли платформы (профиль platform): вход через Keycloak,
ошибки шлюза platform-api, лимиты запросов, несоответствие сборки веба.
Статья для инженера, сопровождающего панель, и администратора пользователей.
Замороженный периметр
Профиль platform (Keycloak, platform-api, platform-web, MinIO,
Redis) работает и исправляется при поломке, но новых функций не
получает. Harness и исполнители от него не зависят: они ходят в IAM по
PAT мимо Keycloak.
Как устроен вход¶
sequenceDiagram
participant B as Браузер
participant W as platform-web
participant K as Keycloak (realm platform)
participant P as platform-api
participant I as IAM
participant CP as Control Plane
B->>W: вход по e-mail и паролю
W->>P: POST /api/v1/auth/login
P->>K: password grant (клиент platform-api)
K-->>P: токен realm с клеймом tenant_id
B->>W: экран модуля Control Plane
W->>P: /api/v1/services/control-plane/…
P->>I: POST /tenants/{IAM_TENANT_ID}/federation:exchange
I-->>P: access token audience control-plane
P->>CP: запрос с этим токеном
CP->>CP: binding (issuer, IAM principal) → права
Отказ возможен на каждом звене: Keycloak (учётная запись, профиль),
platform-api (клейм tenant_id, лимиты), IAM (федерация identity), Control
Plane (binding человека).
Вход в Keycloak¶
| Симптом | Причина | Решение |
|---|---|---|
Форма входа отвечает ошибкой; в логах invalid_grant, Account is not fully set up |
У пользователя есть обязательное действие: временный пароль (смена при первом входе) или незаполненные firstName/lastName, которые требует user profile realm. Форма входа платформы работает через password grant, а он не умеет проводить пользователя через required actions |
Заводить пользователей с постоянным паролем (temporary: false) и заполненными именем и фамилией; для существующих — снять required actions и заполнить поля через Admin API или консоль администратора Keycloak |
Правки platform-realm.json не видны в Keycloak |
start --import-realm импортирует realm только при первом старте, существующий realm не перезаписывается |
Вносить изменения в живой realm через Admin API или консоль администратора; шаблон держать в согласии для новых установок |
Keycloak не стартует, realm-render завершился с ошибкой |
Не задан KEYCLOAK_CLIENT_SECRET (подставляется в шаблон realm) |
Задать в .env (make secrets) |
Keycloak долго в starting, затем OOM |
JVM не укладывается в KEYCLOAK_MEM_LIMIT (768m по умолчанию) |
Поднять лимит; проверить свободную память хоста |
| Ошибка про hostname или редиректы на внутренний адрес | KC_HOSTNAME строится из TAIMEN_PUBLIC_URL с путём /auth; при KEYCLOAK_HOSTNAME_STRICT=true запросы с другим именем отвергаются |
Проверить TAIMEN_PUBLIC_URL; в промышленной установке — KEYCLOAK_HOSTNAME_STRICT=true и корректное имя |
После логина редирект на чужой адрес или ошибка invalid redirect_uri |
Redirect URI клиента platform-web в realm не совпадает с публичным адресом |
Исправить redirect URI клиента в живом realm |
| Нет доступа к консоли администратора Keycloak | Пароль первичного администратора сменили в Keycloak, а .env устарел, или наоборот |
KEYCLOAK_ADMIN_PASSWORD применяется только при первом старте; пароль администратора меняется в самом Keycloak |
platform-api¶
Ошибки platform-api приходят с полями error_code, error_category,
message, request_id.
Статус и error_code |
Причина | Решение |
|---|---|---|
403 MISSING_TENANT_CLAIM |
В токене Keycloak нет клейма tenant_id: у пользователя не задан атрибут tenant_id, либо атрибут не объявлен в user profile realm (Keycloak 24+ молча отбрасывает необъявленные атрибуты), либо нет маппера |
Объявить tenant_id в user profile realm (в шаблоне поставки он объявлен), задать пользователю атрибут с UUID tenant, проверить маппер tenant_id клиента |
401 с error: authentication_required |
Токен Keycloak невалиден: истёк, подписан неизвестным ключом, issuer не совпадает | Проверить, что контейнеры видят Keycloak по публичному адресу (alias TAIMEN_PUBLIC_HOST у caddy) и issuer ${TAIMEN_PUBLIC_URL}/auth/realms/platform |
429 RATE_LIMIT_EXCEEDED |
Превышен лимит запросов с одного IP: RATE_LIMIT_PER_IP (в compose по умолчанию 300 в минуту), для входа — RATE_LIMIT_AUTH_PER_IP (20) |
Если лимит ловят все пользователи сразу — platform-api видит один адрес для всех (см. ниже); иначе поднять лимит в .env |
503 на /ready |
Не готовы зависимости: БД, Redis, миграции | docker compose logs platform-api platform-migrations |
Лимиты за прокси
platform-api определяет клиента по X-Forwarded-For с учётом
TRUSTED_PROXY_COUNT=1 (один доверенный прокси — Caddy). platform-web
пробрасывает адрес браузера в серверных вызовах к API. Если перед Caddy
стоит ещё балансировщик, объявите его в trusted_proxies Caddy, иначе все
пользователи окажутся одним клиентом и будут делить один лимит.
Шлюз к сервисам (/api/v1/services/{service}/…)¶
Статус и error_code |
Причина | Решение |
|---|---|---|
404 gateway.unknown_service |
Сервис не описан в SERVICE_GATEWAY_UPSTREAMS |
Добавить upstream (адрес, audience, scopes) |
422 gateway.invalid_path |
Путь upstream содержит ./.. |
Исправить путь запроса |
401 gateway.identity_rejected |
IAM не подтвердил identity пользователя на federation:exchange: не зарегистрирован identity provider keycloak, не совпадает issuer realm или audience iam-service в токене |
Проверить identity provider в IAM tenant и мапперы audience в realm |
403 gateway.identity_forbidden |
IAM подтвердил identity, но отказал в токене для audience или scopes upstream (например, внешняя identity не привязана к IAM principal) | Привязать внешнюю identity пользователя к IAM principal; проверить scopes в SERVICE_GATEWAY_UPSTREAMS |
503 gateway.identity_unavailable |
IAM недоступен или ответил ошибкой; в details.reason — причина (iam_status_<код>, имя исключения) |
Проверить iam-service; пустой IAM_TENANT_ID в .env даёт неверный адрес обмена — вписать tenant, который напечатал bootstrap, и пересоздать platform-api |
503 gateway.upstream_unreachable |
Upstream не отвечает | Поднять профиль сервиса |
503 gateway.not_initialized |
Шлюз не инициализирован при старте | Логи platform-api при старте |
Ответ upstream 401 invalid_credentials (конверт Control Plane) |
Для IAM principal пользователя нет binding в Control Plane | Создать binding POST /api/v1/principals/{id}/iam-bindings до первого запроса человека; при создании SQL — подождать до 120 с или перезапустить control-plane-api |
Ответы upstream, включая их 4xx/5xx, шлюз отдаёт как есть: ошибку в
конверте {"error": {"code", …}} разбирайте по статье
Аутентификация и доступ.
Веб-консоль¶
| Симптом | Причина | Решение |
|---|---|---|
| Пункт «Control Plane» не виден в меню | Модуль показывается, только если у tenant включён feature flag control_plane_console и у пользователя роль org_admin или platform_admin |
Включить флаг (PATCH /platform/api/v1/admin-config/feature-flags/control_plane_console), выдать роль в realm |
| React hydration error (#418), расхождение времени или адресов между сервером и браузером | Переменные NEXT_PUBLIC_* зашиваются в бандл при docker build (build-args из TAIMEN_PUBLIC_URL, CP_TIMEZONE); сменили .env без пересборки |
docker compose build platform-web && docker compose up -d platform-web |
Запросы веба к API уходят без префикса /platform (404) |
Адрес API с путём склеен через new URL(path, base), который отбрасывает путь базы |
В поставке путь приклеивается к базе строкой; при доработках веба сохранять это правило |
| Пользователя внезапно выкидывает на вход | Refresh токена закончился окончательным отказом Keycloak (400/401/403): сессия истекла или отозвана. На 429 и 5xx сессия не закрывается — это считается временным сбоем |
Проверить настройки сессий realm и логи Keycloak; при массовых выходах — лимиты platform-api |
| Файлы документов не открываются | MinIO недоступен или бакет не создан | docker compose logs minio minio-bootstrap; бакет S3_BUCKET создаётся minio-bootstrap |
Проверка цепочки без браузера¶
# 1. Keycloak отвечает, realm на месте
curl -s http://127.0.0.1:18081/auth/realms/platform | head -c 200
# 2. platform-api жив и готов
curl -s http://127.0.0.1:18080/health; curl -s http://127.0.0.1:18080/ready
# 3. Issuer realm, как его видят контейнеры (через alias caddy)
docker compose exec platform-api python -c \
"import urllib.request,json,os; print(json.load(urllib.request.urlopen(os.environ['KEYCLOAK_URL']+'/realms/platform/.well-known/openid-configuration'))['issuer'])" \
|| echo "проверьте доступность ${TAIMEN_PUBLIC_URL}/auth изнутри сети"
Полная процедура заведения пользователя и привязки к IAM — в статье Вход людей — Keycloak.