sand-boxer/docs/bwrap-credentials.md
tegwick 23d0c2b34d
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
feat: return combined bwrap runtime candidate to Glas
Answer the GLAS-WP-0015 handoff for SAND-WP-0015-T04 without activating any
production path.

Add candidate profile profile.claude-agent-dev-proof v1.1.0 (ext.bwrap,
localhost-only, default: deny, declared api.anthropic.com:443) for GLAS-WP-0012
review. The committed profile grants no egress by itself — ext.bwrap refuses it
unless owner extension config independently allowlists the destination — and a
regression test asserts that fail-closed default.

Reconcile the differing project examples in favour of the acceptance runner's
actor agt / project glas-local-proof, keeping the documented credential route
bound to that single project rather than broadening it.

Record the return contract (profile revision, host scope, consumer tuple,
runtime digest and mount paths, declared egress, value-free denial/cleanup
receipts) in docs/bwrap-runtime.md.

T04 stays wait: Claude credential lane, owner machine authentication, pinned
Claude executable and real-model acceptance remain operator gated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjyScPKb8MV8y2VZHGFSSV

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 716401@bnt-lap001
Assistant-Session: 0d02392b-d4a8-4fed-98e3-32333f768169
2026-09-06 20:34:51 +02:00

75 lines
3.7 KiB
Markdown

# Bwrap owner credential delivery
Nonempty exec credential references now require an explicit owner-configured
route. Unknown or multiple references refuse. Empty references run without
credential acquisition. The owner binds exact allowed profile IDs, projects,
actors and a nonempty run ID before starting its configured exec provider.
These bindings are additional to manager/API consumer authentication.
The provider prefix is an absolute executable plus arguments ending in `--`.
It must implement exec-env delivery: consume its own approval and authentication,
inject ANTHROPIC_API_KEY only into the supplied child, and return the child's
exit status. The supplied child is sand-boxer's fixed host helper, not the
caller command. Its request travels on stdin; key values never travel on argv.
Only the helper sends the key over the private owner Unix channel into the
namespace broker. No key or OpenBao token is returned through the public API.
Owner extension configuration has this shape (proposal only):
```yaml
credential_routes:
glas-claude-agent-dev-anthropic:
profiles: [profile.claude-agent-dev-proof]
projects: [glas-local-proof]
actors: [agt]
exec_argv:
- /absolute/owner/venv/bin/python
- -m
- secrets_engine.cli
- exec
- --catalog
- glas-claude-agent-dev-anthropic
- --field
- ANTHROPIC_API_KEY
- --mode
- exec-env
- --auth
- service-jwt
- --
```
The consumer tuple is exactly `actor: agt`, `project: glas-local-proof`,
`profile.claude-agent-dev-proof` — the identity the Glas real acceptance runner
presents. The earlier `glas-harness` example in this document was a generic
consumer illustration, not a reviewed binding, and is superseded here. The route
stays bound to that single project; it is not broadened to every Glas project,
and `glas-harness` remains only a generic consumer name in unrelated fixtures.
Do not install this example until the exact provider runtime, service identity,
approval contract and profile exist and are reviewed. No production route is
configured by this change. Owner config is trusted executable configuration;
API callers cannot change it. The parent shell's ANTHROPIC_API_KEY and
ANTHROPIC_AUTH_TOKEN are removed before provider invocation, so missing owner
acquisition cannot silently become interactive-shell delivery.
The broker injects only ANTHROPIC_API_KEY, validates nonempty bounded values,
and redacts exact byte sequences from stdout/stderr before truncation. A second
exec without a credential route has no key. Provider output is bounded and
captured; its errors are replaced by fixed messages. Envelope duration is the
command timeout plus 30 seconds of provider/cleanup budget. Provider failure or
invalid JSON refuses; SIGTERM and then SIGKILL bound stuck provider processes.
Engine/backend token revocation remains the provider's responsibility.
This is a delivery boundary for a trusted workload. It cannot prevent arbitrary
workload code from encoding the key, writing it into an artifact, or using it
against an allowed provider. Exact-output redaction is a backstop, not protection
against hostile code; artifact checks, profile admission and enforced egress
remain necessary. No key is written by the delivery mechanism itself.
Proof: scripts/smoke-bwrap-credentials.py uses a synthetic provider and a real
bwrap namespace. Sandbox 0e5fb35a proved child-only delivery, output redaction,
no leak into the next exec, wrong-project denial and teardown. No live OpenBao
or provider credential is involved. This does not activate CCR-2026-0016.
Native adoption is tracked in secrets-engine/SECRETS-WP-0009; production exec
currently refuses before OpenBao while exact-action authorization and engine
service authority are unavailable.