Files
CASAN/docs/architecture/CASAN_CONTROL_PLANE.md
T

4.3 KiB

CASAN Control Plane

Status: production-capable packaged authentication and trust configuration; external infrastructure remains operator-provisioned.

Deployment modes

Local development

  • Default bind: 127.0.0.1.
  • CASAN_CP_AUTH_MODE=local is allowed only on loopback and outside production.
  • Local actor headers are explicitly development identity and are not a production authentication claim.

Networked or production

  • CASAN_CP_AUTH_MODE=jwt is mandatory.
  • Production requires RS256 verification, a mounted public key, exact issuer and audience, and a clock skew from 0 through 300 seconds.
  • Missing or invalid configuration refuses startup before NestJS listens.
  • HS256 is retained only for deterministic non-production tests.

Packaged identity boundary

Browser
  -> enterprise OIDC
  -> oauth2-proxy session
  -> Nginx auth_request
       removes X-CASAN-* and forwarded identity headers
       forwards signed Bearer access token
  -> NestJS AuthProvider
       verifies RS256 signature, iss, aud, sub, exp, nbf and iat
  -> VerifiedClaims
  -> CASAN RBAC role mapping and scoped request identity

Nginx is a TLS/session boundary, not the identity authority for the API. The API ignores caller-supplied identity assertions and derives actor, role, tenant and project only after token verification.

Authentication implementation

backend/src/common/auth-provider.ts defines:

  • AuthProvider and JwtAuthProvider.
  • Typed VerifiedClaims and AuthenticationDecision.
  • RS256/HS256 signature verification using Node's standard crypto APIs.
  • Issuer, audience, expiry, not-before, issued-at and bounded-skew checks.
  • Safe tenant/project syntax validation.
  • Structured authentication audit evidence without raw tokens.
  • Middleware that overwrites request identity only from verified claims.

auth-context.ts refuses direct header use in JWT mode unless the middleware has marked the identity verified. Existing RBAC services then map verified groups and continue to produce governance/authorization evidence.

Production configuration

Required runtime variables:

CASAN_PROFILE=prod
CASAN_CP_AUTH_MODE=jwt
CASAN_CP_JWT_ISSUER=https://...
CASAN_CP_JWT_AUDIENCE=...
CASAN_CP_JWT_PUBLIC_KEY_FILE=/run/casan-idp/idp-public.pem
CASAN_CP_JWT_ROLE_CLAIM=groups
CASAN_CP_JWT_TENANT_CLAIM=casan_tenant
CASAN_CP_JWT_PROJECT_CLAIM=casan_project
CASAN_CP_JWT_CLOCK_SKEW_SECONDS=60

The host path is configured as CASAN_CP_IDP_PUBLIC_KEY and mounted read-only. oauth2-proxy must set xauthrequest output and pass the access token. Images for API, UI and oauth2-proxy must be digest-pinned.

production-preflight.sh validates:

  • TLS hostname, expiry and matching private key.
  • IdP public key readability and RSA public-key format.
  • HTTPS OIDC issuer, secure cookies and token forwarding.
  • Matching oauth2-proxy client ID and API audience.
  • Matching issuer and bounded JWT clock skew.
  • External Vault/KMS signing and S3 Object Lock provider selection.
  • Live short-lived non-root Vault token lookup.
  • A real Object Lock COMPLIANCE anchor write.
  • Digest-pinned images and valid Compose/Nginx configuration.

Authentication evidence

Each production authentication decision appends a JSONL record under CASAN_STATE_ROOT/logs/auth/decisions.jsonl with category, policy, decision, reason, actor, issuer, scope and request method/path. Tokens and secrets are never written. A failure to authenticate returns HTTP 401 with a stable reason code; it is not converted to viewer access.

Local production-like smoke

docker-compose.control-panel.local.yml uses the same bearer-token path. The smoke script generates an ephemeral RSA keypair, mounts the private key into the mock IdP and the public key into the API, and enables token forwarding. This validates the boundary without treating the mock IdP as production.

Residual limitations

  • Public-key rotation currently requires replacing the mounted key and restarting the API; automated JWKS discovery and rollover are not present.
  • Enterprise IdP, managed TLS, Vault and S3 are not provisioned by the repo.
  • Local tests validate crypto and provider contracts, but do not prove a real tenant's claim mapping, token lifecycle, network policy or key rotation.
  • The Control Plane is production-capable for this packaged deployment model; it is not yet a universal multi-runtime scheduler or supervisor.