docs(P27): zero-trust + OIDC + WebAuthn + threat-model docs (REQ-142)
---ci--- project: orca phase: 27 milestone: v0.12 status: execute ---/ci--- docs/threat-model.md (STRIDE + OS surface + residual risks), docs/oidc.md (bundled Dex + BYO + claim mapping + offline), docs/webauthn.md (passkeys + RP ID + bootstrap sequence), docs/security-runbook.md (seal/unseal + rotation + incident response).
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
# OIDC Configuration (v0.12)
|
||||
|
||||
## Bundled Dex (default)
|
||||
|
||||
`orca auth init-idp --rp-id <cluster-domain>` bootstraps a local Dex
|
||||
on the lead, fronted by Traefik (step-ca cert). The WebAuthn connector
|
||||
provides password-free passkey registration + login.
|
||||
|
||||
## BYO External IdP
|
||||
|
||||
Set `oidc.issuer` in config to repoint to Keycloak/Authentik/Google/etc.
|
||||
The bundled Dex is bypassed; the external IdP's authenticators are used.
|
||||
|
||||
## Claim-to-Namespace Mapping
|
||||
|
||||
OIDC `sub` (subject) maps to an ACL entry. Groups (`groups` claim) map
|
||||
to group-based grants. `orca acl grant <ns> --oidc-sub <sub> --perm read`
|
||||
or `orca acl grant <ns> --oidc-group <group> --perm admin`.
|
||||
|
||||
## Offline / Air-Gapped
|
||||
|
||||
Run the bundled Dex on the lead (offline). For the single-operator
|
||||
fully-offline case, skip OIDC and rely on mTLS-only machine identity
|
||||
(no human authn needed; the operator holds the pre-staged SSH key +
|
||||
mTLS cert; no password, no token).
|
||||
|
||||
## Credentials Storage
|
||||
|
||||
`~/.orca/credentials.json` (0600). Short-lived ID token (1h) + refresh.
|
||||
The IdP issues tokens; Orca only stores them. No long-lived
|
||||
Orca-issued tokens (R-021).
|
||||
@@ -0,0 +1,31 @@
|
||||
# Security Runbook (v0.12)
|
||||
|
||||
## Master Key Seal/Unseal
|
||||
|
||||
- `orca cluster seal`: encrypts master key with OIDC-derived key;
|
||||
prints 5 Shamir shards for offline recovery.
|
||||
- `orca cluster unseal`: operator authenticates via OIDC; master key
|
||||
unwrapped into memory; zeroed on shutdown.
|
||||
- `orca cluster unseal --recovery`: if IdP lost, present 3 of 5 shards.
|
||||
|
||||
## Master Key Rotation
|
||||
|
||||
`orca secrets rotate-master [--dry-run]`: generates new master key,
|
||||
re-encrypts all namespace secrets, re-seals. Atomic + automatic rollback.
|
||||
|
||||
## Incident Response
|
||||
|
||||
1. Revoke the compromised identity (OIDC user/group or SPIFFE SVID).
|
||||
2. Rotate the master key (`orca secrets rotate-master`).
|
||||
3. Review the audit log (`orca doctor audit` verifies the hash chain).
|
||||
4. If the master key is compromised, all historical secrets are
|
||||
compromised (no forward secrecy).
|
||||
|
||||
## Sudoers Audit
|
||||
|
||||
`orca doctor proxmox` audits the `/etc/sudoers.d/orca` file against the
|
||||
expected allowlist (pct + qm with NOEXEC; apt-get/dpkg excluded).
|
||||
|
||||
## nft Audit
|
||||
|
||||
`orca doctor nft` audits the live nftables ruleset against the emitted one.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Orca Threat Model (v0.12)
|
||||
|
||||
## Overview
|
||||
|
||||
Orca is a minimalist, offline-first, CLI-first orchestration engine.
|
||||
v0.12 adopts a **zero-trust identity model** (R-021): no Orca-issued
|
||||
credentials. Human identity is exclusively OIDC; machine identity is
|
||||
exclusively mTLS/SPIFFE.
|
||||
|
||||
## R-021 — No Orca Credentials
|
||||
|
||||
Orca never issues, stores, or accepts human-identity credentials.
|
||||
- Human identity: OIDC (external IdP or bundled Dex + WebAuthn)
|
||||
- Machine identity: mTLS + SPIFFE SVIDs
|
||||
- No passwords, no Orca-issued tokens, no CA-key passphrases
|
||||
|
||||
## STRIDE Analysis
|
||||
|
||||
| Component | Spoofing | Tampering | Repudiation | Info Disclosure | DoS | Elevation |
|
||||
|-----------|----------|-----------|-------------|-----------------|-----|-----------|
|
||||
| OIDC client | mitigated by JWKS verification | — | mitigated by ID token | — | — | — |
|
||||
| WebAuthn connector | mitigated by public-key auth | — | mitigated by signed assertions | — | — | — |
|
||||
| ACL | mitigated by deny-by-default + OIDC claims | — | mitigated by audit log | — | — | mitigated by least-privilege perms |
|
||||
| Master key seal | — | mitigated by AES-256-GCM + Shamir | — | mitigated by 0600 + sealing | — | — |
|
||||
| SSH-push transport | mitigated by key auth + TOFU/pin | — | mitigated by audit | — | mitigated by rate limiting (v1.x) | — |
|
||||
| Daemon (deprecated) | mitigated by mandatory mTLS | — | mitigated by audit | mitigated by body limits | mitigated by body limits | mitigated by ACL |
|
||||
| Backup/restore | — | mitigated by HMAC signature | — | mitigated by symlink validation | — | — |
|
||||
| Audit log | — | mitigated by hash chain + append-only trigger | — | — | — | — |
|
||||
| Drift detection | mitigated by per-peer HMAC | — | — | — | — | — |
|
||||
| nftables ingress | — | — | — | — | mitigated by conntrack + rate limit | — |
|
||||
| sudoers | — | — | — | — | — | mitigated by NOEXEC + least-privilege |
|
||||
|
||||
## OS Surface
|
||||
|
||||
Orca writes to: `/etc/orca/`, `/etc/traefik/orca*`, `/etc/systemd/system/orca-*`,
|
||||
`/etc/nftables.d/orca*`, `/etc/syncthing/orca*`, `/etc/sudoers.d/orca`.
|
||||
All via SSH-push (key auth, no passwords). The `orca` system user is
|
||||
`nologin` (no shell access). Scripts run as root only for file writes
|
||||
to `/etc/` (the operator pre-stages the SSH key; no password flows).
|
||||
|
||||
## Residual Risks
|
||||
|
||||
- Legacy CA/mTLS/daemon dual-write window (v1.x closure)
|
||||
- SQLite unencrypted at rest (0600 file mode; CGO-free SQLCipher is v1.x)
|
||||
- Master key compromise compromises all historical secrets (no forward secrecy)
|
||||
- IdP loss: Shamir 3-of-5 recovery; if quorum unavailable, unrecoverable by design
|
||||
- Transport rate limiting + typed errors (v1.x)
|
||||
@@ -0,0 +1,27 @@
|
||||
# WebAuthn / Passkeys (v0.12)
|
||||
|
||||
## Overview
|
||||
|
||||
The bundled Dex uses a custom WebAuthn connector for password-free
|
||||
authentication. Passkeys are public-key credentials — the private key
|
||||
never leaves the authenticator (TPM/security key/phone Secure Enclave).
|
||||
|
||||
## Registration
|
||||
|
||||
`orca auth register` opens the browser to the Dex WebAuthn endpoint.
|
||||
After the ceremony (biometric/security key), Dex maps the credential
|
||||
ID to an OIDC `sub`. Credentials stored at
|
||||
`ClusterDir()/webauthn-credentials.db` (0600, public keys only).
|
||||
|
||||
## RP ID
|
||||
|
||||
The relying-party ID is the cluster's Traefik-served domain
|
||||
(`--rp-id` on `orca auth init-idp`). HTTPS secure context is provided
|
||||
by Traefik (step-ca cert, R-017).
|
||||
|
||||
## Bootstrap Sequence
|
||||
|
||||
1. `orca init` bootstraps the cluster CA (step-ca, mTLS-only).
|
||||
2. `orca auth init-idp` deploys Dex behind Traefik (step-ca cert).
|
||||
3. First operator registers a passkey via the mTLS-authenticated session.
|
||||
4. Subsequent operators use WebAuthn.
|
||||
Reference in New Issue
Block a user