GSSO — Записи архитектурных решений
Acest conținut nu este încă disponibil în limba selectată.
| Код документа | SPEC-GSSO-2026 / Отчёт 01 |
| Версия | 0.2 (исходный текст EN, имеющий преимущественную силу) |
| Дата | 2026-10-06 |
| Статус | Принято. GSSO-ADR-001..014 имеют статус Acceptat (решение владельца, 2026-10-06); владелец может инициировать изменения, которые оформляются новым замещающим ADR |
| Сопутствующие отчёты | 00 RFP · 02 Требования · 03 Потребители и контракт · 04 Техническая документация · 05 Дорожная карта |
История изменений
Section titled “История изменений”| Версия | Дата | Изменения |
|---|---|---|
| 0.1-draft | 2026-10-05 | GSSO-ADR-001..014, все Proposed |
| 0.2 | 2026-10-06 | GSSO-ADR-001..014 приняты владельцем (Acceptat); пересмотр отдельных ADR возможен через новые замещающие ADR |
| 0.3 | 2026-10-06 | Выводы по реализации S1: GSSO-ADR-015 (изменяет 008) и GSSO-ADR-016 (уточняет 004), оба Proposed |
Что такое ADR
Section titled “Что такое ADR”ADR фиксирует одно значимое решение:
- контекст: ситуация, потребовавшая принятия решения;
- решение: что было выбрано;
- рассмотренные альтернативы: что было отклонено и почему;
- последствия: положительные и отрицательные эффекты, которые принимает команда.
Формат следует принятому стилю gregistry/docs/adr и paas_gflow/docs/reports/01-adr.ru.md. После принятия ADR неизменяемо, и любое изменение требует нового ADR, которое его заменяет.
Вышестоящие решения, которые необходимо соблюдать:
saas_crm/docs/reports/DECISIONS.md: D9 (GSSO — платформа идентификации gStack), D27/D28 (GSSO — существующий PaaS, подлежащий повторному использованию), D33 (стек DEV-PLAYBOOK §2 для каждого приложения).gregistry/docs/adr/ADR-002-auth-oidc-gsso.md: никаких локальных паролей, роли в GSSO, SPA использует PKCE, M2M использует client credentials.
Указатель
Section titled “Указатель”| ID | Название | Статус |
|---|---|---|
| GSSO-ADR-001 | GSSO — это control plane поверх Keycloak, а не новый поставщик идентификации | Acceptat |
| GSSO-ADR-002 | Гибридная модель realm: gstack (персонал), cetatean (граждане), tenant-* (изолированные) | Acceptat |
| GSSO-ADR-003 | Один кластер Keycloak 26.6.x с собственной PostgreSQL; существующий экземпляр сохраняется | Acceptat |
| GSSO-ADR-004 | Согласование с желаемым состоянием (desired-state reconciliation) через Keycloak Admin REST API | Acceptat |
| GSSO-ADR-005 | Роли с пространством имён платформы и плоский claim roles | Acceptat |
| GSSO-ADR-006 | Доступ предоставляется через AtribuireAcces с жизненным циклом и принципом «четырёх глаз» | Acceptat |
| GSSO-ADR-007 | События Keycloak через SPI event listener в Kafka; хранилище только на добавление; пересылка в GLog | Acceptat |
| GSSO-ADR-008 | Пользователи остаются в Keycloak; GSSO хранит проекцию для чтения | Acceptat |
| GSSO-ADR-009 | Единый шаблон интеграции для приложений: gsso-spring-boot-starter и @gstack/gsso-angular | Acceptat |
| GSSO-ADR-010 | Стек DEV-PLAYBOOK: микросервис JHipster 9.1.0 gsso + шлюз gsso-gateway + gsso-web | Acceptat |
| GSSO-ADR-011 | Конфигурация как код: базовая конфигурация realm, расширения и темы в репозитории | Acceptat |
| GSSO-ADR-012 | Token exchange (RFC 8693, стандартный token exchange V2 в Keycloak) для вызовов от имени пользователя (on-behalf-of) | Acceptat |
| GSSO-ADR-013 | Отзыв в течение 60 с: короткие токены, завершение сессий, события отзыва | Acceptat |
| GSSO-ADR-014 | Классификация по EU AI Act: GSSO не является системой ИИ | Acceptat |
| GSSO-ADR-015 | Операции с пользователями — прямые аудируемые вызовы Admin API (изменяет GSSO-ADR-008) | Proposed |
| GSSO-ADR-016 | Реализация reconciler: тонкий клиент Admin REST, маркеры владения, облегчённый токен (уточняет GSSO-ADR-004) | Proposed |
GSSO-ADR-001 — GSSO — это control plane поверх Keycloak, а не новый поставщик идентификации
Section titled “GSSO-ADR-001 — GSSO — это control plane поверх Keycloak, а не новый поставщик идентификации”Статус: Acceptat (2026-10-06)
Контекст.
- Keycloak 26.6.3 уже обслуживает все приложения gStack по адресу
sso.gstack.esempla.systems. Это сертифицированный поставщик OIDC/SAML с MFA, WebAuthn, брокерингом, федерацией LDAP, token exchange и консолью учётной записи. - Не хватает управления (governance):
- каталога сервисов;
- ролей в рамках платформы;
- согласования доступа;
- контроля расхождений (drift);
- долговременного аудита;
- единого стандарта интеграции;
- консоли в дизайн-системе gStack.
- Дизайн
GSSO.dc.htmlпредставляет GSSO как «Single Sign-On (Keycloak)».
Решение.
- GSSO — это control plane вокруг встроенного Keycloak.
- Keycloak отвечает за аутентификацию, учётные данные, сессии, выпуск токенов, MFA, федерацию, интерфейс входа (с темой GDS) и самообслуживание учётной записи.
- GSSO отвечает за:
- управляемую модель (realm, платформы, клиенты, роли платформ, предоставления доступа, организационные единицы, политики аутентификации);
- её согласование (reconciliation) с Keycloak;
- хранилище событий;
- отчёты;
- API
appдля потребителей; - консоль администрирования.
- GSSO никогда не обрабатывает пароли пользователей и никогда не выпускает токены.
Рассмотренные альтернативы.
- Использовать только штатную консоль администрирования Keycloak. Отклонено: нет каталога, нет согласования, нет контроля расхождений, нет GDS, нет аудита сверх собственного краткосрочного хранилища событий Keycloak.
- Написать собственного поставщика идентификации (Spring Authorization Server). Отклонено: пришлось бы заново реализовывать сертифицированные, критичные для безопасности функции (MFA, WebAuthn, SAML broker, LDAP) с высоким риском и затратами.
- Коммерческий IAM (Okta, Entra ID). Отклонено: ограничения суверенитета и размещения для государственных данных, стоимость лицензий и уже сделанные вложения в Keycloak.
Последствия.
- (+) Критичный для безопасности код остаётся в зрелом проекте, а GSSO остаётся небольшим.
- (+) Существующие приложения продолжают работать; URL издателя (issuer) не меняется для принятых (adopted) realm.
- (−) Два источника конфигурации могут расходиться, что смягчается согласованием (GSSO-ADR-004).
- (−) GSSO зависит от совместимости Keycloak Admin API; обновления допускаются только после прохождения тестов (GSSO-NFR-OPS-004).
GSSO-ADR-002 — Гибридная модель realm
Section titled “GSSO-ADR-002 — Гибридная модель realm”Статус: Acceptat (2026-10-06)
Контекст.
- Сессии SSO в Keycloak привязаны к realm. Пользователь, вошедший в realm A, не авторизован в realm B, если B не использует A как брокер.
- Сегодня realm
interdictiiде-факто является общим realm для персонала, тогда как другие имена realm (gdocs,gnotify,gstorage,gstack,ultra) встречаются в коде без какого-либо плана. - В макете указан один realm на систему (
cancelaria,interdictii,portal-cetatean,glog-services). Это даёт изоляцию, но не даёт общего SSO.
Решение.
| Realm | Кто | Клиенты | Федерация |
|---|---|---|---|
master | Только начальная настройка Keycloak и аварийный доступ (break-glass) | gsso-reconciler (service account) | — |
gstack | Весь персонал gStack и операторы всех учреждений | Все клиенты SaaS и PaaS для персонала, консоль GSSO, service accounts всех сервисов | AD/LDAP для каждого учреждения (опционально), без MPass |
cetatean | Граждане и предприятия | Публичные порталы и SPA для граждан | MPass/eID (SAML broker), связывание при первом входе через брокер (first-broker-login) по IDNP |
tenant-<code> | Изолированные заказчики (whitelabel-сайты ultra-*, bts-*, esempla-* или учреждение, которому требуется собственный realm) | Только клиенты данного заказчика | Для каждого tenant отдельно |
- Учреждения внутри
gstackразделяются организационными единицами (claimorg_unit) и ролями платформ, а не realm. - Realm для tenant создаются из версионируемого шаблона realm.
- Переключатель realm в консоли задаёт область realm для каждого экрана.
Рассмотренные альтернативы.
- Realm на каждое приложение (как в макете). Отклонено для персонала: нет SSO между приложениями, роли и пользователи дублируются в каждом realm. Сохранено только для
tenant-*. - Единый realm для всего, включая граждан. Отклонено: у граждан и персонала разные политики (MFA, длительность сессии, федерация, минимизация данных), а административные интерфейсы для персонала не должны быть доступны с учётной записью гражданина.
- Keycloak Organizations (несколько организаций внутри одного realm). Рассматривалось для учреждений. Оставлено как вариант на будущее (Q-GSSO-1). Организационные единицы через атрибуты покрывают текущие потребности с меньшей привязкой к недавно появившейся функции.
Последствия.
- (+) Единый вход во все приложения для персонала (цель G-1).
- (+) Данные и политики граждан изолированы от персонала.
- (−) Realm
gstackстановится критичным. Его доступность — это доступность всех приложений для персонала (GSSO-NFR-AVL-*). - (−) Существующие клиенты в
interdictiiдолжны мигрировать (отчёт 05, фаза S4), либоinterdictiiпринимается какgstack(Q-GSSO-1).
GSSO-ADR-003 — Один кластер Keycloak 26.6.x с собственной PostgreSQL; существующий экземпляр сохраняется
Section titled “GSSO-ADR-003 — Один кластер Keycloak 26.6.x с собственной PostgreSQL; существующий экземпляр сохраняется”Статус: Acceptat (2026-10-06)
Контекст.
- Работающий Keycloak имеет версию 26.6.3 (контейнер
keycloak, контейнер базы данныхpostgres-keycloak) и размещён на общем демонстрационном хосте за пограничным nginx. - В файле дизайна gstyle упоминается «Keycloak 24», но эта информация устарела.
Решение.
- GSSO фиксирует Keycloak 26.6.x (обновления патч-версий допускаются) с выделенной базой данных PostgreSQL, отдельной от базы данных GSSO.
- Репозиторий GSSO содержит определения compose и Helm, воспроизводящие работающий экземпляр:
KC_PROXY_HEADERS=xforwarded;- имя хоста
sso.gstack.esempla.systems; - смонтированные JAR расширений и темы;
- включённые health и metrics.
- Работающий экземпляр принимается в управление на месте, а не заменяется. Сначала создаётся резервная копия его базы данных, затем расширения и тема GSSO добавляются в окне обслуживания, согласованном с владельцем.
- Целевая конфигурация высокой доступности в production: 2 узла Keycloak со встроенным кластером Infinispan (сессии реплицируются) за ingress.
Рассмотренные альтернативы.
- Новый Keycloak и миграция данных: отклонено. Это изменило бы секреты и идентификаторы пользователей (
sub) и сломало бы все приложения. - Общая PostgreSQL с GSSO: отклонено, поскольку у них разные профили резервного копирования, обновления и радиуса поражения (blast radius).
Последствия.
- (+) URL издателя и
subсуществующих пользователей не меняются. - (−) Приём в управление требует тщательного runbook (отчёт 04 §11) и точки отката.
GSSO-ADR-004 — Согласование с желаемым состоянием через Keycloak Admin REST API
Section titled “GSSO-ADR-004 — Согласование с желаемым состоянием через Keycloak Admin REST API”Статус: Acceptat (2026-10-06)
Контекст.
- GSSO должен приводить Keycloak в соответствие со своей управляемой моделью, переживать частичные сбои и выявлять ручные изменения.
Решение.
- Путь записи: каждое изменение каталога или предоставления доступа фиксирует в одной транзакции изменение сущности GSSO и
JobSincronizare(транзакционный outbox). Рабочий процесс reconciler забирает ожидающие задания (SELECT … FOR UPDATE SKIP LOCKED) и применяет их черезkeycloak-admin-client26.x с service accountgsso-reconciler. - Идемпотентность: каждая операция выполняет поиск по естественному ключу (имя realm, clientId, имя роли, id пользователя + роль), а затем создаёт, обновляет или ничего не делает. Внутренний id Keycloak сохраняется обратно как
kcId. - Повторные попытки: экспоненциальная задержка (1 с → 5 мин, не более 10 попыток), затем
FAILED, что вызывает оповещение через GNotify. - Полное согласование:
- периодически (по умолчанию каждые 15 мин) и по запросу;
- вычисляет для каждого realm разницу между желаемым состоянием и Keycloak, только для управляемых типов объектов;
- результаты становятся строками
JobSincronizareсоstare=DRIFTи JSON-разницей.
- Политика расхождений для каждого realm:
REPORT(по умолчанию): только отображать;ENFORCE: исправлять автоматически;IGNORE: для принятых realm во время миграции.
- Маркер владения: объекты, созданные GSSO, имеют атрибут
gsso.managed=true. Неуправляемые объекты отображаются как «unmanaged» и никогда не удаляются, если они не приняты в управление. - Принятие (adoption): импорт только для чтения клиентов, ролей и назначений ролей realm в каталог в виде
Platforma+ClientAplicatie+RolPlatforma+AtribuireAcces(ACTIVA, sursa=ADOPTAT).
Рассмотренные альтернативы.
- Только keycloak-config-cli / Terraform: хорошо подходит для статических базовых конфигураций (используется в GSSO-ADR-011), но нет предоставления доступа во время выполнения, нет согласования и нет интерфейса.
- Прямая запись в базу данных Keycloak: отклонено как неподдерживаемое и небезопасное.
- Синхронные вызовы из интерфейса без заданий: отклонено, поскольку частичные сбои оставляют несогласованное состояние без повторных попыток.
Последствия.
- (+) Устойчивость, наблюдаемость и возможность повторного воспроизведения.
- (−) Интерфейс должен показывать статус синхронизации каждого объекта (
stareSync). - (−) Согласованность в конечном счёте (eventual consistency): обычно менее 2 с, ограничена политикой повторных попыток.
GSSO-ADR-005 — Роли с пространством имён платформы и плоский claim roles
Section titled “GSSO-ADR-005 — Роли с пространством имён платформы и плоский claim roles”Статус: Acceptat (2026-10-06)
Контекст.
- Сегодня realm-роли
ROLE_ADMINиROLE_USERобщие для всех приложений. - Приложения считывают их из
realm_access.rolesили из пользовательского claimroles. - Группам-кандидатам gFlow нужны имена ролей с префиксом приложения (
CRM_*,GTENDERS_*).
Решение.
- Каждая роль, которую предоставляет платформа, — это realm-роль с именем
<PLATFORMA_COD_UPPER>_<ROL>(например,INTERDICTII_EMITENT,CRM_ADMIN,GLOG_AUDITOR) и атрибутомgsso.platforma=<cod>. - Составные (composite) роли объединяют нижестоящие роли в пределах одной платформы.
- Роль по умолчанию
ROLE_USERсохраняется для обозначения «аутентифицированный пользователь из персонала». ROLE_ADMINобъявлена устаревшей. Во время миграции она сопоставляется с<APP>_ADMINдля каждого использующего её приложения, затем удаляется (отчёт 05 S4).- Клиентские роли допускаются для областей service account (например,
gstorage-service: object:read). Авторизация людей использует только realm-роли, чтобы один claimrolesобслуживал все приложения. - Mapper GSSO формирует плоский массив
roles(realm-роли пользователя, действующие с учётом составных ролей). - Client scope
gsso-roles-filteredможет ограничить массив ролями платформы-получателя (audience) токена плюсROLE_USER, чтобы токены оставались небольшими. - Starter сопоставляет
rolesс authorities Spring.<APP>_Xстановится authority<APP>_X; для совместимости с JHipster приложение может локально сопоставить<APP>_ADMINсROLE_ADMIN.
Рассмотренные альтернативы.
- Клиентские роли для каждого приложения для людей: отклонено. Тогда токенам нужна структура claim для каждого клиента (
resource_access), а группы-кандидаты gFlow и запросы между приложениями усложняются. - Группы как роли: группы по-прежнему используются, но только как способ объединения ролей (например, «Operator Cancelaria»). Авторизация всегда выполняется по ролям.
Последствия.
- (+) Чёткий радиус поражения для каждой платформы (цель G-2).
- (+) Один claim для всех приложений.
- (−) Существующие приложения должны переименовать свои проверки ролей, что смягчается картой псевдонимов starter во время миграции.
GSSO-ADR-006 — Доступ предоставляется через AtribuireAcces с жизненным циклом и принципом «четырёх глаз»
Section titled “GSSO-ADR-006 — Доступ предоставляется через AtribuireAcces с жизненным циклом и принципом «четырёх глаз»”Статус: Acceptat (2026-10-06)
Контекст.
- Назначения ролей, сделанные непосредственно в Keycloak, не содержат ни причины, ни согласующего, ни срока действия.
- NFRQ56–66 требуют минимальных привилегий и аудита безопасности.
- CAP-GSSO-04 требует быстрого отзыва.
Решение.
- Роль платформы для человека назначается только через
AtribuireAcces:
SOLICITATA ──approve──▶ APROBATA ──reconciled──▶ ACTIVA ──revoke──▶ REVOCATA │ │ └──validPana passed──▶ EXPIRATA └──reject──▶ RESPINSA └──second approval required (sensitive)──▶ stays APROBATA(1/2)- Правила, обеспечиваемые на сервисном уровне; каждый переход записывает
EvenimentGsso:- Запрашивающим может быть сам пользователь, его руководитель, владелец платформы или приложение через
api/v1/app. Указание причины обязательно. - Согласующий — владелец платформы или администратор realm. Для чувствительных ролей дополнительно требуется второй, отличный от первого согласующий с
GSSO_APPROVER. Никто не согласует собственный запрос. ACTIVAустанавливается только после того, как reconciler подтвердит назначение в Keycloak.validPanaнеобязателен. Его значение по умолчанию берётся из политики роли (Q-GSSO-5). Ежечасный планировщик переводит в истёкшие предоставления, срок которых наступил. Пользователи получают предупреждение об истечении срока за 14 дней и за 1 день через GNotify.- Отзыв и истечение срока удаляют назначение и запускают GSSO-ADR-013.
- Администраторы могут предоставлять доступ напрямую (запрос и согласование за один шаг) только для нечувствительных ролей. Это фиксируется в аудите как
ACORDARE_DIRECTA.
- Запрашивающим может быть сам пользователь, его руководитель, владелец платформы или приложение через
- Service accounts получают роли через конфигурацию
ClientAplicatie, а не через предоставления доступа.
Рассмотренные альтернативы.
- Назначение ролей только в Keycloak: нет управления.
- Процесс BPMN в gFlow: рассматривался. GSSO является зависимостью gFlow (gFlow аутентифицируется через GSSO), поэтому возникла бы циклическая зависимость. Жизненный цикл невелик, и машины состояний на сервисном уровне достаточно.
Последствия.
- (+) Даёт ответ на вопрос «у кого что есть, почему, с какого момента, до какого момента и кем согласовано».
- (−) Добавляет шаг в повседневную административную работу, что смягчается массовыми предоставлениями доступа и шаблонами ролей (группами).
GSSO-ADR-007 — События Keycloak через SPI event listener в Kafka; хранилище только на добавление; пересылка в GLog
Section titled “GSSO-ADR-007 — События Keycloak через SPI event listener в Kafka; хранилище только на добавление; пересылка в GLog”Статус: Acceptat (2026-10-06)
Контекст.
- Keycloak хранит пользовательские и административные события в собственной базе данных с коротким сроком хранения и не поддерживает push-доставку.
- Они нужны для панели мониторинга, событий безопасности, времени последнего входа и проекции.
- GLog — WORM-хранилище аудита gStack.
Решение.
- Event listener. Расширение Keycloak от GSSO предоставляет
EventListenerProvidergsso-kafka. Оно публикует каждое пользовательское событие (LOGIN, LOGIN_ERROR, LOGOUT, CODE_TO_TOKEN, CLIENT_LOGIN, UPDATE_CREDENTIAL, REGISTER, IDENTITY_PROVIDER_*…) и административное событие (с представлением объекта) в topic Kafkagsso.kc-events.v1:- CloudEvents в бинарном режиме;
- ключ =
realmId:userId; - асинхронно, с ограниченным локальным буфером.
- Если Kafka недоступна, событие всё равно остаётся в хранилище событий Keycloak, а пропуск восполняется из Admin API потребителем GSSO.
- Потребитель.
gssoидемпотентно потребляет topic (дедупликация поeventId), записываетEvenimentGssoи обновляетProiectieUtilizator(последний вход, неудачные попытки) и агрегаты панели мониторинга. - Собственные события GSSO. Изменения каталога, переходы предоставлений доступа и задания синхронизации записываются в
EvenimentGssoв той же транзакции, что и изменение. - Хранилище.
EvenimentGsso— только на добавление (append-only):- у репозитория нет методов обновления или удаления;
- триггер базы данных отклоняет
UPDATEиDELETE; - каждая строка содержит
hashPrecedentиhash(цепочка SHA-256 для каждого realm).
- Пересылка. Ретранслятор (relay) пересылает каждое событие в GLog
POST /api/v1/app/audit-events(client credentials, scopeaudit:write) с повторными попытками и записывает id квитанции GLog. - Срок хранения. 90 дней в GSSO (Q-GSSO-7); долговременный журнал хранится в GLog.
Рассмотренные альтернативы.
- Опрос API событий Keycloak: отклонено в качестве основного пути из-за задержки и стоимости постраничной выборки. Сохранено для восполнения пропусков.
- Сторонние listener для Kafka: отклонено. Нужны оболочка CloudEvents и именование topic по правилам gStack.
Последствия.
- (+) Панель мониторинга почти в реальном времени и журнал для расследований.
- (−) Kafka добавляется в зависимости среды выполнения Keycloak. Сбой Kafka не блокирует вход, поскольку listener асинхронный и неблокирующий.
GSSO-ADR-008 — Пользователи остаются в Keycloak; GSSO хранит проекцию для чтения
Section titled “GSSO-ADR-008 — Пользователи остаются в Keycloak; GSSO хранит проекцию для чтения”Статус: Acceptat (2026-10-06)
Контекст.
- У пользователей и учётных данных должен быть один мастер-источник. Консоли нужны быстрый поиск по всем realm, время последнего входа и статус MFA, а также просмотр предоставлений доступа по пользователю.
Решение.
- Keycloak — мастер-источник пользователей: идентичность, атрибуты, учётные данные, связи федерации.
- Редактирование пользователей в консоли вызывает Keycloak Admin API через reconciler (
JobSincronizareтипаUTILIZATOR). Сброс учётных данных и обязательные действия (required actions) вызывают его синхронно, поскольку они не являются желаемым состоянием. ProiectieUtilizatorобновляется тремя способами:- из событий;
- ночной полной синхронизацией для каждого realm (постранично, по 500 на страницу);
- по запросу при открытии пользователя.
Она хранит sub, имя пользователя, имя, e-mail,
idnp(в зашифрованном виде), признак enabled, типы MFA, время последнего входа и realm.
- Удаление пользователя в Keycloak очищает проекцию и анонимизирует поля действующего лица в рабочих таблицах GSSO. Строки аудита сохраняют только
sub.
Последствия.
- (+) Нет двойного мастер-источника; пользователи из федерации (LDAP/MPass) видны.
- (−) Проекция может отставать на несколько секунд; консоль показывает время «обновлено в».
GSSO-ADR-009 — Единый шаблон интеграции для приложений
Section titled “GSSO-ADR-009 — Единый шаблон интеграции для приложений”Статус: Acceptat (2026-10-06)
Контекст.
- Сегодня существуют четыре шаблона (отчёт 00 §2).
- Шаблон A — JWT HS512, выпускаемые приложением после входа через Keycloak, — сохраняет локальный ключ подписи и локальные пароли. Это лишает смысла единый выход (SSO logout), отзыв и аудит.
Решение.
| Тип приложения | Шаблон |
|---|---|
| Шлюз JHipster + микросервисы (playbook) | Шлюз = OAuth2 client (BFF, authorization code + PKCE, конфиденциальный). Микросервисы = resource servers. Всё через gsso-spring-boot-starter |
| Монолит Spring Boot с SPA | Resource server через starter; SPA = публичный клиент + PKCE через @gstack/gsso-angular (или режим BFF) |
| Межсервисное взаимодействие | Client credentials, один конфиденциальный клиент на каждый вызывающий сервис; token exchange для вызовов от имени пользователя (GSSO-ADR-012) |
| Клиенты Kafka | SASL OAUTHBEARER с client credentials сервиса |
| Мобильное приложение (gsso_mob) | Публичный клиент + PKCE + redirect с пользовательской схемой |
| Сервисы не на Java (Python RAG, Node) | Проверка через JWKS; документированный фрагмент кода |
- Starter (
systems.esempla.gsso:gsso-spring-boot-starter):- проверка issuer и JWKS плюс проверка audience;
roles→ authorities, с необязательной картой псевдонимов для миграции;GssoPrincipal, предоставляющийsub,username,orgUnit,locale,idnp?;- перехватчик client credentials для
RestClient/WebClientи помощник для token exchange; - listener событий отзыва (GSSO-ADR-013);
KeycloakHealthIndicatorв группе readiness;- помощник для Testcontainers.
Он повторно использует проверенный код из
gregistry(AudienceValidator) иcancelarie(KeycloakHealthIndicator).
- Angular-библиотека (
@gstack/gsso-angular): вход через PKCE (или режим сессии BFF), guard ролей и директива*gssoHasRole, тихое обновление (silent refresh), единый выход и синхронизация локали из claimlocale. - Локальные пароли и токены, выпускаемые приложением, запрещены для новых приложений и удаляются из существующих в ходе миграции (отчёт 03 §2).
Последствия.
- (+) Одна проверка безопасности охватывает все приложения; выход и отзыв работают везде.
- (−) Приложения с шаблоном A (interdictii, gdocs, gnotify) требуют изменений в коде, запланированных в отчёте 05.
GSSO-ADR-010 — Стек DEV-PLAYBOOK
Section titled “GSSO-ADR-010 — Стек DEV-PLAYBOOK”Статус: Acceptat (2026-10-06)
Решение.
gsso: JHipster 9.1.0,applicationType: microservice.- Пакет
systems.esempla.gsso,authenticationType: oauth2(сам GSSO, realmgstack), Maven, PostgreSQL, Kafka. languages: ro,ru,enс основным языкомro,skipClient: true.- Сущности из
gsso.jdl.
- Пакет
gsso-gateway: JHipster 9.1.0applicationType: gateway. Это BFF дляgsso-web(клиентgsso-console, конфиденциальный) и единая точка входа API; он маршрутизирует только/api/v1/**и/api/v1/app/**.gsso-web: отдельный Angular SPA на@gstack/gds-angular/@gstack/gds-core, с темойgdsThemedCss('#7c3aed')(--gds-accent-gsso), i18n ro/ru/en.keycloak/: расширения (модуль Maven, Java 21, Keycloak SPI 26.6.x), темы (FreeMarker + GDS CSS) и базовые конфигурации realm.- Версии Java, Spring Boot, Angular, PostgreSQL и Kafka — ровно те, что генерирует JHipster 9.1.0, с фиксацией на S0. Любое отклонение требует ADR.
- Начальная загрузка: консоль аутентифицируется в том самом Keycloak, которым она управляет. Если GSSO недоступен, Keycloak и все входы продолжают работать; приостанавливается только управление.
Последствия.
- (+) Тот же набор инструментов и те же соглашения, что и у других приложений gStack.
- (−) Консоль зависит от realm
gstack. Аварийный доступ (break-glass) — консоль администрирования Keycloak в realmmaster, доступная только команде платформы.
GSSO-ADR-011 — Конфигурация как код
Section titled “GSSO-ADR-011 — Конфигурация как код”Статус: Acceptat (2026-10-06)
Решение.
- Репозиторий содержит следующее; всё это применяется при развёртывании разовым заданием
gsso-bootstrapс помощьюkeycloak-config-cli, с подстановкой переменных и без секретов:keycloak/realms/gstack.json,cetatean.jsonиtenant-template.json: базовая конфигурация, то есть настройки realm, потоки (flows), client scopes, mappers, политика паролей, темы, event listener, а также клиентыgsso-consoleиgsso-reconciler;keycloak/extensions/(JAR);keycloak/themes/gstack/(login, account, email);docker-compose.ymlиhelm/.
- Объекты времени выполнения (платформы, их клиенты и роли, предоставления доступа, пользователи) принадлежат reconciler GSSO, а не файлам базовой конфигурации. Эти два множества не пересекаются, поэтому начальная загрузка никогда не перезаписывает объекты времени выполнения.
- Секреты (секреты клиентов, учётные данные reconciler, SMTP, привязка LDAP) поступают из переменных окружения или хранилища секретов.
.env.exampleперечисляет только имена.
Последствия.
- (+) Keycloak можно восстановить из git плюс резервной копии базы данных (цель G-4), а изменения проверяются в merge request.
GSSO-ADR-012 — Token exchange для вызовов от имени пользователя
Section titled “GSSO-ADR-012 — Token exchange для вызовов от имени пользователя”Статус: Acceptat (2026-10-06)
Контекст.
- CAP-GSSO-07: вызовы CRM ↔ gDocFlow ↔ gTenders должны передавать идентичность пользователя, чтобы вызываемое приложение применяло правила видимости этого пользователя.
Решение.
- Использовать стандартный token exchange (V2, internal-to-internal) Keycloak, доступный в 26.x.
- У каждой целевой платформы есть client scope audience.
- Клиент-источник может выполнять обмен только для audience, перечисленных в его
ClientAplicatie.audienteSchimb. GSSO согласует эти списки с разрешениями token exchange или политиками клиентов. - Полученные в результате обмена токены:
- сохраняют
subпользователя; - устанавливают
audравным целевой платформе; - содержат
act.sub= вызывающий клиент; - ограничены ролями целевой платформы.
- сохраняют
- Имперсонация и обмен external-to-internal отключены.
Последствия.
- (+) Делегирование с минимальными привилегиями без передачи паролей пользователей или долгоживущих токенов.
- (−) Разрешённые пары необходимо поддерживать; они видны в консоли и в отчёте 03.
GSSO-ADR-013 — Отзыв в течение 60 с
Section titled “GSSO-ADR-013 — Отзыв в течение 60 с”Статус: Acceptat (2026-10-06)
Контекст.
- CAP-GSSO-03/04 требуют, чтобы отозванный пользователь или роль теряли доступ в течение 60 с (в некоторых пакетах требование смягчено до 5 мин).
- Resource servers проверяют JWT офлайн, поэтому отозванная роль остаётся в ещё не истёкшем access token.
Решение.
- Время жизни access token: 5 мин в
gstack; 2 мин для клиентов с пометкойsensitive. - При отзыве, истечении срока, отключении пользователя или «завершении сессий» GSSO:
- удаляет назначение или отключает пользователя;
- удаляет сессии пользователя в Keycloak (
logoutпользователя, что также запускает back-channel logout для клиентов, которые его поддерживают); - публикует в Kafka
gsso.access-revoked.v1сsub, затронутыми ролями платформ и временем not-before.
- Starter потребляет
gsso.access-revoked.v1и хранит в памяти список запретов с ключомsub+ not-before на время жизни токена. Запрос с токеном, выпущенным до времени not-before, получает 401. - Шлюзы BFF также удаляют свою серверную сессию при back-channel logout.
Рассмотренные альтернативы.
- Интроспекция токена при каждом запросе: отклонено из-за задержки и нагрузки на Keycloak со стороны всех приложений. Остаётся доступной для особо чувствительных endpoint.
Последствия.
- (+) Отзыв в течение 60 с для приложений, использующих starter. Остальные полагаются на истечение срока токена (максимум 5 мин).
GSSO-ADR-014 — Классификация по EU AI Act
Section titled “GSSO-ADR-014 — Классификация по EU AI Act”Статус: Acceptat (2026-10-06)
Решение.
- GSSO не является системой ИИ в смысле Регламента (ЕС) 2024/1689, ст. 3(1). Он не содержит логического вывода (inference), скоринга или ранжирования лиц.
- Вход с учётом риска (адаптивная MFA по сигналам IP или устройства), если он будет добавлен позже, должен быть основан на правилах и задокументирован. Любой скоринг на основе ML требует новой классификации с помощью навыка
ai-actдо начала проектирования.
GSSO-ADR-015 — Операции с пользователями — прямые аудируемые вызовы Admin API
Section titled “GSSO-ADR-015 — Операции с пользователями — прямые аудируемые вызовы Admin API”Статус: Proposed (2026-10-06). Изменяет одно предложение GSSO-ADR-008.
Контекст.
- GSSO-ADR-008 предусматривает, что редактирование пользователей в консоли проходит через reconciler как
JobSincronizareтипаUTILIZATOR. - Пользователи не являются желаемым состоянием: их мастер-источник — Keycloak.
- Создание пользователя должно сразу возвращать консоли его id в Keycloak, а администратор ожидает, что отключение или завершение сессий подействует сразу, а не после очереди.
Решение.
- Операции с пользователями синхронно вызывают Keycloak Admin API через
KeycloakAdminClient: создание, редактирование, включение/отключение, обязательные действия (required actions), удаление учётных данных, завершение сессий, разблокировка. - Каждая успешная операция добавляет
EvenimentGssoв рамках того же запроса и обновляетProiectieUtilizator. - Ошибки Keycloak отображаются в RFC 7807: 409 — конфликт, 400 — ошибка валидации, 502 — сбои Keycloak.
- Очередь reconciler остаётся для желаемого состояния: realm, клиенты, роли и, начиная с S2, назначения ролей по предоставлениям доступа.
Последствия.
- (+) Немедленная обратная связь и отсутствие очереди для операций, не являющихся желаемым состоянием.
- (−) При недоступности Keycloak операции с пользователями сразу завершаются ошибкой, а не откладываются; консоль показывает ошибку.
GSSO-ADR-016 — Детали реализации reconciler
Section titled “GSSO-ADR-016 — Детали реализации reconciler”Статус: Proposed (2026-10-06). Уточняет GSSO-ADR-004; принятые там решения остаются в силе.
Контекст. Разработка и тестирование S1 на Keycloak 26.6.3 выявили пять моментов, которые GSSO-ADR-004 оставил открытыми или определил неверно.
Решение.
- Admin-клиент. Тонкий JSON-клиент на Spring
RestClient(KeycloakAdminClient) заменяетkeycloak-admin-client. Стек RESTEasy этой библиотеки плохо уживается со Spring Boot 4, а GSSO использует лишь небольшую часть API. Все вызовы Keycloak по-прежнему проходят через этот единственный класс. - Маркер владения.
gsso.managedпринимает два значения:catalog: создан reconciler, который может обновлять и удалять объект;baseline: принадлежит базовым файлам realm (baseline) или шаблону тенанта; reconciler никогда не изменяет и не удаляет его, а обнаружение расхождений его пропускает. Немаркированные объекты считаются неуправляемыми: о них сообщается, но они никогда не удаляются. Единственное значениеtrueпозволило бы режиму ENFORCE удалить клиент консоли и роль по умолчаниюROLE_USERв каждом realm тенанта.
- Облегчённый access token для
gsso-reconciler. Опцияclient.use.lightweight.access.token.enabled. Полный токен содержит административные роли каждого realm, созданного reconciler, и после нескольких десятков realm превышает ограничения на размер HTTP-заголовков (HTTP 431). Кроме того, его claims устаревают сразу после создания realm (HTTP 403). С облегчённым токеном (≈780 байт, постоянный размер) Keycloak проверяет права в реальном времени. Ответ 403 по-прежнему вызывает одно обновление токена и одну повторную попытку. - Порядок. Рабочий процесс забирает задания, срок которых наступил, с помощью
FOR UPDATE SKIP LOCKEDи никогда не берёт realm, у которого уже есть задание в статусеRUNNING, поэтому задания одного realm применяются по одному и в порядке id, в том числе при нескольких экземплярах (GSSO-FR-079). - Классы сбоев.
- Временные: нет ответа, 401, 429, 5xx. Повторяются с экспоненциальной задержкой (1 с → 5 мин),
FAILEDпосле 10 попыток. - Постоянные: прочие 4xx или объект, принадлежащий baseline. Сразу
FAILED.
- Временные: нет ответа, 401, 429, 5xx. Повторяются с экспоненциальной задержкой (1 с → 5 мин),
Последствия.
- (+) Каждый пункт покрыт интеграционными тестами на реальном Keycloak (
ReconcilerIT). - (−) Тонкий клиент приходится расширять вручную, когда нужны новые вызовы Admin API.