TR 03187-Conformance Statement
CIVITAS/CORE aims to conform to Level 1 of BSI TR-03187, a German security recommendation for Urban Data Platforms. In the context of BSI TR-03187, CIVITAS/CORE implements requirements that pertain to "Entwickler" (Software Developers) and "Lösungsanbieter" (Integrators). Requirements that pertain to "Betreiber" (Operators) are out of scope.
The following sections detail how the pertinent requirements of BSI TR-03187 are fulfilled in CIVITAS/CORE.
Scope note on 3rd party components: The conformance assessment currently covers components developed by the CIVITAS/CORE project. Verification of 3rd party components (e.g. upstream container images, external libraries) is out of scope for the time being.
State covered: This statement reflects the current development state of CIVITAS/CORE — the staging branch of the deployment repository and the develop branch of the platform repository.
| Requirement | Status | Description |
|---|---|---|
| AR-1 Geringstmögliche Privilegien | Done | Least privilege enforced at multiple layers: OPA default allow := false with explicit permission grants only. Containers run as non-root (UID 1000/1001) with drop: [ALL] capabilities, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false. Dedicated Kubernetes ServiceAccounts per deployment. Spring Security anyRequest().authenticated() catch-all. Mandated through Security Architecture Principles. |
| AR-2 Legacy-Clienttechnologien vermeiden | Done | For components developed by CIVITAS/CORE, ESLint rules block legacy HTML elements (<object>, <embed>, <applet>) at error level in the CI pipeline (see ESLint config and implementation ticket). |
| AR-3 Nicht verwendete Abhängigkeiten entfernen | In Progress | Unused-dependency detection for JVM modules runs in CI via mvn dependency:analyze -DfailOnWarning=true across the portal backend, portal-model, config-adapter, and AuthZ pipelines, each with a curated exclusion list for dependencies the analyzer cannot resolve through indirection. SSDLC policy (Section 6.6) and the Deployment Checklist mandate reasonable effort toward minimizing shipped artifacts. Gaps: the config-adapter ships as a single container image bundling every adapter module, so unused adapter code cannot be pruned per-deployment (platform#1870), and the frontend has no equivalent unused-package-dependency check (platform#1875). |
| AR-4 Version Pinning | Done | All dependencies and container images are pinned to specific versions, ensured through the Deployment Standards (section "Version Management"), the Frontend Style Guide (section "Imports / Exports"), and the Backend Style Guide (section "Imports"). External Helm chart versions are pinned in components/*/charts.yaml and container image tags in components/*/images.yaml; Java dependencies are pinned in pom.xml, frontend dependencies via pnpm-lock.yaml, and Dockerfiles are version-tagged (portal-backend and authz-repo additionally pin their base image by SHA256 digest). Implementation ticket: Pin Helm image tags to release versions. Caveat: images are pinned by mutable tag rather than immutable digest, and the authz deployments use pullPolicy: Always, so a re-pushed tag could change the running image (deployment#278). |
| AR-5 Sitzungs-IDs zufällig und eindeutig | Done | All JPA entities use @GeneratedValue(strategy = GenerationType.UUID) (Level 4 random UUIDs). Frontend session IDs (UML modeler, pipeline editor) use crypto.randomUUID(). Backend is stateless (SessionCreationPolicy.STATELESS), no server-side session IDs. Auth sessions delegated to Keycloak. |
| AR-6 Sitzungsablauf nach Inaktivität | Done | Keycloak SSO Session Idle is set to 60 minutes. A frontend inactivity detector stops background token refresh and triggers logout after a period of no user interaction, so the Keycloak idle timeout takes effect. Implementation ticket: Add frontend inactivity detector to enforce session timeout. |
| AR-7 Rollenbasierte Benutzerverwaltung | Done | Role-based user management is implemented. Users are assigned role "Standard User" on registration. For details, see Authorization Data Model. |
| AR-8 Replay-Schutz | In Progress | User authentication is performed system-wide by OpenID Connect with signed JWT tokens including timestamps. Kafka messages use CloudEvents with unique UUIDs and timestamps per message. Portal-backend has enable.idempotence: true (exactly-once per partition). The config-adapter saga engine deduplicates per dataset (existsForDataset() check), and mTLS via Linkerd provides transport-layer replay protection. Gap: deduplication is missing on the non-Flowable config-adapter adapter paths (platform#1658). |
| AR-9 Geheimnisse müssen änderbar sein | Done | As per SSDLC (section 9) and Deployment Standards (Section "Security"), secrets are stored through Kubernetes secrets or other secure means external to the application, in a changable manner. Exception: Keycloak stores secrets (passwords, signing keys) in database; all of them are changable through regular Keycloak mechanisms. |
| AR-10 Geheimnisse von Benutzern dürfen nicht zur Sicherstellung von Vertraulichkeit verwendet werden | Done | User credentials are managed exclusively by Keycloak and never used for data confidentiality. All confidentiality mechanisms (TLS, K8s secrets) use system-managed credentials. Architectural separation: Keycloak handles user secrets, everything else uses infrastructure-level secrets. The requirement is also part of the Security Architecture Principles. |
| AR-11 Kryptografische Verfahren sollen TR-2101-1 entsprechen | Done | Production code uses BSI-approved algorithms: AES-256-GCM for credential encryption (CryptoUtils.java), PBKDF2-HMAC-SHA256 with 600k iterations for key derivation (CryptoKeyLoader.java), HKDF-SHA256 for per-credential key isolation, RS256 and ES256 for JWT/WebAuthn signatures (Keycloak realm config). No weak ciphers (DES/3DES/RC4/Blowfish) in production code. Requirement to use BSI-approved cryptography is also part of Backend Code Style Guide and Deployment Standards. |
| AR-12 Standardframeworks für sicherheitskritische Funktionen | Done | Standard frameworks used for all security-critical functions: Spring Security (backend auth/authz), Keycloak (identity management), NextAuth (frontend session management), Jackson (deserialization), OPA (policy enforcement), Linkerd (mTLS). No custom cryptography or authentication implementations. Ensured through inclusion in Security Architecture Principles document. |
| AR-13 Ganze Zertifikatkette validieren | Done | Encryption between container instances is enforced through mandatory mTLS via the Linkerd service mesh, with defaultInboundPolicy: cluster-authenticated set cluster-wide (defaults/environment/global.yaml); the APISIX ingress edge is explicitly scoped to require an authenticated mesh identity by default. A Kyverno policy additionally flags any meshed namespace that omits an inbound policy; running that policy in Enforce rather than Audit mode is the operator's responsibility. |
| AR-14 Alle vorgesehenen Sicherheitsmechanismen defaultmäßig anschalten | In Progress | Security mechanisms enabled by default: the frontend sets a nonce-based CSP, X-Content-Type-Options, X-Frame-Options, and Referrer-Policy via Next.js middleware; Keycloak has brute-force protection (10-attempt lockout) in production; Kyverno pod-security policies enforce the hardening baseline (running them in Enforce rather than Audit mode is the operator's responsibility). APISIX strips inbound authorization headers (X-Userinfo, X-Access-Token, X-Allowed-Scope-Ids) before upstream delivery via a serverless-pre-function on the portal, frost, and keycloak routes, preventing header spoofing that would bypass the APISIX→OPA filtering chain. Gap: APISIX does not set security response headers (HSTS, CSP) on API responses at the gateway, tracked via deployment#242. |
| AR-15 Verschlüsselte Kommunikation | Done | Encryption between container instances is enforced through mandatory mTLS via the Linkerd service mesh, with defaultInboundPolicy: cluster-authenticated set cluster-wide (defaults/environment/global.yaml); the APISIX ingress edge is explicitly scoped to require an authenticated mesh identity by default. A Kyverno policy additionally flags any meshed namespace that omits an inbound policy; running that policy in Enforce rather than Audit mode is the operator's responsibility. |
| AR-16 Abschirmung unterschiedlicher Vertrauenszonen | Done | Namespace-based trust-zone isolation is available: each component can be deployed into its own namespace, every component ships a default-deny ingress NetworkPolicy with explicit per-component allow rules (defaults/environment/networkpolicies.yaml.gotmpl), and Linkerd mTLS is mandatory between pods. The deployment ships singleNamespace: true by default; for full trust-zone separation the operator must set singleNamespace: false so that components are placed in separate namespaces. Caveat: in multi-namespace mode the NetworkPolicy component-namespace resolver fails open (emits a permissive peer) when a namespace cannot be resolved (deployment#255). |
| AR-17 Integritätsgeschützter Kanal für Deployment | Done | CIVITAS/CORE is delivered as source code and Helm charts through GitLab and container images through the GitLab Container Registry over TLS, so transport-layer integrity and authentication of the delivery channel are ensured. Container images carry SLSA Build Provenance attestations (in-toto predicate https://slsa.dev/provenance/v1) generated by docker buildx --provenance=true, binding the image digest to the CI build metadata. Release container images are signed manually by the Product Owner prior to release. Automating signing within the CI pipeline is tracked in platform#1697. |
| CT-1 Container-Hardening | Done | All container workloads apply the shared hardening baseline (runAsNonRoot: true, capabilities.drop: [ALL], readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, seccompProfile: RuntimeDefault) defined in defaults/environment/security.yaml.gotmpl and referenced by every chart's securityContext/podSecurityContext. Mandated through Deployment Standards (section "Security"). |
| CT-2 Werkzeuggestützte Prüfung auf Container-Sicherheitslücken | Done | Trivy scans are used to scan container images. (implementation ticket) |
| CT-3 Basisimages aus vertrauenswürdigen Quellen | Done | All container base images are sourced from trusted, well-established providers: - eclipse-temurin (Adoptium/Eclipse Foundation) — Java components (portal-backend, config-adapter) - node (Docker Official Image) — portal-frontend - alpine (Docker Official Image) — build stages - openpolicyagent/opa (CNCF project) — policy engine (authz) - busybox (Docker Official Image) — init containers AuthZ repository uses SHA256 digest pinning for reproducible builds. Mandated through Deployment Standards (section "Version Management"). |
| CT-4 Minimalistische Basisimages | Done | Base images across the deployment use minimized Alpine variants (e.g. eclipse-temurin:25-jre-alpine, node:22-alpine) for CIVITAS-developed services, and the OPA image uses a -static (distroless) variant — all minimal compared to full OS images. Mandated through the Backend Style Guide. |
| CT-5 Geheimnisse zur Laufzeit dynamisch bereitstellen | Done | As per SSDLC (section 9) and Deployment Standards (Section "Security"), secrets are stored through Kubernetes secrets or other secure means external to the application. Helm templates use secretKeyRef to inject secrets from Kubernetes Secrets at runtime. No secrets are baked into container images. CI pipeline includes secret scanning to prevent hardcoded secrets from being merged.Exception: Keycloak stores secrets (passwords, signing keys) in database; all of them are changeable through regular Keycloak mechanisms. |
| CT-6 Gehärtete Clusterknoten | Not Applicable | Since CIVITAS/CORE assumes it runs on an existies kubernetes cluster, this requirement is out of scope for CIVITAS/CORE. |
| CT-8 Geringstmögliche Privilegien für Container-Images | Done | All CIVITAS/CORE-developed containers run as non-root: Helm deployments set runAsUser: 1000, runAsNonRoot: true. Dockerfiles create non-root users (UID 1001). Additionally: drop: [ALL] capabilities, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false. Ensured through Deployment Standards (section "Security"). |
| CT-9 Transportverschlüsselung & Integrität zwischen Pods | Done | Encryption between container instances is enforced through mandatory mTLS via the Linkerd service mesh, with defaultInboundPolicy: cluster-authenticated set cluster-wide (defaults/environment/global.yaml); the APISIX ingress edge is explicitly scoped to require an authenticated mesh identity by default. A Kyverno policy additionally flags any meshed namespace that omits an inbound policy; running that policy in Enforce rather than Audit mode is the operator's responsibility. |
| MS-3 Vermeidung fester Credentials für Managed-Service-Zugriffe | Not Applicable | Not applicable, as any possible managed service access is outside the scope of the application's design. |
| AUT-1 Einheitliche Vertrauensniveaus in der Authentifizierung | Done | Authentication is centralized through Keycloak. For Keycloak, no fallback methods (e.g. password reset through security questions) are defined. Single trust level for all users. |
| AUT-2 Multi-Faktor-Authentisierung | Done | CIVITAS/CORE uses Keycloak as the identity provider for all components. MFA is available through Keycloak (WebAuthn and TOTP), configured via a custom browser flow with a 2FA subflow gated by a conditional-user-configured authenticator. OTP uses HmacSHA256; WebAuthn uses ES256/RS256. |
| AUT-3 Dedizierte Serviceaccounts | In Progress | Dedicated ServiceAccounts are created for config-adapter and etcd (serviceAccount.create: true); external Helm operators (cloudnative-pg, strimzi, keycloakx, apisix) ship their own. Mandated through Deployment Standards (section "Security"). Gaps: portal backend/frontend, AuthZ repository service, and OPA declare no serviceAccountName and fall back to the namespace default ServiceAccount; config-adapter and etcd mount their SA tokens (automountServiceAccountToken: true) with no apparent need for Kubernetes API access, and no workload sets automountServiceAccountToken: false. Tracked via Minimize ServiceAccount token exposure across CIVITAS workloads. |
| AUT-4 Kryptografisch abgesicherter Zugriff auf Infrastruktur | Done | Infrastructure access is the operator's responsibility. CIVITAS/CORE provides Keycloak with WebAuthn support (ES256/RS256) as an available cryptographic authentication mechanism. Operators can enable cryptographically secured access for administration. Direct Keycloak admin access is not a supported use case in the CIVITAS/CORE operational model. |
| AUT-5 Zugriffskontrollmodell definieren | Done | The authorization model is documented here |
| AUT-6 Sitzungs-IDs invalidieren | Done | CIVITAS/CORE uses Keycloak for authentication and Keycloak supports this out of the box. |
| AUT-7 Passwortrichtlinien | Done | Keycloak enforces password policies per TR-03187: user realm requires min 12 characters with uppercase, lowercase, and digit (length(12) and upperCase(1) and lowerCase(1) and digits(1)). Master/admin realm requires min 20 characters with additional special character. Authentication is centralized through Keycloak via NextAuth (OIDC), so these policies apply to all user-facing authentication. |
| W-1 Deny All als Default | Done | Four-layer deny-all-by-default: (1) OPA default allow := false with explicit permission-based allow rules only (main.rego). (2) APISIX bearer_only: true rejects requests without valid JWT. (3) Spring Security anyRequest().authenticated() catch-all (SecurityConfig.java). (4) NextAuth middleware denies unauthenticated access to all non-public paths. This is mandated as part of the SSDLC (Section "3. Requirements you need to fulfill"). |
| W-2 Zugriffskontrollmodell definieren | Done | The authorization model is documented in the Authorization Data Model and implemented via OPA Rego policies (permission evaluation with provider-based endpoint mapping) and Keycloak RBAC. |
| W-3 Einheitlicher Zugriffskontrollmechanismus | Done | Unified access control for backend API traffic via APISIX (API gateway) + OPA (policy engine). The /v1/* portal-backend route passes through OIDC authentication (APISIX openid-connect plugin, bearer_only: true) and OPA authorization (components/portal/apisix-plugins.yaml).Deliberate exceptions to this chain: - Portal BFF (Next.js frontend): handles authentication via NextAuth; has no own authorization layer (access control to backend APIs still goes through APISIX + OPA). - Keycloak ( idm.*): self-authenticated — it is the identity provider. |
| W-4 Restriktive CORS-Policy | Done | No CORS configuration in backend (no @CrossOrigin annotations, no CorsConfiguration beans, no wildcard origins). Backend is not directly exposed to browsers — APISIX handles API gateway concerns. Ingress-level CORS is operator responsibility (see also W-17). CORS policy mandated through Backend Style Guide (section "CORS-Policy"). |
| W-5 Web-Server-Verzeichnisauflistung deaktivieren | Done | Spring Boot embedded Tomcat disables directory listing by default; no override found. Next.js serves only explicitly referenced assets from public/. No ResourceHandlerRegistry configured. |
| W-6 Nicht benötigte Datei-Metadaten und Sicherungskopien vermeiden | Done | Dockerfiles COPY only production artifacts (JARs, .next/, public/). No backup or metadata files in deployed images. AuthZ has explicit .dockerignore. Spring Boot and Jetty do not serve static files without specific provisions. |
| W-7 Sitzungs-IDs nach Logout invalidieren | Done | Federated logout implemented: NextAuth signOut() clears the JWT session and calls Keycloak's OIDC logout endpoint with id_token_hint (auth.config.ts signOut event). Both the local NextAuth JWT and the Keycloak SSO session are terminated. Implementation details documented in Authentication Flow. |
| W-8 Kurzlebige JWTs | Done | Keycloak token lifetimes (base-values.yaml.gotmpl): access token 5 minutes (accessTokenLifespan: 300), SSO Session Idle 60 minutes, SSO Session Max 10 hours. Admin realm stricter: SSO idle 30 minutes. Frontend session maxAge 10 hours.(Implementation ticket) |
| W-9 Sichere DB-Zugriffe (ORM/Prepared) | Done | Spring Data JPA with parameterized @Query annotations used throughout. All queries use :paramName binding — no raw SQL or string concatenation detected. Enforced through Backend Style Guide (section "Security"). |
| W-10 Vom Benutzer übergebene Objekte defensiv deserialisieren | Done | Jackson ObjectMapper is used without dangerous polymorphic typing (enableDefaultTyping()/activateDefaultTyping() are not used). Custom deserializers (e.g. UpstreamNodes.NodesDeserializer) validate JSON token types explicitly before deserializing. No XXE-vulnerable XML parsing. Mandated through the Backend Style Guide (section "Security"). |
| W-11 Clientseitige Eingabevalidierung | Done | Client-side validation implemented through React Hook Form with Zod schemas. Forms enforce email validation, length constraints (min/max), regex patterns, and required fields. Examples: UserInputDTO uses z.email(), z.string().min(2), phone validation with regex; DatasourceInputDTO uses z.string().trim().max(150). Mandated through Frontend Style Guide (section "Security Principles"). |
| W-12 Serverseitige Eingabevalidierung | Done | Server-side validation is enforced via Jakarta Bean Validation: @Validated on BaseController, @Valid @RequestBody on create/update endpoints, with constraint annotations (@NotBlank, @Email, @Size, slug patterns) on input DTOs such as DataSetInputDTO, DataSourceInputDTO, and NamedApiInputDTO. Mandated through the Backend Style Guide (section "Security"). |
| W-13 Limitierung Anzahl Ergebnisse Datenbankabfragen | Done | Pagination is enforced via @PageableDefault(size=20, sort="createdAt", direction=DESC) on BaseController.getAll(). All controllers extend BaseController and inherit pagination, so list endpoints return no unbounded result sets. |
| W-14 Standardzugangsdaten ändern | Done | Authentication is centralized through Keycloak. The Keycloak admin password is injected from a Kubernetes Secret (keycloak-admin-user) generated by the secrets component at installation time. No hardcoded default credentials exist in the codebase. |
| W-15 Whitelisting für Eingabedaten | Done | Jackson ObjectMapper does not enable polymorphic default typing (enableDefaultTyping()/activateDefaultTyping() are not used), so JSON deserialization will not instantiate arbitrary classes from client-supplied type hints. Custom deserializers (e.g. UpstreamNodes.NodesDeserializer) validate JSON token types explicitly before deserializing. No XXE-vulnerable XML parsing. Mandated through the Backend Style Guide (section "Security"). See also W-10. |
| W-16 Whitelisting für URLs in Eingabedaten | In Progress | URL inputs are not restricted by an explicit scheme/host/port allowlist; MQTT connector and SQL connector DSN fields accept any syntactically valid URL. Tracked as a security finding via platform#1865. |
| W-17 Whitelisting für Allow-Origin | Not Applicable | Should be done at ingress and is thus responsibility of the operator. We recommend the following CORS settings: * Access-Control-Allow-Origin allows only specific domains, not . Access-Control-Allow-Methods contains only the HTTP verbs required by the use case (e.g. GET, POST). * Access-Control-Allow-Headers is defined explicitly, not through wildcards. * Access-Control-Allow-Credentials is only set when required by the use base. |
| W-18 Detaillierte Fehlermeldungen Produktivsystemen vermeiden | Done | This is mandated as part of the SSDLC (Section "3. Requirements you need to fulfill") |
| W-19 Minimale Auskunft über Komponenten | Done | Actuator endpoints are restricted to health, info, and prometheus (portal-backend/src/main/resources/application.yaml). No server header configured (Spring Boot default: no disclosure). Stack traces are not exposed (default NEVER in production). Next.js x-powered-by disabled. AuthZ health endpoint: show-details: never. Mandated as part of SSDLC policy (section 3). |
| W-20 Nicht benötigte HTTP-Verben deaktivieren | Done | HTTP verbs are restricted per endpoint at the OPA authorization layer: each backend path enumerates its allowed methods in the endpoint-mapping data (authz/rego/data/backends/portal_backend/data.json), and any method not listed for a path is denied as unknown_endpoint (fail-secure default-deny, authz/rego/policy/main.rego). Independently, the portal backend's Spring MVC controllers map only the verbs each endpoint uses, so any unmapped verb returns 405 by framework default. |
| W-21 Keine sensiblen Daten in URLs | Done | Tokens transmitted exclusively in Authorization headers (Bearer), never in URLs. Refresh tokens sent via POST body (application/x-www-form-urlencoded). Frontend proxy explicitly strips cookies from forwarded requests. API path parameters used only for UUIDs, never for tokens or passwords. This is mandated as part of the SSDLC (Section "3. Requirements you need to fulfill"). |
| W-22 Clientseitiges Caching und Autocomplete abschalten | In Progress | API requests from the portal-frontend carry Cache-Control: no-store, and credential inputs in the connector configuration (MQTT and SQL password fields) render with type="password" and autoComplete="new-password", suppressing browser autofill and credential storage. Mandated in the Frontend Style Guide (section "Security Principles"). Gap: authenticated HTML pages (platform#1668) and backend API responses (platform#1666) do not consistently set Cache-Control: no-store. |
| W-23 HSTS aktivieren | Not Applicable | This needs to be set at the egress and is thus responsibility of the Operator. |
| IoT-1 Zugang allen IoT-Ressourcen standardmäßig verweigern | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| IoT-2 Einheitlicher Zugriffskontrollmechanismus | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. h Security Architecture Principles |
| IoT-3 Authentifizierung und Autorisierung für IoT-Geräte | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| IoT-4 Standardzugangsdaten ändern | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| IoT-5 Device Onboarding | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| IoT-6 Generierung von Netzschlüsseln nach Zufallsprinzip | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. h Security Architecture Principles |
| IoT-7 Erneuerung Netzschlüssel | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| IoT-8 Replay-Schutz | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| IoT-9 Eindeutige Identifikation von IoT-Geräten | Not Applicable | Not applicable, as there is no direct traffic from IoT devices to CIVITAS/CORE. |
| VPN-1 VPN-Verschlüsselungsverfahren gemäß TR-02101-1 | Not Applicable | Not applicable, as VPN is assumed to be handled by the Operator at an infrastructure level. Document in a suitable "Product Scope" type document. |
| VPN-2 Sichere Konfiguration VPN-Gateway | Not Applicable | Not applicable, as VPN is assumed to be handled by the Operator at an infrastructure level. Document in a suitable "Product Scope" type document. |
| L-1 Logging von Sicherheitsereignissen | Done | Security event logging implemented across components: OPA decision logs enabled (JSON, console) with sensitive header masking via mask.rego. Keycloak logs 68 event types (LOGIN, LOGIN_ERROR, admin events with details, account changes, token events, MFA events; 30-day retention). Backend SecurityExceptionHandler logs auth failures (401), access denied (403), and JWT validation failures at WARN level. Config-adapter logs connector lifecycle events. Frontend logs proxy auth events via Pino (JSON in production). See concept ticket. |
| L-2 Logging von fehlgeschlagenen Authentisierungsvorgängen und allen Authorisierungvorgängen | Done | Failed authentication logged by: Keycloak LOGIN_ERROR + all *_ERROR event types (68 event types configured). Backend SecurityExceptionHandler catches 401/403 at WARN level. OPA decision logs capture authorization denials with reason codes (default_deny, permission_denied, unknown_endpoint). OPA mask.rego redacts tokens, authorization headers, and userinfo from decision logs. See concept ticket. |
| L-3 Schutz von Logs vor unbefugtem Zugriff | Done | All CIVITAS/CORE components write logs exclusively to stdout without storing them. OPA decision logs mask sensitive headers (tokens, authorization, userinfo) via mask.rego. Keycloak stores events in its database with 30-day retention; that database is only accessible by the Keycloak service. Log storage, integrity, and access control are the operator's responsibility; the hardening guide documents minimum expectations. |
| L-4 Sensible Informationen nicht loggen | In Progress | Sensitive data masking is implemented across components: OWASP Encode (Encode.forJava()) wraps log arguments in portal-backend (including the security exception handler), config-adapter, and the authz repository (UserContextService with UUID masking); maskSensitiveFields() masks connector secrets; Pino filters request headers in the frontend; OPA mask.rego masks tokens, authorization headers, and userinfo in decision logs. Mandated by the Backend Style Guide (section "Logging"). Gaps: the AuthZ decision log emits the full subject UUID unmasked (platform#1672); the frontend logs a raw Keycloak error JSON (platform#1669) and has console.* calls that bypass Pino redaction (platform#1670). |
| DH-1 Verschlüsselung At-Rest | Not Applicable | Not applicable, as this is considered the responsibility of the operator. CIVITAS/CORE assumes encryption to be handled transparently at a volume level. |
| DH-2 Schutz geheimer Schlüssel | Done | As per SSDLC (section 9) and Deployment Standards (Section "Security"), secrets are stored through Kubernetes secrets or other secure means external to the application. Exception: Keycloak stores secrets (passwords, signing keys) in database. |
| DH-3 IPC-Schnittstellen müssen geschützt sein | In Progress | Internal service-to-service (IPC) calls are protected at the transport layer by mandatory Linkerd mTLS (defaultInboundPolicy: cluster-authenticated) and per-component NetworkPolicies; endpoints such as the AuthZ Repository's user-context endpoint rely on this mesh-and-network-policy boundary as the intended control. Gap: the Kafka message bus has no topic-level authorization — mTLS authenticates connections and NetworkPolicies gate reachability, but any pod able to reach the broker can produce to or consume from any topic. Tracked via platform#1294, platform#1637, and deployment#245. |
| DH-4 Data Governance-Vorgaben etablieren | Done | CIVITAS/CORE provides features through which organizations can implement data governance: * Fine-grained permission management * Separation of Data Sources and Data Sets * Data Sets, Data Sources, and Data Models can carry custom metadata tags * Data provenance tracking via Data Source as a first-class entity |
| ORG-6 Schwachstellenmanagement | In Progress | Known vulnerabilities are surfaced automatically via GitLab SAST, Dependency-Scanning, and Secret-Detection templates plus Trivy-based container scanning per built image, all reporting into the GitLab Security Dashboard; Renovate additionally opens dependency-update merge requests and flags security advisories (including OSV) as a labeled category. Gap: no documented triage SLA or remediation-ownership process exists yet beyond this automated detection and alerting. Tracked via platform#1473. |
| ORG-7 Tests nur auf dedizierter Umgebung | Not Applicable | Neither Civitas Connect nor any of the members of the project team provide a production environment. Therefore this requirement is not applicable. All tests are run on dedicated environments with synthetic data. The requirement for synthetic data is part of the Security Architecture Principles. |
| ORG-8 Penetrationstests | In Progress | A penetration test is currently underway, tracked through GitLab Epic Penetration Test (#118). Results and any resulting remediation items will be tracked through that epic. |
Generated on 08 July 2026, 14:09 UTC from https://gitlab.com/civitas-connect/civitas-core/requirements (labels: requirement-source::tr-03187, tr-level::1).