feat(casan): establish assurance kernel and harden control plane
This commit is contained in:
@@ -10,20 +10,26 @@ This document defines the boundary between the local workstation experience and
|
||||
flowchart LR
|
||||
B["Browser"] -->|TLS + OIDC cookie| N["Nginx"]
|
||||
N -->|auth_request| O["oauth2-proxy"]
|
||||
N -->|overwritten identity headers| A["Control Panel API"]
|
||||
N -->|signed bearer token; identity headers removed| A["Control Panel API"]
|
||||
A -->|verify RS256 + issuer + audience + time claims| I["VerifiedClaims"]
|
||||
A -->|tenant-scoped encrypted store| S["CASAN state"]
|
||||
A -->|random bridge token, local only| H["Mac host bridge"]
|
||||
H -->|official CLI auth| P["Codex / Claude"]
|
||||
```
|
||||
|
||||
The API must not be published directly. Nginx is the only ingress and overwrites `X-CASAN-Actor`, `X-CASAN-Groups`, and `X-CASAN-Role`. The API refuses a non-loopback strict bind unless `CASAN_CP_TRUST_AUTH_PROXY=1` is explicit.
|
||||
The API must not be published directly. Nginx is the only ingress and removes
|
||||
`X-CASAN-*` and forwarded identity headers. The API refuses every production or
|
||||
non-loopback bind unless `CASAN_CP_AUTH_MODE=jwt` has a valid cryptographic
|
||||
verifier. Proxy headers alone are never authenticated identity.
|
||||
|
||||
## Implemented controls
|
||||
|
||||
- TLS at Nginx; production accepts only TLS 1.2/1.3.
|
||||
- OIDC authentication through oauth2-proxy.
|
||||
- Secure, HttpOnly, SameSite=Lax session cookies with bounded expiry/refresh.
|
||||
- Browser-supplied identity headers are overwritten at Nginx.
|
||||
- Browser-supplied identity headers are removed at Nginx.
|
||||
- The API verifies RS256 signature, issuer, audience, subject, expiry,
|
||||
not-before/issued-at bounds and clock skew before deriving request identity.
|
||||
- CSP, frame denial, MIME sniffing protection, referrer and browser permission restrictions.
|
||||
- API request body capped at 1 MiB.
|
||||
- SSE buffering disabled for trace streams; no intermediate proxy cache.
|
||||
@@ -53,21 +59,26 @@ Before production deployment:
|
||||
2. Do not deploy `provider-auth-bridge.py`.
|
||||
3. Use managed OpenAI/Anthropic credentials from Vault/KMS or workload identity.
|
||||
4. Use an enterprise IdP and explicit group-to-role mapping.
|
||||
5. Use a CA-issued certificate and a fixed production hostname.
|
||||
6. Set a digest-pinned `CASAN_CP_API_IMAGE`, `CASAN_CP_UI_IMAGE`, and `CASAN_CP_OAUTH2_PROXY_IMAGE`.
|
||||
7. Keep the API on a private container/network segment with Nginx as its only caller.
|
||||
8. Restrict egress from the API to allowlisted model providers, Vault/KMS, object storage and required observability endpoints.
|
||||
9. Store state on encrypted storage; send audit heads to KMS/WORM/Object Lock.
|
||||
10. Export rate-limit, auth failure, bridge-disabled and audit-chain metrics to alerting.
|
||||
11. Back up and restore-test tenant state before enabling write actions.
|
||||
12. Run the production preflight and security suites against the exact deployment images.
|
||||
5. Mount the IdP RS256 public key and configure exact issuer/audience; coordinate
|
||||
key rotation with an API restart until JWKS rollover is implemented.
|
||||
6. Use a CA-issued certificate and a fixed production hostname.
|
||||
7. Set a digest-pinned `CASAN_CP_API_IMAGE`, `CASAN_CP_UI_IMAGE`, and `CASAN_CP_OAUTH2_PROXY_IMAGE`.
|
||||
8. Keep the API on a private container/network segment with Nginx as its only caller.
|
||||
9. Restrict egress from the API to allowlisted model providers, Vault/KMS, object storage and required observability endpoints.
|
||||
10. Store state on encrypted storage; send audit heads to KMS/WORM/Object Lock.
|
||||
11. Export rate-limit, auth failure, bridge-disabled and audit-chain metrics to alerting.
|
||||
12. Back up and restore-test tenant state before enabling write actions.
|
||||
13. Run the production preflight and security suites against the exact deployment images.
|
||||
|
||||
## Known residual risks
|
||||
|
||||
- Local bridge authorization is bearer-token based; a process with access to the token file can call it.
|
||||
- In-memory rate windows reset when the API or bridge restarts. Production should also rate-limit at ingress.
|
||||
- Goal output is stored in tenant-scoped local state but is not currently envelope-encrypted as a whole.
|
||||
- A compromised container on the private Control Panel network may attempt to forge proxy headers. Production network policy must keep unrelated workloads off that network.
|
||||
- Static public-key rotation requires a coordinated file replacement and API
|
||||
restart; automated JWKS rollover is not implemented.
|
||||
- A compromised ingress container can interfere with availability or bearer
|
||||
forwarding, but cannot mint a valid IdP signature without the IdP key.
|
||||
- Developer account subscriptions have provider-specific quotas and are not an availability SLA.
|
||||
- The local mock IdP and self-signed TLS do not prove enterprise SSO readiness.
|
||||
|
||||
@@ -83,4 +94,3 @@ packages/casan-harness/scripts/bash/local-full.sh start
|
||||
This terminates the bridge, deletes the old token and creates a new one. Then inspect `tmp/control-panel-local/auth-bridge/model-audit.jsonl` for unexpected provider/status/hash activity. The log contains no raw prompts.
|
||||
|
||||
If a goal audit chain is suspected of tampering, stop new goal submissions, preserve `.specify/logs/audit/goal-orchestrator.jsonl` and its head, and compare each `prev_hash`/`record_hash` before restoring service.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user