GSSO — Documentație tehnică
| Cod document | SPEC-GSSO-2026 / Raportul 04 |
| Versiune | 0.1-draft (sursa EN, text care prevalează) |
| Data | 2026-10-05 |
| Statut | Proiect: descrie sistemul planificat. Încă nu există cod |
| Rapoarte însoțitoare | 00 Caiet de sarcini · 01 ADR · 02 Cerințe · 03 Consumatori și contract · 05 Foaie de parcurs |
Istoricul reviziilor
Section titled “Istoricul reviziilor”| Versiune | Data | Modificări |
|---|---|---|
| 0.1-draft | 2026-10-05 | Vederi C4, componente, model de date, fluxuri, configurația de bază a realm-urilor, securitate, implementare, runbook de preluare, dimensionare, observabilitate, testare |
1. Contextul sistemului (C4 nivelul 1)
Section titled “1. Contextul sistemului (C4 nivelul 1)”flowchart TB admin([Administrator IAM / proprietar de platformă / aprobator / auditor / helpdesk]) staff([Utilizator angajat]) citizen([Cetățean]) apps[SaaS și PaaS gStack<br/>interdictii, cancelaria, gdocs, gregistry, drumuri,<br/>CRM, gDocFlow, gTenders, glog, gnotify, gstorage, gflow] mob[gsso_mob GovSign] gsso[[GSSO<br/>platforma de identitate și SSO]] mpass[MPass / eID] ldap[AD / LDAP al instituțiilor] glog[GLog] gnotify[GNotify] smtp[Releu SMTP]
admin -- consolă --> gsso staff -- autentificare / SSO --> gsso citizen -- autentificare --> gsso mob -- OIDC PKCE --> gsso apps -- OIDC, JWKS, api/v1/app, evenimente Kafka --> gsso gsso -- broker SAML --> mpass gsso -- federare LDAP --> ldap gsso -- evenimente de audit --> glog gsso -- alerte, notificări de expirare --> gnotify gsso -- invitații, e-mailuri de resetare --> smtp2. Containere (C4 nivelul 2)
Section titled “2. Containere (C4 nivelul 2)”flowchart LR subgraph edge[Margine] nginx[nginx / ingress<br/>sso.gstack… · gsso.gstack…] end subgraph gssoSys[GSSO] web[gsso-web<br/>Angular + GDS<br/>static] gw[gsso-gateway<br/>gateway JHipster 9.1 · BFF] srv[gsso<br/>microserviciu JHipster 9.1] db[(PostgreSQL<br/>gsso)] kc[Keycloak 26.6.x<br/>+ gsso-kc-extensions<br/>+ tema gstack] kdb[(PostgreSQL<br/>keycloak)] boot[gsso-bootstrap<br/>job keycloak-config-cli] end kafka[[Kafka]] glog[GLog] gn[GNotify]
nginx --> web nginx --> gw nginx --> kc gw -- /api/v1/** --> srv gw -. flux OIDC code, client gsso-console .-> kc srv -- Admin REST, SA gsso-reconciler --> kc srv --- db kc --- kdb boot -- realm-uri de bază --> kc kc -- gsso.kc-events.v1 --> kafka kafka --> srv srv -- gsso.access-revoked.v1, gsso.grant.v1 --> kafka srv -- audit --> glog srv -- notificare --> gn| Container | Tehnologie | Responsabilitate |
|---|---|---|
gsso-web | Angular (versiunea conform JHipster 9.1.0), @gstack/gds-angular, ngx-translate ro/ru/en | Interfața consolei; fără token-uri (cookie BFF) |
gsso-gateway | Gateway JHipster 9.1.0 (Spring Cloud Gateway), client OAuth2 | Autentificare și sesiune (BFF), CSRF, rutarea /api/v1/**, limitări de rată pe zona app |
gsso | Microserviciu JHipster 9.1.0, Spring Boot, Hibernate, Liquibase, Kafka, keycloak-admin-client 26.x | Catalog, atribuiri, reconciliator, consumator de evenimente, releu către GLog, rapoarte, API-urile admin și app |
| Keycloak | quay.io/keycloak/keycloak:26.6.x (imagine personalizată cu extensii + temă, kc.sh build) | Autentificare, token-uri, sesiuni, MFA, federare, consola contului |
gsso-bootstrap | adorsys/keycloak-config-cli compatibil cu 26.x | Aplică configurațiile de bază ale realm-urilor la implementare (idempotent) |
| PostgreSQL ×2 | așa cum este generat de JHipster 9.1.0 (gsso); versiune suportată de Keycloak (keycloak) | Baze de date, copii de rezervă și cicluri de viață separate |
| Kafka | clusterul gStack partajat (țintă Strimzi; un singur broker în compose) | Transportul evenimentelor |
2.1 Structura depozitului (govtech/gstack/gsso)
Section titled “2.1 Structura depozitului (govtech/gstack/gsso)”gsso/ CLAUDE.md gsso.jdl gsso.dc.html test-scenarios.md .env.example docs/reports/ 00..05 (en, ro, ru), README, docx/, pdf/, img/ keycloak/ extensions/ Maven module: gsso-kafka event listener, mappers (roles, roles_scoped, org_unit, tenant), conditional-role authenticator themes/gstack/ login/, account/, email/ (FreeMarker + GDS CSS, messages_ro/ru/en) realms/ gstack.json, cetatean.json, tenant-template.json (keycloak-config-cli, ${ENV} placeholders) Dockerfile FROM keycloak:26.6.x → kc.sh build with providers + theme gsso/ JHipster 9.1.0 microservice (generated from gsso.jdl + custom code) gsso-gateway/ JHipster 9.1.0 gateway gsso-web/ Angular SPA on GDS sdk/ gsso-spring-boot-starter/ gsso-angular/ deploy/ docker-compose.yml local + demo host stack docker-compose.test.yml postgres + kafka + keycloak for IT (always `down -v`) nginx/gsso.conf vhost templates (applied only with owner approval) helm/gsso/ Kubernetes target testing/results/3. Componentele gsso
Section titled “3. Componentele gsso”Pachet (systems.esempla.gsso) | Componentă | Note |
|---|---|---|
domain, repository, service, web.rest | CRUD generat de JHipster pentru entitățile JDL | regenerat; codul personalizat se află în clase cu denumiri separate |
keycloak | KeycloakAdminGateway | Singura clasă care accesează keycloak-admin-client. Căutări după cheie naturală, marcajul gsso.managed, traducerea erorilor în RFC 7807 |
sync | JobOutbox, ReconcilerWorker, RealmDiffer, DriftPolicy | Joburi outbox, worker cu FOR UPDATE SKIP LOCKED + advisory lock per realm, diff complet periodic |
sync.handlers | RealmHandler, ClientHandler, RoleHandler, RoleMappingHandler, UserHandler, PolicyHandler, OrgUnitHandler | Un handler per tip de obiect: apply(job), diff(realm) |
grant | GrantLifecycleService, GrantExpiryScheduler, ApprovalPolicy | Mașina de stări, principiul „patru ochi”, expirare, notificări |
events | KcEventConsumer, EventStore, HashChain, GlogRelay, RevocationPublisher | Consum idempotent, stocare append-only, redirecționare, evenimente de ieșire |
projection | UserProjectionUpdater, NightlyUserSync | ProiectieUtilizator |
report | DashboardAggregator, AccessReport | KPI-uri, intervale de autentificări, structura metodelor de autentificare |
web.rest.admin, web.rest.app | Controlere de fațadă | Zone, scope-uri, filtru de delimitare pe realm, stocarea Idempotency-Key |
security | RealmScopeAuthorizationManager, PlatformScopeAuthorizationManager | Delimitarea GSSO_REALM_ADMIN/GSSO_PLATFORM_OWNER |
notify | GnotifyClient | Avertismente de expirare, alerte |
4. Modelul de date
Section titled “4. Modelul de date”erDiagram REALM ||--o{ CLIENT_APLICATIE : "conține" REALM ||--|| POLITICA_AUTENTIFICARE : "are" REALM ||--o{ UNITATE_ORGANIZATIONALA : "are" REALM ||--o{ PROIECTIE_UTILIZATOR : "proiectează" PLATFORMA ||--o{ CLIENT_APLICATIE : "deține" PLATFORMA ||--o{ ROL_PLATFORMA : "expune" PLATFORMA }o--o{ REALM : "implementată în" ROL_PLATFORMA ||--o{ ROL_PLATFORMA : "compus din" PACHET_ROLURI }o--o{ ROL_PLATFORMA : "grupează" ATRIBUIRE_ACCES }o--|| ROL_PLATFORMA : "acordă" ATRIBUIRE_ACCES }o--o| PACHET_ROLURI : "prin pachet" ATRIBUIRE_ACCES }o--o| UNITATE_ORGANIZATIONALA : "delimitată la" ATRIBUIRE_ACCES ||--o{ APROBARE : "aprobată prin" UNITATE_ORGANIZATIONALA ||--o{ UNITATE_ORGANIZATIONALA : "părinte" JOB_SINCRONIZARE }o--|| REALM : "vizează" EVENIMENT_GSSO }o--|| REALM : "în"Definiția de referință este gsso.jdl. Câmpurile principale:
| Entitate | Câmpuri-cheie | Note |
|---|---|---|
Realm | nume (unic), denumireAfisata, tip {STAFF, CETATEAN, TENANT, SERVICE}, brokerAlias, politicaDrift {REPORT, ENFORCE, IGNORE}, stare {ACTIV, INACTIV}, stareSync, kcId, adoptat | |
Platforma | cod (unic), denumire, tip {SAAS, PAAS}, descriere (ro/ru/en), urlBaza, accent, stare, autoInregistrare | proprietarii prin ProprietarPlatforma(sub) |
ClientAplicatie | clientId, protocol {OIDC, SAML}, tipAcces {PUBLIC_PKCE, CONFIDENTIAL, BEARER_ONLY, SERVICE_ACCOUNT}, redirectUris, webOrigins, postLogoutUris, backchannelLogoutUrl, audienta, scopuri, audienteSchimb, sensibil, stare, stareSync, kcId | unic (realm, clientId) |
RolPlatforma | cod (cu prefix, unic per realm), descriereRo/Ru/En, compozit, sensibil, valabilitateImplicitaZile, stareSync, kcId | rolurile-copil prin autorelație |
PachetRoluri | cod, denumire, roluri | reconciliat ca grup Keycloak |
AtribuireAcces | userSub, realm, rol / pachet, unitate, validDe, validPana, stare {SOLICITATA, APROBATA, ACTIVA, RESPINSA, REVOCATA, EXPIRATA}, solicitant, motiv, sursa {CONSOLA, APP, ADOPTAT, DIRECT}, motivRevocare | |
Aprobare | atribuire, aprobator, nivel (1/2), decizie, comentariu, data | |
UnitateOrganizationala | cod, denumire (ro/ru/en), parinte, sefi | |
PoliticaAutentificare | parola, otp, webauthn, qr, client, broker, magic (booleene), politicaParola, mfaRoluriSensibile, sesiuneInactivMin, sesiuneMaxOre, tokenAccesMin | una per realm |
JobSincronizare | realm, tipObiect, cheieObiect, operatie {CREATE, UPDATE, DELETE, MAP, UNMAP, DIFF}, stare {PENDING, RUNNING, OK, FAILED, DRIFT, ACCEPTAT}, incercari, urmatoareaIncercare, eroare, diff (jsonb), corelatie | |
ProiectieUtilizator | sub, realm, username, nume, email, idnpCriptat, activ, mfa (set), ultimaAutentificare, ultimulEsec, unitate, locale, actualizatLa | model de citire |
EvenimentGsso | id (UUID), realm, tip, categorie {KC_USER, KC_ADMIN, CATALOG, GRANT, SYNC, CONSOLE}, actor, subiect, client, ip, moment, payload (jsonb), hashPrecedent, hash, glogId | append-only; partiții lunare |
Coloanele JSONB (diff, payload, descriere) sunt declarate ca TextBlob în JDL și convertite printr-un changelog Liquibase suplimentar cu @JdbcTypeCode(SqlTypes.JSON). Changelog-urile sunt append-only.
5. Fluxuri cap-coadă
Section titled “5. Fluxuri cap-coadă”5.1 Înregistrarea unei platforme → clienți și roluri în Keycloak
Section titled “5.1 Înregistrarea unei platforme → clienți și roluri în Keycloak”sequenceDiagram actor A as Administrator de platformă participant W as gsso-web participant G as gsso-gateway participant S as gsso participant DB as BD gsso participant R as ReconcilerWorker participant K as Keycloak A->>W: Creează platforma "crm" + clienți + roluri W->>G: POST /api/v1/admin/platforme (Idempotency-Key) G->>S: releu (token-ul utilizatorului) S->>DB: tx: Platforma, ClientAplicatie*, RolPlatforma*, JobSincronizare*, EvenimentGsso S-->>W: 201 (stareSync=PENDING) R->>DB: preia joburile (SKIP LOCKED, lock pe realm) R->>K: GET client după clientId → absent → POST client (gsso.managed=true) R->>K: POST roluri, compozite, mapper de audiență R->>DB: job OK, kcId stocat, stareSync=IN_SYNC, eveniment SYNC_OK W->>G: interogare / reîmprospătare → insigna „sincronizat”5.2 Cerere de atribuire → aprobare → token
Section titled “5.2 Cerere de atribuire → aprobare → token”sequenceDiagram actor Req as Solicitant actor Own as Proprietar de platformă actor Ap2 as Aprobator (sensibil) participant S as gsso participant K as Keycloak participant N as GNotify Req->>S: POST /admin/atribuiri {sub, CRM_ADMIN, motiv} S->>S: SOLICITATA (+eveniment) S->>N: notifică proprietarul Own->>S: aprobă (nivelul 1) alt rol sensibil Ap2->>S: aprobă (nivelul 2, ≠ solicitant, ≠ aprobatorul-proprietar) end S->>S: APROBATA + Job MAP S->>K: adăugare role-mapping (reconciliator) K-->>S: 204 S->>S: ACTIVA (+eveniment, gsso.grant.v1) Note over K: următorul token al utilizatorului conține CRM_ADMIN în roles5.3 Revocarea în 60 s
Section titled “5.3 Revocarea în 60 s”sequenceDiagram actor O as Proprietar participant S as gsso participant K as Keycloak participant Kf as Kafka participant App as Aplicație (starter) O->>S: revocă atribuirea (motiv) S->>K: ștergere role-mapping S->>K: POST /users/{id}/logout (sesiuni + back-channel logout) S->>Kf: gsso.access-revoked.v1 {sub, notBefore=now} Kf->>App: deny-list pentru sub până la expirarea TTL-ului token-ului App-->>App: cereri cu iat < notBefore → 401 S->>S: REVOCATA (+eveniment → GLog)5.4 Eveniment de autentificare → tablou de bord și GLog
Section titled “5.4 Eveniment de autentificare → tablou de bord și GLog”sequenceDiagram participant U as Utilizator participant K as Keycloak (+gsso-kafka) participant Kf as Kafka participant S as gsso participant L as GLog U->>K: autentificare (parolă + OTP) K-->>U: token-uri K--)Kf: eveniment LOGIN (asincron) Kf->>S: consum (deduplicare după eventId) S->>S: EvenimentGsso (lanț de hash-uri), projection.lastLogin, agregate S->>L: POST /api/v1/app/audit-events (client credentials) L-->>S: id de confirmare5.5 Reconcilierea completă și drift-ul
Section titled “5.5 Reconcilierea completă și drift-ul”- La fiecare 15 min sau la cerere,
RealmDifferîncarcă starea dorită pentru realm și citește Keycloak (clienți, roluri, compozite, mapările rolurilor gestionate, grupuri, fluxuri și câmpurile de politică pe care le gestionează). - Pentru fiecare diferență creează un
JobSincronizare(DIFF):- lipsește în Keycloak →
CREATE(când politica esteENFORCE) sauDRIFT; - diferit →
UPDATEsauDRIFT; - prezent în Keycloak cu
gsso.managed=true, dar absent în GSSO →DELETEsauDRIFT; - prezent fără marcaj →
NEGUVERNAT(doar raportare).
- lipsește în Keycloak →
- În consolă, un administrator poate reîncerca, impune (aplică valoarea din GSSO) sau accepta drift-ul (copiază valoarea din Keycloak în GSSO).
5.6 Adoptarea unui realm existent (de ex. interdictii)
Section titled “5.6 Adoptarea unui realm existent (de ex. interdictii)”Mai întâi se face o rulare de probă (GSSO-FR-080), apoi importul:
- clienții sunt grupați în platforme pe baza unui fișier de mapare (
clientId→ codul platformei); - rolurile realm-ului sunt mapate la roluri de platformă prin reguli de redenumire (de exemplu
ROLE_ADMIN→ candidați<APP>_ADMINper platformă, marcați pentru revizuire); - mapările curente utilizator→rol devin
AtribuireAcces(ACTIVA, sursa=ADOPTAT).
Nimic nu se scrie în Keycloak cât timp politica de drift este IGNORE.
5.7 Autentificarea în consolă (BFF)
Section titled “5.7 Autentificarea în consolă (BFF)”- Browserul deschide
gsso.gstack…, iargsso-gatewayîl redirecționează către Keycloak (realmgstack, clientgsso-console, PKCE + confidențial). - Utilizatorul se autentifică. MFA este obligatorie pentru orice rol
GSSO_*(NFR-SEC-008). - Gateway-ul stochează token-urile în sesiunea de pe server și setează cookie-ul
SESSION(HttpOnly,Secure,SameSite=Lax) plus cookie-ul CSRF. - Apelurile SPA poartă cookie-ul. Gateway-ul transmite access token-ul către
gsso, care aplică delimitarea pe realm și pe platformă pe baza rolurilorGSSO_*și a atributelor acestora.
5.8 Autentificarea cetățeanului prin MPass
Section titled “5.8 Autentificarea cetățeanului prin MPass”- Un client
cetateanredirecționează cetățeanul către Keycloak, care intermediază (broker) către MPass (SAML POST). - Aserțiunea revine. Fluxul first-broker-login caută utilizatorul după atributul IDNP; dacă îl găsește, leagă contul, altfel creează utilizatorul cu atributele mapate.
- Keycloak setează valoarea
acrpe baza nivelului de asigurare MPass, iar token-ul este emis pentru portal.
6. Configurația de bază a realm-ului (keycloak/realms/gstack.json, rezumat)
Section titled “6. Configurația de bază a realm-ului (keycloak/realms/gstack.json, rezumat)”| Setare | Valoare |
|---|---|
| Temă de autentificare / cont / e-mail | gstack (GDS), limbi ro, ru, en, implicit ro |
| Protecție brute force | activă, 5 eșecuri, increment de așteptare 60 s, maxim 15 min |
| Politica de parole | length(12) and upperCase(1) and lowerCase(1) and digits(1) and notUsername and notEmail and passwordHistory(5) |
| Sesiune SSO inactivă / maximă | 30 min / 10 h |
| Access token | 5 min |
| Evenimente | evenimente de utilizator + de administrare activate, evenimente de administrare cu reprezentare, listener-e jboss-logging, gsso-kafka, expirare 7 zile |
| Client scopes (implicite) | profile, email, gsso-roles (roluri plate), gsso-org (org_unit, org_unit_path, roles_scoped), gsso-locale, acr |
| Client scopes (opționale) | idnp, gsso-roles-filtered, offline_access |
| Fluxul browser | Cookie (alt) → Identity provider redirector (alt) → Formulare: username+parolă (req) → OTP/WebAuthn condiționat (condiție: utilizatorul are rolul GSSO_MFA_REQUIRED sau orice rol marcat sensibil) |
| Roluri implicite | ROLE_USER |
| Clienți de bază | gsso-console (confidențial, standard flow, PKCE), gsso-api (bearer), gsso-reconciler se află în master |
| Acțiuni obligatorii | verificarea e-mailului, actualizarea parolei, configurarea OTP, înregistrarea WebAuthn, termeni (dezactivat) |
| Token exchange | token exchange standard V2 activat; permisiuni per client din GSSO |
cetatean.json folosește aceeași temă și setări diferite:
- un identity provider SAML MPass cu un flux first-broker-login care face potrivirea după IDNP;
- fără LDAP;
- autentificarea cu parolă dezactivată implicit;
- sesiune inactivă 15 min.
tenant-template.json este o copie parametrizată a gstack, fără federare.
7. Modelul de securitate
Section titled “7. Modelul de securitate”| Aspect | Măsură |
|---|---|
| Accesul la consolă | BFF; roluri GSSO_*; MFA obligatorie; inactivitate 15 min; CSRF; CSP |
| Delimitarea pe realm | GSSO_REALM_ADMIN poartă atributul gsso.realm; filtru pe server la fiecare interogare și comandă; testat prin matricea de autorizare |
| Delimitarea pe platformă | GSSO_PLATFORM_OWNER cu atributul gsso.platforma (multi-valoare) |
| Reconciliatorul | Service account în master doar cu rolurile manage-*/view-* ale realm-urilor gestionate (fine-grained admin permissions V2); credențiale în depozitul de secrete; rotite la fiecare 90 de zile |
| Principiul „patru ochi” | ApprovalPolicy: solicitant ≠ aprobator; pentru rolurile sensibile doi aprobatori distincți; rolurile GSSO sunt ele însele sensibile |
| Secrete | Secretele clienților sunt generate de Keycloak, afișate o singură dată în consolă și nu sunt persistate în BD GSSO |
| Date cu caracter personal | IDNP criptat (AES-GCM, cheie din depozitul de secrete) și mascat; jurnale curățate |
| Integritatea evenimentelor | Lanț de hash-uri + trigger în BD + copie WORM în GLog |
| Chei | Chei de realm RS256, rotație la 90 de zile cu suprapunere (cheia nouă activă, cea veche pasivă până trece TTL-ul maxim al token-ului) |
| Lanțul de aprovizionare | SBOM (CycloneDX), Trivy, Semgrep, Gitleaks prin /gsast; imaginea Keycloak construită dintr-un digest fixat |
Rolurile consolei GSSO (realm gstack):
| Rol | Sensibil |
|---|---|
GSSO_ADMIN | da |
GSSO_REALM_ADMIN | da |
GSSO_PLATFORM_OWNER | da |
GSSO_APPROVER | da |
GSSO_HELPDESK | da |
GSSO_AUDITOR | nu |
GSSO_IDNP_VIEW | da |
GSSO_MFA_REQUIRED | marcaj |
8. Implementare
Section titled “8. Implementare”8.1 Gazda demo (convenția gStack actuală)
Section titled “8.1 Gazda demo (convenția gStack actuală)”- Stiva compose
~/devops/gsso/pe gazda partajată. Containerele se alătură rețelei externegstack-web. - Containerele active
keycloak+postgres-keycloaksunt preluate (§11.1): imaginea standard este înlocuită cu imaginea GSSO, construită pe aceeași versiune, cu extensii și temă adăugate. gsso,gsso-gateway,gsso-web,gsso-postgresși, dacă nu este disponibil un Kafka partajat, un Kafka cu un singur nod (KRaft).- vhost-uri:
sso.gstack.esempla.systems→ keycloak:8080, ca în prezent;- nou
gsso.gstack.esempla.systems→ gsso-web + gateway. Orice modificare a nginx-ului de margine necesită aprobarea proprietarului, iar reînnoirea certificatului trebuie reparată mai întâi (NFR-AVL-006).
- Fluxul de implementare: construirea imaginilor amd64 → push în
registry.esempla.systems/govtech/gstack/gsso-*(saudocker save | ssh | docker load) →docker compose up -d --no-deps --force-recreate <svc>. - Bugetul de memorie pe gazda de ~8 GB:
- Keycloak heap de 1 GB;
- gsso 512 MB;
- gateway 384 MB;
- postgres ×2 câte 256 MB fiecare;
- Kafka 512 MB, dacă este local.
8.2 Ținta Kubernetes (Helm)
Section titled “8.2 Ținta Kubernetes (Helm)”- Keycloak: 2 replici (cluster Infinispan prin DNS_PING Kubernetes), cu PDB și HPA pe CPU.
- gsso: 2 replici. Reconciliatorul este singleton per realm prin advisory lock, astfel încât ambele replici pot rula.
- gateway: 2 replici, sesiuni în Redis sau JDBC.
- PostgreSQL: CloudNativePG, câte 2 instanțe fiecare.
- Kafka: clusterul Strimzi partajat.
9. Dimensionare (inițială)
Section titled “9. Dimensionare (inițială)”| Element | Estimare |
|---|---|
| Utilizatori angajați | 5 000 (inițial) → 20 000 |
| Vârf de autentificări | 50/min tipic, rafală de 10/s la ora 9:00 |
| Evenimente/zi | ≈ 50 000 (autentificări, reîmprospătarea token-urilor nu este jurnalizată implicit, administrare) → ≈ 30 MB/zi jsonb → partiții pe 90 de zile ≈ 3 GB |
| BD GSSO | < 10 GB în primul an |
| BD Keycloak | < 5 GB (sesiuni în memorie, funcția de sesiuni persistente de utilizator activată în 26.x → +1 GB) |
10. Observabilitate
Section titled “10. Observabilitate”- Metrici (Micrometer → Prometheus):
gsso_sync_jobs{state},gsso_reconcile_seconds,gsso_drift_total,gsso_event_lag_seconds,gsso_glog_lag_seconds;- Keycloak
keycloak_logins_total,keycloak_failed_login_attempts_total(metrics SPI); - metrici JVM și HTTP.
- Jurnale: JSON cu trace id; filtru de curățare pentru
Authorization,access_token,client_secret,password,idnp. - Tracing: OpenTelemetry pe traseul gateway → gsso → apelurile admin către Keycloak.
- Alerte: NFR-OBS-004, rutate prin GNotify.
11. Runbook de operare (schiță)
Section titled “11. Runbook de operare (schiță)”11.1 Preluarea Keycloak-ului activ
Section titled “11.1 Preluarea Keycloak-ului activ”- Obțineți aprobarea proprietarului și conveniți o fereastră. Reparați mai întâi reînnoirea TLS.
- Faceți
pg_dumpal bazei de date Keycloak și copiați-l în afara gazdei. Exportați fiecare realm (kc.sh export --realm … --users different_files) ca referință. - Construiți imaginea Keycloak GSSO pe aceeași versiune (26.6.3), cu extensii și temă adăugate. Încă nu se aplică nicio configurație de bază.
- Înlocuiți imaginea și verificați:
- autentificările pentru toate aplicațiile;
- issuer-ul este neschimbat;
- JWKS este neschimbat. Rollback = imaginea anterioară, aceeași bază de date.
- Activați listener-ul
gsso-kafkaîn realm-ulinterdictii(acțiune de administrare), apoi pornițigssocu realm-ulinterdictiiadoptat,IGNORE. - Aplicați configurațiile de bază
gstackșicetatean(realm-uri noi; nimic existent nu se modifică).
11.2 Alte runbook-uri
Section titled “11.2 Alte runbook-uri”| Runbook | Pași |
|---|---|
| Actualizarea Keycloak | Copie de rezervă a bazei de date → rularea suitei IT pentru configurația de bază + reconciliator pe imaginea nouă → lansare etapizată → smoke test |
| Rotația cheilor | Adăugați o cheie RS256 nouă (prioritate mai mare) → așteptați cel puțin 1 TTL de token + refresh → setați cheia veche ca pasivă → eliminați-o după durata maximă a sesiunii |
| Rotația secretului de client | „Rotire” în consolă → fereastră de grație cu secret dublu → reimplementarea aplicației → secretul vechi invalidat |
| Acces de urgență (break-glass) | Folosiți administratorul de urgență din master (credențiale sigilate, regula celor două persoane); fiecare utilizare este raportată |
| Restaurare | Restaurați baza de date Keycloak din copia de rezervă → rulați o reconciliere completă în REPORT → analizați drift-ul → ENFORCE |
| Certificat | Reînnoire prin webroot; alertă cu 21 de zile înainte; job lunar de verificare |
12. Strategia de testare
Section titled “12. Strategia de testare”| Nivel | Domeniu | Instrumente |
|---|---|---|
| Unitar | Mașina de stări a atribuirilor, politica de aprobare, differ-ul, lanțul de hash-uri, mapper-ele, maparea din starter | JUnit 5, AssertJ |
| Integrare | Reconciliatorul pe Keycloak real, listener de evenimente → Kafka → consumator, Liquibase + trigger append-only | Testcontainers (Keycloak 26.6.x cu extensii, PostgreSQL, Kafka) și deploy/docker-compose.test.yml (întotdeauna down -v) |
| Contract | OpenAPI api/v1/app, scheme de evenimente (CloudEvents + JSON Schema) | api_audit.py, teste de schemă |
| E2E | Fluxurile consolei (înregistrarea platformei, utilizator, aprobarea atribuirii, revocare, drift), SSO între două aplicații-exemplu, mock MPass | Cypress |
| Securitate | Matricea de autorizare (delimitare pe realm/platformă, principiul „patru ochi”), ZAP baseline, antete, SAST/SCA/secrete | /gtestgen, /gtest, /gsast |
| Performanță | Rafală de autentificări, liste din consolă, reconcilierea a 1 000 de clienți | /load-test, k6 pentru Keycloak |
| Verificare UI | Controale nefuncționale, chei netraduse, accesibilitate (a11y) | /gfront |
Scenariile de testare sunt listate în test-scenarios.md (TS-GSSO-NN) și reutilizează cazurile comune TC-COM-*.
13. Estimarea costurilor
Section titled “13. Estimarea costurilor”| Element | Estimare |
|---|---|
| Gazda demo | Încape pe gazda existentă (≈ 3 GB RAM suplimentar) |
| Ținta Kubernetes | 3 vCPU / 6 GB requests (Keycloak 2×, gsso 2×, gateway 2×) + 2 clustere PostgreSQL |
| Efortul de construire (S0–S3) | ≈ 14–18 persoane-săptămâni (1 backend, 1 frontend, 0,5 Keycloak/DevOps) |
| Migrarea aplicațiilor existente (S4) | ≈ 1–2 persoane-săptămâni per aplicație de tip A, ≈ 0,5 per aplicație de tip B |