Bezpieczeństwo i RBAC
RBAC i uprawnienia
Autoryzacja na platformie DataFlow AI jest regulowana przez hierarchiczny model kontroli dostępu opartej na rolach (RBAC). Haczyk: istnieją trzy różne słowniki ról — role realmu Keycloak, hierarchia backendowa DataFlowRole oraz persony frontendu — które muszą być pogodzone przez zakodowane na sztywno tabele mapowania. Ta strona dokumentuje wszystkie trzy, pełne macierze uprawnień, sposób działania egzekwowania oraz znane luki.
Trzy słowniki ról
Pojedynczy człowiek-użytkownik jest opisywany trzema różnymi nazwami ról w zależności od tego, na którą warstwę patrzysz. Zrozumienie mapowania między nimi jest niezbędne do rozumowania o dostępie.
| Warstwa | Słownik | Źródło |
|---|---|---|
| Dostawca tożsamości | Role realmu Keycloak | realm-export.json |
| Usługi backendowe | Hierarchia DataFlowRole | RBACService.kt (moduł common) |
| SPA frontendu | Persony (PersonaId) | frontend/src/types/permissions.ts |
1. Role realmu Keycloak
Realm dataflow dostarcza sześć ról realmu: org_admin, workspace_admin, developer, analyst, operator oraz viewer. org_admin jest rolą złożoną, która obejmuje pozostałych pięć.
2. Hierarchia backendowa DataFlowRole
RBACService.DataFlowRole definiuje pięć uporządkowanych ról, każdą z numerycznym poziomem:
ADMIN(100) > ENGINEER(75) > ANALYST(50) > STEWARD(40) > VIEWER(25)
Rola przyznaje każde uprawnienie, którego requiredRole.level jest mniejszy lub równy poziomowi roli użytkownika (RBACService.hasPermission).
3. Persony frontendu
SPA modeluje cztery persony (PersonaId): admin, engineer, analyst oraz steward. Każda persona mapuje się na stały zestaw uprawnień oraz listę dozwolonych prefiksów tras.
Słowniki nie pasują do siebie
Keycloak dostarcza developer, operator oraz org_admin — nie ma roli realmu STEWARD ani roli realmu ENGINEER. Backend i frontend natomiast oczekują engineer oraz steward. „Steward" w Keycloak może pojawić się tylko poprzez grupę AD (PLK-BI-Stewards) lub nazwę roli data_steward, z których żadna nie znajduje się w dostarczonym eksporcie realmu. Zaszczepiony przykładowy użytkownik „Tomasz Zielinski / Data Steward" faktycznie nosi rolę realmu viewer.
Tabele mapowania
Grupy Keycloak → role realmu
Eksport realmu mapuje cztery grupy w stylu korporacyjnym na role realmu:
| Grupa | Przyznawana rola realmu |
|---|---|
/PLK-BI-Admins | org_admin |
/PLK-BI-Engineers | developer |
/PLK-BI-Analysts | analyst |
/PLK-BI-Operations | operator |
KeycloakJwtConverter oraz RBACService dodatkowo wiedzą o PLK-BI-Stewards i PLK-BI-Viewers, ale te grupy nie występują w dostarczonym eksporcie realmu.
Zaszczepieni użytkownicy
| Nazwa użytkownika | Rola realmu | Grupa | Atrybut stanowiska |
|---|---|---|---|
| anna.kowalska@polkomtel.pl | developer | PLK-BI-Engineers | Data Engineer |
| marek.nowak@polkomtel.pl | analyst | PLK-BI-Analysts | Business Analyst |
| katarzyna.wisniewski@polkomtel.pl | org_admin | PLK-BI-Admins | Platform Admin |
| tomasz.zielinski@polkomtel.pl | viewer | (brak) | Data Steward |
Wszyscy czterej zaszczepieni użytkownicy mają puste credentials oraz requiredActions: [UPDATE_PASSWORD].
Dowolna surowa rola → DataFlowRole
Brama mapuje każdy surowy ciąg roli, który zobaczy — role realmu, role klienta, nazwy grup oraz ścieżki grup — na pojedynczy DataFlowRole (RBACService.mapSingleRole / KeycloakJwtConverter). Wygrywa najwyższa zmapowana rola; wartością domyślną jest VIEWER.
| Surowa rola / grupa | Rozwiązany DataFlowRole |
|---|---|
PLK-BI-Admins, /PLK-BI-Admins | ADMIN |
admin, dataflow-admin, org_admin, workspace_admin, platform_admin | ADMIN |
PLK-BI-Engineers | ENGINEER |
engineer, dataflow-engineer, data_engineer, developer, operator | ENGINEER |
PLK-BI-Analysts | ANALYST |
analyst, dataflow-analyst, business_analyst | ANALYST |
PLK-BI-Stewards | STEWARD |
steward, dataflow-steward, data_steward | STEWARD |
PLK-BI-Viewers | VIEWER |
viewer, dataflow-viewer | VIEWER |
Nazwy z prefiksem ROLE_* | To samo mapowanie po usunięciu prefiksu |
| Nierozpoznana rola | Pomijana — brak niejawnego przyznania (FR-020) |
KeycloakJwtConverter.extractAuthorities konwertuje rozwiązaną rolę na uprawnienia Spring ROLE_*. Jeśli JWT nie ma żadnych mapowalnych ról, zestaw uprawnień jest pusty, a żądanie jest odrzucane przez @PreAuthorize — to celowy wybór przeciwdziałający eskalacji uprawnień. Mapowania org_admin / developer / operator zostały dodane późno, aby naprawić sytuację użytkowników, którzy w przeciwnym razie byliby po cichu degradowani do ANALYST lub VIEWER.
Dlaczego wartości domyślne mapowania mają znaczenie
Reguły „najwyższa wygrywa, domyślnie VIEWER, nierozpoznane pomijane" oznaczają, że nieznany ciąg roli nigdy nie eskaluje uprawnień — ale błędnie zapisana oczekiwana rola po cichu degraduje użytkownika. Tabele mapowania są jedynym kruchym punktem godzącym wszystkie trzy słowniki.
Backendowa macierz uprawnień
RBACService definiuje katalog 30 uprawnień, każde oznaczone requiredRole. Ponieważ model jest hierarchiczny, rola otrzymuje uprawnienie, gdy jej poziom jest ≥ poziomu wymaganej roli uprawnienia.
Uprawnienia według domeny
| Domena | Uprawnienie → wymagana rola |
|---|---|
| Pipeline | VIEW_PIPELINE→VIEWER; CREATE/EDIT/RUN/SCHEDULE_PIPELINE→ENGINEER; DELETE_PIPELINE→ADMIN |
| Connection | VIEW_CONNECTION→VIEWER; CREATE/EDIT/TEST_CONNECTION→ENGINEER; DELETE_CONNECTION→ADMIN |
| Monitoring | VIEW_MONITOR→VIEWER; ACKNOWLEDGE_ALERT→ANALYST; CONFIGURE_ALERT→ENGINEER; DELETE_ALERT→ADMIN |
| Lineage | VIEW_LINEAGE→VIEWER; EDIT_LINEAGE→ENGINEER |
| Migration | VIEW_MIGRATION→VIEWER; CREATE_MIGRATION→ENGINEER; EXECUTE_MIGRATION→ADMIN |
| AI Copilot | USE_COPILOT→ANALYST; CONFIGURE_COPILOT→ADMIN |
| Workspace | VIEW_WORKSPACE→VIEWER; EDIT_WORKSPACE/MANAGE_MEMBERS→ADMIN |
| Zarządzanie użytkownikami | VIEW_USERS→ANALYST; MANAGE_USERS→ADMIN |
| Audyt | VIEW_AUDIT_LOG→ANALYST; EXPORT_AUDIT_LOG→ADMIN |
| System | VIEW_SYSTEM_SETTINGS/MODIFY_SYSTEM_SETTINGS→ADMIN |
Role × uprawnienia (hierarchicznie)
✔ = przyznane. Poziomy: ADMIN 100, ENGINEER 75, ANALYST 50, STEWARD 40, VIEWER 25.
| Poziom uprawnień (wymagana rola) | ADMIN | ENGINEER | ANALYST | STEWARD | VIEWER |
|---|---|---|---|---|---|
VIEW_PIPELINE / VIEW_CONNECTION / VIEW_MONITOR / VIEW_LINEAGE / VIEW_MIGRATION / VIEW_WORKSPACE (VIEWER) | ✔ | ✔ | ✔ | ✔ | ✔ |
ACKNOWLEDGE_ALERT / USE_COPILOT / VIEW_USERS / VIEW_AUDIT_LOG (ANALYST) | ✔ | ✔ | ✔ | – | – |
CREATE/EDIT/RUN/SCHEDULE_PIPELINE / CREATE/EDIT/TEST_CONNECTION / CONFIGURE_ALERT / EDIT_LINEAGE / CREATE_MIGRATION (ENGINEER) | ✔ | ✔ | – | – | – |
DELETE_PIPELINE / DELETE_CONNECTION / DELETE_ALERT / EXECUTE_MIGRATION / CONFIGURE_COPILOT / EDIT_WORKSPACE / MANAGE_MEMBERS / MANAGE_USERS / EXPORT_AUDIT_LOG / VIEW_SYSTEM_SETTINGS / MODIFY_SYSTEM_SETTINGS (ADMIN) | ✔ | – | – | – | – |
Inwersja hierarchii STEWARD
STEWARD znajduje się na poziomie 40, poniżej ANALYST na poziomie 50. STEWARD dziedziczy zatem tylko hierarchiczne uprawnienia poziomu VIEWER z RBACService. Wszelkie rzeczywiste uprawnienia stewarda pochodzą wyłącznie z kontrolerów, które wyraźnie wymieniają STEWARD na swoich listach @PreAuthorize — a nie z hierarchii ról. Model person frontendu (poniżej) zamiast tego nadaje stewardowi szerokie prawa zarządzania danymi, więc oba modele naprawdę nie zgadzają się co do tego, jak potężny jest steward.
Kontrole uwzględniające workspace
RBACService udostępnia także kontrole o zakresie workspace nałożone na kontrole uprawnień:
canAccessWorkspace— ADMIN widzi wszystkie workspace; workspacedefaultjest otwarty dla wszystkich; każdy inny workspace wymaga członkostwa.canModifyPipeline,canDeletePipeline,canRunPipeline— każda ocenia odpowiednie uprawnienie oraz kontrolę workspace.
Frontendowa macierz uprawnień
Frontendowy katalog uprawnień (frontend/src/types/permissions.ts) definiuje 28 uprawnień jako ciągi domain:action obejmujące domeny pipeline, quality, governance, lineage, code, admin, system oraz catalog. (Komentarz nagłówkowy pliku mówi „26"; rzeczywista lista to 28.) Uprawnienia są przypisywane per persona poprzez personaPermissions, a model jest opisany jako wspierany po stronie serwera przez PolicyEngine.kt w metadata-service.
Persona × uprawnienia
✔ = przyznane. Persona admin posiada wszystkie 28 uprawnień.
| Uprawnienie | engineer | analyst | admin | steward |
|---|---|---|---|---|
pipeline:view | ✔ | ✔ | ✔ | ✔ |
pipeline:create | ✔ | – | ✔ | – |
pipeline:edit | ✔ | – | ✔ | – |
pipeline:run | ✔ | ✔ | ✔ | – |
pipeline:delete | ✔ | – | ✔ | – |
pipeline:deploy | ✔ | – | ✔ | – |
pipeline:debug | ✔ | – | ✔ | – |
quality:view | ✔ | ✔ | ✔ | ✔ |
quality:create | ✔ | – | ✔ | ✔ |
quality:edit | ✔ | – | ✔ | ✔ |
quality:evaluate | – | ✔ | ✔ | ✔ |
governance:policy | – | – | ✔ | ✔ |
governance:review | – | – | ✔ | ✔ |
governance:approve | – | – | ✔ | ✔ |
lineage:view | ✔ | ✔ | ✔ | ✔ |
lineage:edit | – | – | ✔ | ✔ |
code:view | ✔ | ✔ | ✔ | – |
code:review | ✔ | – | ✔ | – |
code:commit | ✔ | – | ✔ | – |
admin:users | – | – | ✔ | – |
admin:workspace | – | – | ✔ | – |
admin:security | – | – | ✔ | – |
admin:infrastructure | – | – | ✔ | – |
admin:billing | – | – | ✔ | – |
system:settings | – | – | ✔ | – |
catalog:view | ✔ | ✔ | ✔ | ✔ |
catalog:edit | – | – | ✔ | ✔ |
catalog:classify | – | – | ✔ | ✔ |
Zwróć uwagę, jak frontendowa persona steward posiada bogate uprawnienia governance:*, quality:*, lineage:edit oraz catalog:* — dokładnie te uprawnienia, których backendowa hierarchia odmawia STEWARD (poziom 40). Ta rozbieżność jest jedną ze znanych luk.
Jak działa egzekwowanie
Autoryzacja jest egzekwowana w dwóch warstwach: brama sprawdza ważność tokenu i obecność roli; każda usługa stosuje drobnoziarniste kontrole na poziomie metody oraz workspace/własności.
Request ──▶ API Gateway ──▶ Downstream service ──▶ @PreAuthorize ──▶ workspace check
│ │ │
│ token valid? │ JWT re-validated │ method-level
│ role present? │ X-User-* → context │ role/permission
▼ ▼ ▼
coarse HTTP rule SecurityContext fine-grained grant
Reguły na poziomie bramy
Gdy dev-permit-reads=false, reaktywny SecurityConfig bramy stosuje gruboziarniste reguły oparte na metodzie do /api/v1/**:
| Metoda HTTP | Wymagane uprawnienie |
|---|---|
DELETE | ROLE_ADMIN |
POST / PUT / PATCH | ROLE_ADMIN lub ROLE_ENGINEER |
GET | ROLE_ADMIN, ROLE_ENGINEER, ROLE_ANALYST, ROLE_STEWARD lub ROLE_VIEWER |
| Każda inna wymiana | Uwierzytelniony |
Gdy dev-permit-reads=true, wszystkie żądania GET plus POST-y copilot / ai / catalog-ask / search stają się permitAll.
Adnotacja @PreAuthorize na poziomie usługi
Usługi niższego poziomu uruchamiają @EnableMethodSecurity(prePostEnabled = true), więc kontrolery noszą adnotacje @PreAuthorize. Ponieważ KeycloakJwtConverter produkuje rzeczywiste uprawnienia ROLE_*, hasRole / hasAnyRole oceniają autentyczne role Keycloak. Reprezentatywna próbka zaobserwowanych zabezpieczeń:
| Usługa / kontroler | Grupa punktów końcowych | Zabezpieczenie |
|---|---|---|
lineage-service BiLineageController | lineage BI | hasAnyAuthority('ROLE_ADMIN','ROLE_STEWARD') |
lineage-service PropagationController | propagacja | hasRole('ADMIN') |
lineage-service LineageAuthoringController | tworzenie | hasAnyRole('STEWARD','ADMIN') |
monitor-service AdminScheduledReportsController | raporty zaplanowane | hasAnyRole('ADMIN','STEWARD') |
metadata-service WorkspaceController | CRUD workspace | hasRole('ADMIN') (wszystkie metody) |
metadata-service UserController | zarządzanie użytkownikami | hasRole('ADMIN') (wszystkie metody) |
metadata-service AuditLogController | log audytu | hasRole('ADMIN') |
metadata-service ConnectionController | połączenia | odczyt = 5 ról; create/edit/test = ADMIN/ENGINEER; delete = ADMIN |
metadata-service CdrMetricsController | metryki CDR | odczyt = 5 ról; zapis = ADMIN/ENGINEER |
metadata-service PiiClassifierController | klasyfikacja PII | scan = ADMIN/ANALYST/STEWARD/ENGINEER; mutacja = ADMIN/STEWARD |
metadata-service TagController | polityka tagów | hasAnyRole('governance-admin','data-steward','admin') or hasAuthority('SCOPE_governance:policy') |
metadata-service SearchController | wyszukiwanie / reindeksacja | wyszukiwanie = permitAll(); reindeksacja = hasAnyRole('ADMIN','PLATFORM_OPS') |
pipeline-engine ErasureController | usuwanie GDPR | hasAnyRole('ADMIN','STEWARD') |
pipeline-engine QuarantineController | kwarantanna | odczyt = ADMIN/DATA_STEWARD/DATA_ENGINEER; mutacja = ADMIN/DATA_STEWARD; release = ADMIN |
Zabezpieczenia tras frontendu
RBAC frontendu jest tylko UX — SPA jest klientem publicznym, a rzeczywiste egzekwowanie zawsze odbywa się po stronie serwera. Mimo to frontend uniemożliwia użytkownikom nawigację do stron, których nie mogą używać:
ProtectedRoutepokazuje spinner podczasisLoading, przekierowuje do/loginjeśli!isAuthenticated, następnie wywołujecanAccess(effectivePersona, pathname)i renderujeAccessDeniedw przypadku niepowodzenia.effectivePersonato magazyn person w trybie deweloperskim, w przeciwnym razieuser.persona.

- RBAC oparty na prefiksie trasy —
data/permissions.tsdefiniujepersonaRoutes;canAccessdopasowuje dozwolony prefiks dokładnie lub jakoprefix + '/'. Ta mapa jest zablokowana przezpermissions-rbac.test.ts(65 asercji). PermissionGateto zabezpieczenie na poziomie komponentu zbudowane na hookachusePermission/usePermissions/useAnyPermission, obsługujące pojedyncze lub wiele uprawnień zrequireAlloraz opcjonalnymfallback.useAuth().hasRole(role)sprawdzarealmRoles;useAuth().hasPermission(perm)sprawdza pochodzącą z persony tablicępermissions.
Dozwolone prefiksy tras per persona
| Persona | Dozwolone prefiksy tras |
|---|---|
| engineer | /, /design-studio, /monitor, /governance, /migration, /connections, /data-marketplace, /marketplace, /my-pipelines, /pipelines, /data-browser, /templates, /admin/incidents, /telecom |
| analyst | /, /my-pipelines, /data-browser, /data-marketplace, /marketplace, /monitor, /governance/quality, /governance/lineage |
| admin | /, /design-studio, /monitor, /governance, /migration, /admin, /connections, /my-pipelines, /pipelines, /data-browser, /templates, /data-marketplace, /marketplace, /telecom |
| steward | /, /monitor, /governance, /data-browser, /data-marketplace, /marketplace, /admin/audit-log, /admin/access-reviews, /admin/incidents |
Znane ryzyka i luki
Badanie ujawniło kilka problemów z poprawnością autoryzacji wartych śledzenia.
Niedopasowane role @PreAuthorize
Kilka kontrolerów zabezpiecza punkty końcowe nazwami ról, których rzeczywisty token Keycloak nigdy nie może nosić. KeycloakJwtConverter emituje wyłącznie pięć kanonicznych uprawnień ROLE_ADMIN, ROLE_ENGINEER, ROLE_ANALYST, ROLE_STEWARD oraz ROLE_VIEWER. Zabezpieczenia takie jak:
hasRole('DATA_STEWARD')orazhasRole('DATA_ENGINEER')—QuarantineControllerhasRole('PLATFORM_OPS')— reindeksacjaSearchControllerhasAnyRole('governance-admin','data-steward')—TagController
...nigdy nie dopasują się do autentycznego użytkownika. Te punkty końcowe są faktycznie niedostępne dla rzeczywistych użytkowników — stają się osiągalne tylko w trybie dev-permit-reads, gdzie anonimowemu użytkownikowi przyznawany jest szeroki zestaw ról, który akurat obejmuje ROLE_DATA_STEWARD / ROLE_DATA_ENGINEER. To rzeczywista wada poprawności autoryzacji.
Inwersja hierarchii STEWARD
Jak zauważono powyżej, STEWARD (poziom 40) plasuje się poniżej ANALYST (poziom 50) w hierarchii backendu, więc STEWARD dziedziczy tylko uprawnienia poziomu VIEWER z RBACService — podczas gdy model person frontendu nadaje stewardowi szerokie prawa zarządzania, jakości, lineage oraz katalogu. Oba modele nie zgadzają się co do tego, jak potężny jest steward, a uprawnienia STEWARD w backendzie zależą całkowicie od jawnych list @PreAuthorize, a nie od hierarchii.
Furtka dev-permit-reads
dataflow.gateway.dev-permit-reads (domyślnie false) to potężny przełącznik. Gdy true, dopuszcza wszystkie żądania GET bez uwierzytelnienia i przyznaje anonimowemu użytkownikowi niższego poziomu szeroki zestaw ról (ROLE_ADMIN, ROLE_DPO, ROLE_COMPLIANCE_OFFICER, ROLE_AUDITOR, ROLE_STEWARD, ROLE_OPS, ROLE_ENGINEER, ROLE_USER, ROLE_DATA_ENGINEER, ROLE_DATA_STEWARD). W produkcji musi być false, a nie znaleziono żadnego zabezpieczenia środowiskowego, które by to egzekwowało.
Inne obserwacje
- Fragmentacja słownika ról — trzy systemy ról godzone wyłącznie przez zakodowane na sztywno tabele mapowania w
RBACService,KeycloakJwtConverterorazkeycloak.ts. Mapowaniaorg_admin/developerbyły późną poprawką błędu. - Rozbieżność dokumentacji — przewodnik administratora opisuje rolę
MANAGERoraz klientadataflow-ui, które nie istnieją ani w kodzie, ani w eksporcie realmu.
Skutek netto dla operatorów
Podczas audytowania dostępu nigdy nie zakładaj, że trzy modele ról się zgadzają. Weryfikuj względem rzeczywistej hierarchii RBACService oraz tabeli mapowania KeycloakJwtConverter — i potwierdzaj, że dev-permit-reads ma wartość false w każdym wdrożeniu produkcyjnym.
Podsumowanie
| Temat | Kluczowy fakt |
|---|---|
| Słowniki | Role realmu Keycloak, backendowa DataFlowRole, persony frontendu — godzone przez tabele mapowania |
| Hierarchia backendu | ADMIN(100) > ENGINEER(75) > ANALYST(50) > STEWARD(40) > VIEWER(25) |
| Uprawnienia backendu | 30 uprawnień, przyznawanych gdy poziom roli ≥ poziom wymaganej roli |
| Uprawnienia frontendu | 28 uprawnień domain:action przypisywanych per persona |
| Egzekwowanie | Gruboziarniste reguły HTTP bramy + @PreAuthorize usługi + kontrole workspace |
| RBAC frontendu | Zabezpieczenia tras tylko UX i PermissionGate — rzeczywiste egzekwowanie jest po stronie serwera |
| Najważniejsze ryzyka | Niedopasowane role @PreAuthorize, inwersja STEWARD, furtka dev-permit-reads |
Aby poznać stronę uwierzytelniania — jak tożsamość jest ustanawiana, zanim uruchomi się którakolwiek z tych kontroli — zobacz Uwierzytelnianie i SSO.