06 Authorization

Модель администрирования capabilities

Модель администрирования capabilities

Статус документа

Этот документ фиксирует операционную модель, по которой команда администрирует доступы в KSAILab после перехода на Keycloak.

Его цель: снять двусмысленность между IAM, platform permissions и frontend visibility.

По состоянию на 2026-03-11 backend auth foundation уже landed, поэтому ниже описывается не только target-state, но и текущий runtime baseline.

Короткий ответ

Где хранится каталог возможностей

Каталог capabilities хранится как версионируемый продуктовый контракт в двух местах:

  • в backend как capability registry;
  • в документации как canonical human-readable catalog.

Новые capability keys не создаются из UI и не заводятся вручную в Keycloak.

Где capabilities администрируются

Повседневное администрирование выполняется в platform UI, а не в Keycloak:

  • админ собирает bundles;
  • назначает bundles пользователям и группам;
  • делает точечные allow/deny overrides;
  • проверяет итоговый effective access.

Где хранятся назначения прав

Рабочие назначения прав хранятся в БД платформы:

  • bundles;
  • assignments;
  • overrides;
  • связи между bundle и capability.

Для чего нужен Keycloak

Keycloak хранит IAM-контур:

  • identity;
  • credentials;
  • login/logout endpoints и SSO session lifecycle;
  • realm roles;
  • clients;
  • protocol mappers;
  • service account ksailab-admin-service.

Важно: ksailab-admin-service нужен backend для provisioning и lifecycle-операций. Это не human admin.

Keycloak не является основным хранилищем полного каталога platform permissions. Keycloak также не является владельцем canonical browser session bootstrap для KsaiLab UI: эту роль выполняет backend через /api/v1/auth/login, /api/v1/auth/callback и GET /api/v1/auth/me.

Принцип разделения ответственности

ЗонаГде живётКто администрируетКак часто меняется
Пользователь, пароль, login/logout endpointsKeycloakIAM/platform adminПо жизненному циклу аккаунтов
Базовые realm roles admin, teacher, studentKeycloakIAM/platform adminРедко
Capability definitionsBackend + docsРазработчикиПри добавлении новых фич
Permission bundlesПлатформа БДPlatform adminЧасто
Assignments user/group -> bundleПлатформа БДPlatform adminЧасто
Allow/deny overridesПлатформа БДPlatform adminТочечно
Resource-scoped ABACBackendРазработчикиПри развитии доменной модели

Runtime baseline после backend MR !10

