Skip to main content

Security conventions — gentian-ui (kernel shell)

Implements the same mandatory controls as gentian-apps/apps/_template/docs/SECURITY.md. Read that document for the full M1–M27 checklist; this file maps template modules to this repo and notes kernel-specific deployment differences.

Template parity (implemented here)​

RequirementLocation
M1–M3 OIDC + JWTbackend/app/core/auth.py, frontend/src/auth/
M4 tenant contextbackend/app/core/tenant.py (JWT claims, not TENANT_ID env)
M7 log redactionbackend/app/core/logging_middleware.py
M8 health probesbackend/app/api/routes/health.py
M9 CORSbackend/app/core/config.py, chart/values.yaml
Origin check on POST/PUT/PATCH/DELETE (forged cross-site requests)gentian_app_runtime.origin_check — the rule and what it leaves open are in its docstring; CSRF_TRUSTED_ORIGINS allow-lists further origins, empty by default
M11–M13 pod hardeningchart/templates/_helpers.tpl
M16–M17 Gateway APIchart/templates/httproute.yaml
M22 / S1 OpenFGA PEPbackend/app/core/authz.py, openfga_client.py
AuthZEN PEP (Stage 2)Enabled by default on fresh installs (openfga.authzenEnabled + OpenFGA experimentals: [authzen]). BFF uses /access/v1/evaluation instead of native /check.
M26 DB scoping stubbackend/app/db/session.py
M27 resource limitschart/values.yaml, values-production.yaml.example
Frontend bearer tokenfrontend/src/api/client.ts
Protected shell routesfrontend/src/auth/RequireAuth.tsx, router.tsx

Kernel-specific differences​

TopicCatalog app (template)Kernel shell (this repo)
DeployAppProfile + tenant installgentian-os ApplicationSet
GatewayTenant Gatewaykernel-public-gateway in gentian-kernel
Host{subDomain}.{tenantDomain}portal.{kernelDomain}
Identity envTENANT_ID, TENANT_NAMESPACEKERNEL_DOMAIN
RBACOptional namespace RoleClusterRole for catalog APIs (rbac.create: true)
No profile/—Correct — not a catalog app

The assistant and the model gateway​

The desktop's API relays a signed-in person's chat to the platform's model gateway (backend/app/api/routes/llm.py, described in ai-widget.md).

  • The credential is this tenant's desktop's own key, generated and registered by the platform and mounted from the Secret llm-credentials-desktop. The desktop does not hold the gateway's administrator key, another app's key, or any Kubernetes authority to read one.
  • Every member who can open the desktop can use it. The key cannot tell them apart, so the API sends the person's subject as the request's end user, builds the upstream request from an allow-list, calls two fixed paths, caps the request size, the conversation length and max_tokens, and forwards none of the browser's headers.
  • Neither the key nor the gateway's address reaches the browser or a log.
  • Left open: no limit or budget per person, and none on the key itself.

Local dev​

Copy backend/.env.example → backend/.env and frontend/.env.example → frontend/.env.local, or use docker-compose.dev.yaml which sets AUTH_DISABLED=true and VITE_AUTH_DISABLED=true.