feat(identity): per-scope network identity plane (slices 1-5)
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.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user