Сейчас в runtime уже подтверждено:

  • canonical browser login entry идёт через GET /api/v1/auth/login;
  • canonical browser callback идёт через GET /api/v1/auth/callback;
  • canonical browser logout идёт через POST /api/v1/auth/logout;
  • frontend bootstrap идёт через GET /api/v1/auth/me;
  • backend рассчитывает effective access по модели principal + bundles + overrides;
  • local POST /api/v1/auth/login и POST /api/v1/auth/refresh больше не являются рабочим auth flow и возвращают 410 Gone;
  • onboarding orchestration вынесен в отдельный POST /api/v1/onboarding/* контур;
  • минимальный capability baseline уже существует в коде.

Это нужно читать как один непрерывный контракт:

  1. frontend инициирует browser login только через backend entrypoint;
  2. backend владеет code exchange и browser auth session;
  3. frontend потребляет только уже поднятый bootstrap-контекст через /auth/me.

Следующая logout/session wave добавляет сюда ещё четыре жёстких правила:

  • browser cookie = opaque session key only;
  • auth session и access/refresh/id tokens = server-side only;
  • Redis = target storage для browser auth session;
  • local app logout и full platform logout = разные уровни одного контракта.

Текущие runtime capability keys

На сейчас backend уже отдаёт:

  • auth.bootstrap.read
  • onboarding.teacher.create
  • onboarding.group.create
  • onboarding.group.assign_teacher
  • onboarding.student.bulk_create
  • onboarding.credentials.consume

Текущие runtime bundle identifiers

Сейчас backend возвращает минимальную bootstrap summary через технические bundle identifiers:

  • role:admin
  • role:teacher
  • role:student

Это не отменяет более богатую целевую модель bundles вроде admin.base или admin.permissions, но важно не путать текущий runtime baseline с будущим административным UX.

Read-only permissions source of truth wave

Первая delivery-wave для permission administration deliberately вводит отдельный backend read layer без CRUD:

  • GET /api/v1/permissions/catalog;
  • GET /api/v1/permissions/role-mappings;
  • GET /api/v1/permissions/bundles.

Этот слой code-backed и нужен, чтобы frontend Permissions -> Roles и Permissions -> Groups перестали читать docs или локальные массивы как runtime source of truth.

Важно:

  • /auth/me остаётся bootstrap endpoint только для current principal;
  • новый /api/v1/permissions/* слой не является generic /capabilities bootstrap endpoint;
  • role mappings и starter bundles в этой волне ещё не требуют отдельной DB-модели;
  • assignments, overrides и write-оркестрация остаются follow-up треком.

Целевая административная модель

1. Capability Definition

Capability definition — это стабильный ключ вида domain.resource.action.

Примеры:

  • education.courses.read
  • education.courses.manage
  • permissions.users.manage
  • monitoring.logs.read

Definition включает:

  • ключ;
  • display name;
  • описание;
  • тип (global или resource-aware);
  • backend enforcement note;
  • frontend usage note;
  • suggested starter bundles.

Capability definition добавляется только через релиз и одновременно фиксируется:

  • в backend registry;
  • в permission-catalog.md;
  • во frontend permission matrix, если capability влияет на экран или действие.

2. Permission Bundle

Bundle — это рабочий административный набор capabilities.

Именно bundles должны быть основной единицей повседневного администрирования, потому что они:

  • быстрее поддерживаются, чем ручные назначения по одному permission;
  • уменьшают хаос;
  • позволяют быстро включать новую фичу без правок Keycloak.

Рекомендуемый продуктовый стартовый набор bundles:

  • admin.base
  • admin.permissions
  • admin.monitoring
  • teacher.base
  • student.base

Эти bundle names нужно трактовать как target administrative design для платформенного UI.

3. Assignment

Assignment связывает subject с bundle.

Subject может быть:

  • пользователем;
  • платформенной группой;
  • в будущем организационным контекстом или workspace.

Основной путь выдачи прав:

  1. realm role даёт базовую классификацию пользователя;
  2. platform admin назначает один или несколько bundles;
  3. backend рассчитывает effective capabilities;
  4. frontend получает готовый capability set через GET /api/v1/auth/me.

Важно: этот шаг 4 не означает, что frontend владеет permissions. Он только потребляет backend-calculated result.

4. Overrides

Overrides нужны как исключение, а не как основная модель.

Разрешены два вида:

  • allow override
  • deny override

Приоритет:

  1. deny override
  2. allow override
  3. bundle grants
  4. starter mapping from realm role

Это правило нужно считать canonical precedence для всей платформы.

Как это администрируется в platform UI

Раздел Permissions

Целевой административный UX должен опираться на уже существующие frontend-разделы:

  • Permissions -> Users
  • Permissions -> Groups
  • Permissions -> Roles

Permissions -> Users

Экран должен покрывать:

  • просмотр пользователя;
  • его realm role;
  • список назначенных bundles;
  • effective capabilities;
  • точечные allow/deny overrides;
  • создание teacher accounts;
  • запуск one-time credential handoff;
  • lifecycle actions через отдельный backend credential/admin contract.

Текущий frontend runtime уже пришёл к этой модели частично:

  • teacher account provisioning идёт через onboarding contract;
  • временный пароль раскрывается только через one-time credential receipt flow;
  • каталог пользователей, активация и удаление читаются из backend directory API;
  • follow-up password changes больше не живут в admin UI и уходят в self-service Settings -> Security flow;
  • assignments, effective capabilities, allow/deny overrides и admin credential lifecycle ещё ждут отдельный backend permission contract.

Settings -> Security

Self-service безопасность не должна смешиваться с административным CRUD раздела Permissions.

Текущий frontend contract здесь такой:

  • Settings -> Security открывает только backend-owned account security entrypoint GET /api/v1/auth/account/security;
  • frontend не вызывает legacy /users/password/* endpoints как рабочую модель;
  • delete-account и admin reset-password остаются явно unavailable, пока backend не отдаст отдельный lifecycle contract.

Permissions -> Groups

Экран должен покрывать:

  • создание и редактирование permission bundles;
  • привязку capabilities к bundle;
  • назначение bundle группам;
  • просмотр, какие пользователи получают право через group assignment.

Текущий frontend runtime здесь сознательно ограничен:

  • экран больше не использует моковые группы, fake counters или локальный CRUD;
  • он показывает живой backend snapshot существующих групп как будущих assignment targets;
  • создание учебных групп и roster actions остаются в Education -> Groups;
  • собственный bundle catalog и group assignments ещё должны прийти отдельным backend-контрактом.

Permissions -> Roles

Экран должен покрывать:

  • mapping базовых realm roles к стартовым bundles;
  • просмотр базового набора capabilities по role family;
  • аудит, какие capabilities приходят из role starter mapping, а какие из bundle/override.

Текущий frontend runtime здесь тоже уже подготовлен к следующей волне:

  • список, detail route и create route уже разведены как отдельные экраны;
  • список показывает runtime baseline role:admin, role:teacher, role:student и документированные starter bundles / scope groups;
  • backend read-model теперь поставляет этот snapshot через GET /api/v1/permissions/role-mappings, GET /api/v1/permissions/bundles и GET /api/v1/permissions/catalog;
  • create и edit intentionally не притворяются рабочим CRUD, пока backend role mapping orchestration ещё не отдал контракт.

При этом onboarding первой версии раскладывается так:

  • Permissions -> Users — teacher accounts;
  • Education -> Groups — создание groups;
  • Education -> Groups -> roster — bulk onboarding студентов.

Это важно, потому что student provisioning в KSAILab привязан к group membership, а не к абстрактной пользовательской карточке.

Как быстро добавлять новую capability

Целевой рабочий сценарий должен занимать один релиз и несколько минут админской настройки после него.

Добавление новой фичи

  1. Разработчик добавляет capability key в backend registry.
  2. Разработчик обновляет permission-catalog.md.
  3. Разработчик добавляет backend policy check.
  4. Если capability влияет на UI, обновляется frontend-permission-matrix.md.
  5. После релиза platform admin открывает Permissions -> Groups и добавляет capability в нужные bundles.
  6. Пользователи сразу получают новый доступ через существующие assignments.

Это и есть модель релиз + UI-настройка.

Удаление capability

Безопасный порядок:

  1. отметить capability как deprecated в каталоге;
  2. убрать её из bundles;
  3. удалить обращения из frontend;
  4. удалить backend policy usage;
  5. только после этого удалять definition.

Что меняется без релиза, а что нет

Без релиза можно

  • создать новый bundle;
  • выдать или снять bundle;
  • сделать точечный override;
  • поменять composition существующих bundles;
  • изменить mapping realm role -> starter bundles;
  • отключить или включить пользователя через platform UI.

Для первой версии отдельно фиксируется:

  • manual onboarding выполняет только admin;
  • учётки teacher и student не создаются преподавателями;
  • временный пароль выдаётся через credential_receipt и одноразовый consume flow;
  • обычное добавление новой platform feature не требует правок в Keycloak.

Требует релиза

  • новый capability key;
  • новая backend policy;
  • новая resource-scoped ABAC логика;
  • новая frontend feature, если у неё ещё нет capability contract;
  • изменения в auth flow;
  • изменения клиентов, realm roles или mapper contract в Keycloak.

Как быстро настраивать Keycloak

Основной принцип

Keycloak нужно настраивать как Realm as Code, а не вручную через GUI как единственный способ работы.

Это означает:

  • realm/bootstrap/provisioning config хранится в keycloak-scripts-ksailab;
  • clients, roles и mappers заводятся через bootstrap/import;
  • ручные правки в UI допустимы только для диагностики и экстренного администрирования.

Отдельные repo boundaries для Keycloak-контура:

  • ci-pipelines/pipelines-ksailab — source of truth для pipeline logic;
  • infra-keycloak-ksailab — физический deployment Keycloak;
  • keycloak-theme-ksailab — login theme и branding.

Поддерживаемый scripting path для scripts repo — только Python. PowerShell fallback больше не считается supported operational path.

Что обязательно должно быть описано as code

  • realm;
  • clients ksailab-frontend, ksailab-backend, ksailab-admin-service;
  • redirect URIs;
  • logout URIs и post-logout redirect contract;
  • realm roles admin, teacher, student;
  • protocol mappers для базовых claims и roles;
  • service account permissions для backend orchestration.

При этом ownership clients нужно описывать явно:

  • ksailab-frontend может оставаться transition browser-login client, если runtime ещё опирается на него под backend initiation;
  • ksailab-backend не нужно путать с canonical browser-login client, пока он остаётся backend-facing audience/bearer contract;
  • target architecture предпочитает отдельный backend browser-auth client, чтобы убрать двусмысленность ownership.

Временная политика работы через Keycloak GUI

До полной стабилизации realm as code допускается использовать Keycloak GUI, но только как вспомогательный инструмент:

  • для первичного исследования настроек realm/client;
  • для smoke-валидации после деплоя;
  • для аварийного unblock, если нужно быстро подтвердить гипотезу.

При этом действуют жёсткие правила:

  1. Ручная GUI-правка не становится канонической сама по себе.
  2. Любое рабочее изменение должно быть перенесено в keycloak-scripts-ksailab в том же delivery cycle.
  3. Если GUI-изменение влияет на backend/frontend contract, это отдельно фиксируется в docs и связанных issue.
  4. Долгоживущая конфигурация, существующая только в GUI, считается техническим долгом.

Отдельная boundary по human admin bootstrap:

  • первый human admin platform-admin создаётся через отдельный operator flow в Keycloak;
  • backend runtime может только проверять presence и синхронизировать профиль при login;
  • ksailab-admin-service не должен описываться как human admin surrogate.

Когда Keycloak реально нужно менять

Правки в Keycloak нужны, если меняется:

  • login flow;
  • client configuration;
  • redirect URI policy;
  • post-logout redirect policy;
  • realm roles;
  • federation;
  • SSO/integration topology;
  • claims или mapper contract.

Для обычного добавления новой platform feature Keycloak менять не нужно. Для обычного изменения bundles, assignments, overrides или capability rollout Keycloak также не должен становиться точкой ежедневного администрирования.

Что должен рассчитывать backend

Backend должен возвращать в GET /api/v1/auth/me уже готовый effective access context:

  • principal;
  • classification;
  • realm_roles;
  • effective_capabilities;
  • bundles.

Backend остаётся единственным источником истины по effective permissions, потому что только он видит:

  • realm roles из IAM;
  • bundles и assignments из БД платформы;
  • overrides;
  • ABAC-контекст ресурса.

Отдельно:

  • /auth/me не является прямым чтением Keycloak token payload для UI;
  • /auth/me не заменяет backend session ownership;
  • /auth/me не отменяет обязательную backend ABAC-проверку реального действия.

Критерии правильной модели

Модель считается операционно удачной, если:

  • Keycloak не превращается в хранилище сотен platform permissions;
  • новые capability keys появляются только через контролируемый релиз;
  • админ может за минуты выдать новую фичу через bundle composition;
  • frontend строит меню и экраны по GET /api/v1/auth/me;
  • backend централизованно проверяет доступ и не полагается на UI.

Связанные документы