Перейти к содержанию

Панель и 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.

См. также