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.
Release covered: This statement reflects the state of CIVITAS/CORE at the v2.0-beta release (deployment repository), with platform components pinned at v1.0.0.
| 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 | SSDLC policy (Section 6.6) and the Deployment Checklist (section "Production Requirements") mandate a reasonable effort to be made towards minimizing shipped artifacts. Todo: config adapters are not shipped piecemeal; all of them are in one container, should be changed. |
| 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 charts ( components/*/charts.yaml): apisix 2.12.6, keycloakx 7.1.4, keycloak-config-cli 1.3.6, strimzi-kafka-operator 0.48.0, cloudnative-pg 0.26.0, cnpg/cluster 0.3.1, frost 2.7.0, kafka-ui 1.5.2.Container images ( components/*/images.yaml): portal backend/frontend v1.0.0, authz/opa v1.0.0, config-adapter 1.0.2, apicurio registry/ui 3.1.3, apisix gateway 3.14.1-ubuntu, keycloak 26.4.0, keycloak-config-cli 6.4.0-26, postgis 16-3.4, model-atlas apicurio-0.0.1, frost-server-http 2.6.0.Java dependencies are pinned in pom.xml, frontend dependencies via pnpm-lock.yaml, Dockerfiles version-tagged (authz additionally uses SHA256 digest pinning).Implementation ticket: Pin Helm image tags to release versions. |
| 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 | Done | 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). Config-adapter saga engine deduplicates per dataset (existsForDataset() check). Manual synchronous offset commits ensure at-least-once delivery. mTLS via Linkerd provides transport-layer replay protection. |
| 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 | In Progress | Encryption between container instances is implemented through TLS via the Linkerd service mesh. Namespace-level sidecar injection is enabled. Application-level TLS verification (ssl_verify, NODE_TLS_REJECT_UNAUTHORIZED) is delegated to the mesh layer.Gap: Linkerd mTLS is opportunistic — no Server or AuthorizationPolicy CRDs are deployed, so connections can fall back to plaintext if a sidecar is missing.Tracked via Add Linkerd AuthorizationPolicy CRDs to enforce mTLS. |
| AR-14 Alle vorgesehenen Sicherheitsmechanismen defaultmäßig anschalten | In Progress | Security mechanisms enabled by default: Frontend sets CSP (nonce-based), X-Content-Type-Options, X-Frame-Options, Referrer-Policy via Next.js middleware. Keycloak has brute force protection enabled in production (10-attempt lockout). Trivy container scanning feeds into GitLab Security Dashboard. CSRF intentionally disabled (stateless JWT API). Kyverno policies enforce pod security standards (drop-all-caps, read-only rootfs, probes, resource limits). APISIX strips inbound authorization headers (X-Userinfo, X-Access-Token, X-Allowed-Scope-Ids) before upstream delivery via a serverless-pre-function plugin (components/portal/apisix-plugins.yaml), preventing header injection/spoofing to bypass the APISIX→OPA filtering chain.Gap: APISIX does not set security response headers (HSTS, CSP on API responses, etc.) at the gateway layer for /v1/* routes. Tracked via APISIX security hardening — response headers.Note: Deployment of Kyverno and the decision to run it in Enforce mode is the operator's responsibility. |
| AR-15 Verschlüsselte Kommunikation | In Progress | Encryption between container instances is implemented through TLS via the Linkerd service mesh. Namespace-level sidecar injection is enabled. Application-level TLS verification (ssl_verify, NODE_TLS_REJECT_UNAUTHORIZED) is delegated to the mesh layer.Gap: Linkerd mTLS is opportunistic — no Server or AuthorizationPolicy CRDs are deployed, so connections can fall back to plaintext if a sidecar is missing.Tracked via Add Linkerd AuthorizationPolicy CRDs to enforce mTLS. |
| AR-16 Abschirmung unterschiedlicher Vertrauenszonen | In Progress | Namespace-based isolation is implemented: 12+ component-specific namespaces when singleNamespace: false (portal, keycloak, authz, postgres, kafka, etcd, apisix, config-adapters, model-atlas, apicurio, frost, redpanda-connect). NetworkPolicies exist for 11 components with pod-level ingress restrictions. Linkerd mTLS between pods.Gap: default deployment uses singleNamespace: true; no namespace-level default-deny NetworkPolicies.Tracked via Switch to multi-namespace default and add default-deny NetworkPolicies. |
| AR-17 Integritätsgeschützter Kanal für Deployment | In Progress | CIVITAS/CORE is deployed as source code and Helm charts through GitLab and container images through the GitLab Container Registry. GitLab enforces TLS on the transport layer, so integrity and authentication of the delivery channel are ensured. Container images carry automatic SLSA Build Provenance attestations (in-toto predicate https://slsa.dev/provenance/v1) generated by docker buildx --provenance=true, which cryptographically bind the image digest to the CI build metadata (source commit, pipeline ID). Verified on registry.gitlab.com/civitas-connect/civitas-core/civitas-core-v2/civitas-core-platform/backend-portal:v1.0.0.Gap: Images are not signed with cosign/sigstore or Notary — no signature tags or separate signing keys exist in the registry. Cryptographic signing with an external key would strengthen non-repudiation against registry compromise. Tracked via Implement container image and helm chart signing. |
| CT-1 Container-Hardening | In Progress | All CIVITAS/CORE-developed components (Portal, AuthZ, Model-Atlas, Config-Adapter, ETCD) implement full container hardening: runAsNonRoot: true, drop: [ALL] capabilities, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, runAsUser: 1000. Dockerfiles set non-root users (UID 1001).Gap: Apicurio (3rd party) has no securityContext configured — the chart values (components/apicurio/charts/apicurio/values.yaml) show securityContext: {} and the value overlay does not set it.Tracked via Add securityContext for Apicurio container. |
| 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) — Model Atlas init container AuthZ repository uses SHA256 digest pinning for reproducible builds. Model Atlas uses eclipse-temurin:21-jre-alpine.Mandated through Deployment Standards (section "Version Management"). |
| CT-4 Minimalistische Basisimages | In Progress | Alpine-based images are used for all components (eclipse-temurin:21-jre-alpine, node:22-alpine), which are minimal compared to full OS images. JLink for custom minimal JRE is not yet implemented but is a planned improvement per the Backend Style Guide. Model Atlas: same eclipse-temurin:21-jre-alpine, single OSGi fat JAR, no JLink. |
| 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").Note: Apicurio (3rd party) does not have a securityContext configured. |
| CT-9 Transportverschlüsselung & Integrität zwischen Pods | In Progress | Encryption between container instances is implemented through TLS via the Linkerd service mesh. Namespace-level sidecar injection is enabled. Application-level TLS verification (ssl_verify, NODE_TLS_REJECT_UNAUTHORIZED) is delegated to the mesh layer.Gap: Linkerd mTLS is opportunistic — no Server or AuthorizationPolicy CRDs are deployed, so connections can fall back to plaintext if a sidecar is missing.Tracked via Add Linkerd AuthorizationPolicy CRDs to enforce mTLS. |
| 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 | In Progress | CIVITAS/CORE uses Keycloak as the identity provider for all components. MFA support is available through Keycloak (WebAuthn and TOTP). A custom browser flow is configured in components/keycloak/values/config/base-values.yaml.gotmpl (top-level flow custom browser, with subflows custom browser forms and custom browser 2fa). The 2FA subflow is gated by a conditional-user-configured authenticator, so 2FA is enforced only for users who have registered a TOTP or WebAuthn credential; users without registered factors complete authentication with username/password alone. OTP uses HmacSHA256; WebAuthn uses ES256/RS256.Gap: MFA is not enabled by default — Configure OTP and Webauthn Register required actions are not set on user creation. Enabling MFA as a default is a planned improvement. |
| AUT-3 Dedizierte Serviceaccounts | In Progress | Dedicated ServiceAccounts are created by default for model-atlas, config-adapter, and etcd (serviceAccount.create: true in each chart). External Helm operators used by the deployment (cloudnative-pg, strimzi, keycloakx, apisix) ship their own ServiceAccounts. Mandated through Deployment Standards (section "Security").Gaps: 1. Portal backend, Portal frontend, AuthZ repository service, and OPA do not declare serviceAccountName and fall back to the namespace default ServiceAccount.2. Model-atlas, config-adapter, and etcd are deployed with automountServiceAccountToken: true, so their SA tokens are mounted into the pods even though no Kubernetes API access is apparent.No pod spec or ServiceAccount in the deployment repository 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.- FROST-Server: internal-only in v2.0-beta, therefore no authorization chain configured. |
| 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. Model Atlas uses Jetty, which also cannot list directories by default. |
| 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 without dangerous enableDefaultTyping()/activateDefaultTyping(). Custom deserializers (e.g. UpstreamNodes.NodesDeserializer) validate JSON token types explicitly before deserializing. No XXE-vulnerable XML parsing. Handled through Backend Style guide (section "Security") and Model Atlas EMF/Jackson validation. Model Atlas: Jackson configured via Gecko codec framework (no dangerous typing). Also accepts XMI/Ecore deserialization via EMF (EcoreMessageBodyHandler) — EMF deserialization creates model objects from schema (not arbitrary Java objects), safe by design. |
| 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 | In Progress | Server-side validation via Jakarta Bean Validation: @Validated on BaseController, @Valid @RequestBody on create/update endpoints. Input DTOs carry constraint annotations (@NotBlank, @Email, @Size), for example DataSetInputDTO enforces @NotBlank @Size(min=3, max=255) on name, DataSourceInputDTO enforces @NotBlank on name. Enforced through the Backend Style Guide (section "Security").Gap: DistributionInputDTO.accessUrl has no validation annotation (URL-whitelisting for this field also relates to W-16).Implementation ticket: Add missing validation annotations to input DTOs. |
| W-13 Limitierung Anzahl Ergebnisse Datenbankabfragen | Done | Pagination enforced via @PageableDefault(size=20, sort="createdAt", direction=DESC) on BaseController.getAll(). All list endpoints inherit pagination. No unbounded result sets. All controllers extend BaseController and inherit pagination enforcement.Model Atlas: EPackageResource accepts skip/limit query params with @DefaultValue("0")/@DefaultValue("100"). Pagination exists but no max bound on limit. Accepted given internal-only access (NetworkPolicy restricts to portal-backend only). |
| 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. Model Atlas uses the Gecko codec framework over Jackson with the same restriction; EMF deserialization (EcoreMessageBodyHandler) instantiates only model objects defined by the registered Ecore schema, not arbitrary Java classes.Mandated through the Backend Style Guide (section "Security"). See also W-10. |
| W-16 Whitelisting für URLs in Eingabedaten | In Progress | URL inputs in DTOs are not currently constrained by an explicit URL allowlist (scheme/host/port). The closest constraint is @NotBlank on string fields that hold URLs (e.g. DistributionInputDTO.accessUrl does not even have that). Mandated through the Backend Style Guide (section "Security").Tracked via [https://gitlab.com/civitas-connect/civitas-core/civitas-core-v2/civitas-core-platform/-/issues/1052](Add missing validation annotations to input DTOs). |
| 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 restricted to health, info, and prometheus (portal-backend/src/main/resources/application.yaml). No server header configured (Spring Boot default: no disclosure). Stack traces not exposed (default NEVER in production). Next.js x-powered-by disabled. AuthZ health endpoint: show-details: never. Model Atlas has a global ModelAtlasExceptionMapper that returns generic messages for 5xx errors; stack traces are opt-in via the MODELATLAS_DEBUG_STACKTRACE env var (off by default), and Swagger UI has been removed from the build. Mandated as part of SSDLC policy (section 3). |
| 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 (portal-frontend/src/app/services/api/request/apiRequest.ts, portal-frontend/src/lib/serverFetch.ts), so credential responses are not cached client-side. Mandated in the Frontend Style Guide (section "Security Principles").Gap on credential-bearing forms (data source connector configurations): - The MQTT and SQL connectors expose password fields (and the SQL connector additionally dsn, which commonly embeds credentials) via connectorSources.ts. They are rendered as plain inputs through DynamicFormField → TextField, which sets neither type="password" nor autoComplete="off". The browser may therefore store and replay these values.- HTML page responses from the data source detail/edit views are served without Cache-Control headers (no header set in next.config.ts or middleware.ts), so the rendered pages including credential values may be cached by the browser by default.Tracked via Disable autocomplete and browser caching on credential-bearing forms. |
| 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 (e.g. KafkaCloudEventPublisher, DataSetSagaPublisher, UserController), config-adapter (20+ locations), and authz repository (UserContextService with UUID masking ab12****ef34). maskSensitiveFields() with MASKED_VALUE = "********" masks connector secrets in portal-backend. Pino in the frontend filters request headers, logging only non-sensitive ones. OPA mask.rego masks tokens, authorization headers, and base64-encoded userinfo (PII) in decision logs. Portal-backend production code does not use System.out / System.err / printStackTrace. Model Atlas (civitas fork) routes errors through a global ModelAtlasExceptionMapper and uses the structured logger framework throughout. Mandated by Backend Style Guide (section "Logging").Gaps: - portal-backend/src/main/java/de/civitascore/portal/controller/exception/SecurityExceptionHandler.java logs ex.getMessage() at lines 47, 64, 79 without Encode.forJava(...) wrapping.- Model Atlas: org.eclipse.fennec.model.atlas.management/.../storage/AbstractEObjectStorageService.java:352 retains an e.printStackTrace(System.out) call alongside an existing structured logger entry, bypassing the logging framework for stdout.Tracked via L-4 follow-up: encode exception messages and remove residual stacktrace print. |
| 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-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-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 | Penetration Tests are planned and tracked through Gitlab Epic Penetration Test |
Generated on 14 April 2026, 13:53 UTC from https://gitlab.com/civitas-connect/civitas-core/requirements (labels: requirement-source::tr-03187, tr-level::1).