diff --git a/docs/oidc.md b/docs/oidc.md new file mode 100644 index 0000000..6692415 --- /dev/null +++ b/docs/oidc.md @@ -0,0 +1,31 @@ +# OIDC Configuration (v0.12) + +## Bundled Dex (default) + +`orca auth init-idp --rp-id ` 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 --oidc-sub --perm read` +or `orca acl grant --oidc-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). diff --git a/docs/security-runbook.md b/docs/security-runbook.md new file mode 100644 index 0000000..c11aab1 --- /dev/null +++ b/docs/security-runbook.md @@ -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. diff --git a/docs/threat-model.md b/docs/threat-model.md new file mode 100644 index 0000000..d47c2e8 --- /dev/null +++ b/docs/threat-model.md @@ -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) diff --git a/docs/webauthn.md b/docs/webauthn.md new file mode 100644 index 0000000..8baf3c2 --- /dev/null +++ b/docs/webauthn.md @@ -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.