41499e069d
Fingerprint map + pure resolver (account umbrella / key-level scope rule), live Warp provider on warp-* structures, broker lifecycle (up/down/cycle/exec/routes/status/bind), wireguard+socks boilerplate stubs, agent-manager bind integration. CLI carries emails and fingerprints only; key bytes never appear. 41 committed tests.
66 lines
3.0 KiB
Markdown
66 lines
3.0 KiB
Markdown
# Identity Plane — per-scope network identity for runtimes
|
|
|
|
Runtimes are sandboxed to centrally-managed network identities keyed by
|
|
auth scope. Compute lives in scripts, never in agent runtimes:
|
|
attestation runs outside-in (pid → session → harness scans assign
|
|
scope; runtimes never claim it).
|
|
|
|
## Model
|
|
|
|
- **Grouping level = account api origin** (email-anchored). One oauth
|
|
subject, or one main account behind several API keys, is a group.
|
|
- **Isolation unit = api token.** Lookup resolves `api_key →
|
|
account_origin(s)`; one origin rolls scope UP to the umbrella
|
|
account, two or more (openrouter + provider) keep scope DOWN at the
|
|
key itself. The account is master; the key is never authoritative
|
|
about its own scope.
|
|
- **Cycling follows the scope unit.** Rotation is the priority
|
|
mechanism; a cycle provisions a fresh identity for whatever the
|
|
scope unit is.
|
|
- **Keys referenced by fingerprint** (`sha256:<64hex>`) in the
|
|
checked-in map. Key bytes never appear in the map, state, code
|
|
paths, or CLI output. CLI shows emails and fingerprints only.
|
|
|
|
## Files
|
|
|
|
- `identity-map.json` (tracked): `{accounts: {email: {keys:
|
|
[{fp, origins[], label?}]}}}`. Fingerprints via
|
|
`identity-resolve.py fp`. Top-level `_` entries are doc-only.
|
|
- `identity-state.json` (gitignored runtime state): scope →
|
|
label/provider/netns assignment + run bindings.
|
|
- `bin/identity-resolve.py`: pure resolver + `fp` / `lookup` / `check`.
|
|
- `bin/identity-provider.py`: `Provider` interface, real
|
|
`WarpProvider`, boilerplate `GenericWireGuardProvider` and
|
|
`SocksProxyProvider`.
|
|
- `bin/identity-broker.py`: lifecycle (`up/down/cycle/exec/routes/
|
|
status/bind`). `--map` / `--state` select files.
|
|
- `tests/test_identity_plane.py`: resolver, provider shapes, broker
|
|
transitions, CLI flags — stubbed runners only.
|
|
|
|
## Warp provider (live)
|
|
|
|
Built on established structures: identity via
|
|
`netvm-new-identity.sh` (operator-authorized 2026-10-03), netns via
|
|
`netvm-node-up.sh` / `netvm-node-down.sh` (`warp-<label>`), exec via
|
|
`netvm-exec.sh`. Scopes are NOT nodes: no chrome-box profile, no
|
|
NODES.md entry. Labels fit `^[a-z0-9][a-z0-9-]{0,22}$` as
|
|
`id-<slug>`; slugs derive deterministically from the scope unit.
|
|
|
|
Security boundaries: this code never reads `/etc/netvm` (confs are
|
|
consumed only by root tools inside netns setup) and never prints key
|
|
material. `cycle` removes the old conf before provisioning; when
|
|
removal is denied it fails closed with the exact human step.
|
|
|
|
## Known limits / deferred stages
|
|
|
|
- Consumer Warp shares one egress IP across distinct identities
|
|
(verified live; see `docs/WARP-EGRESS-FIX.md`). Cycling rotates
|
|
identity keys, not egress IPs, until egress isolation lands or a
|
|
non-warp provider implements.
|
|
- v1 scopes NETWORK identity only. Short-lived brokered credential
|
|
issuance (runtimes holding no raw keys) is deferred; harnesses
|
|
receive keys through existing means.
|
|
- `bind` attributes agent-manager scans to scopes by session name;
|
|
pid-anchored continuous attestation (re-verify bindings on every
|
|
refresh) is future work.
|