docs: README + example.json for cred-proxy (PRD 0010)
- Architecture diagram gains the cred-proxy lane (agent talks plain HTTP via bearer-auth-injection; sidecar talks HTTPS to the real upstream with the manifest token). - Adds a cred-proxy entry under the sidecar bullet list, with a pointer to PRD 0010. - Manifest example illustrates the `tokens` array on a bottle. - Auth section notes that declaring an `anthropic` token routes CLAUDE_BOTTLE_OAUTH_TOKEN through the sidecar instead of into the agent's environ. - claude-bottle.example.json gains an `agentic` bottle declaring all four token kinds, plus a paired `agentic-helper` agent.
This commit is contained in:
@@ -72,11 +72,13 @@ pieces of v1.
|
|||||||
A bottle is the agent container plus up to three per-protocol egress
|
A bottle is the agent container plus up to three per-protocol egress
|
||||||
sidecars on a per-agent Docker `--internal` network. The agent has no
|
sidecars on a per-agent Docker `--internal` network. The agent has no
|
||||||
default route off-box; its only way out is through the pipelock
|
default route off-box; its only way out is through the pipelock
|
||||||
sidecar (for HTTP/HTTPS), the ssh-gate sidecar (for SSH), or the
|
sidecar (for HTTP/HTTPS), the git-gate sidecar (for git operations
|
||||||
git-gate sidecar (for git operations against declared upstreams).
|
against declared upstreams), or the cred-proxy sidecar (for API
|
||||||
Each sidecar also sits on an egress network that does have internet
|
calls that need a manifest-declared token — Anthropic OAuth, GitHub
|
||||||
access, so the agent's traffic always passes through a container
|
PAT, Gitea PAT, npm). Each sidecar also sits on an egress network
|
||||||
that enforces the manifest before it leaves the host.
|
that does have internet access, so the agent's traffic always passes
|
||||||
|
through a container that enforces the manifest before it leaves the
|
||||||
|
host.
|
||||||
|
|
||||||
```
|
```
|
||||||
host ( ./cli.py )
|
host ( ./cli.py )
|
||||||
@@ -91,12 +93,17 @@ that enforces the manifest before it leaves the host.
|
|||||||
│ │ built locally) │ │ (TLS bump, DLP,│ │ hosts
|
│ │ built locally) │ │ (TLS bump, DLP,│ │ hosts
|
||||||
│ │ │ │ allowlist) │ │
|
│ │ │ │ allowlist) │ │
|
||||||
│ │ skills, env, │ └────────────────┘ │
|
│ │ skills, env, │ └────────────────┘ │
|
||||||
│ │ ~/.gitconfig │ │
|
│ │ ~/.gitconfig, │ │
|
||||||
│ │ │ git ops ┌────────────────┐ │ SSH (push/
|
│ │ ~/.npmrc, tea │ git ops ┌────────────────┐ │ SSH (push/
|
||||||
│ │ │ ───────────────► │ git-gate image │──┼──► fetch) to
|
│ │ │ ───────────────► │ git-gate image │──┼──► fetch) to
|
||||||
│ │ │ │ (gitleaks + │ │ bottle.git
|
│ │ │ │ (gitleaks + │ │ bottle.git
|
||||||
│ │ │ │ git daemon) │ │ upstreams
|
│ │ environ: URLs │ │ git daemon) │ │ upstreams
|
||||||
│ └──────────────────┘ └────────────────┘ │
|
│ │ only, no real │ └────────────────┘ │
|
||||||
|
│ │ tokens │ bearer-auth ┌────────────────┐ │ HTTPS to
|
||||||
|
│ │ │ ───────────────► │ cred-proxy │──┼──► bottle.tokens
|
||||||
|
│ │ │ HTTP, plain │ (strips/injects│ │ upstreams
|
||||||
|
│ │ │ │ Authorization)│ │ (with the
|
||||||
|
│ └──────────────────┘ └────────────────┘ │ real token)
|
||||||
│ │
|
│ │
|
||||||
│ agent on internal network (no default route); │
|
│ agent on internal network (no default route); │
|
||||||
│ sidecars also attached to an egress network. │
|
│ sidecars also attached to an egress network. │
|
||||||
@@ -129,6 +136,20 @@ that enforces the manifest before it leaves the host.
|
|||||||
`insteadOf` rewrite still keys off the original hostname. Brought
|
`insteadOf` rewrite still keys off the original hostname. Brought
|
||||||
up only when `bottle.git` has entries. Design in
|
up only when `bottle.git` has entries. Design in
|
||||||
`docs/prds/0008-git-gate.md`.
|
`docs/prds/0008-git-gate.md`.
|
||||||
|
- **cred-proxy image** — per-bottle sidecar (`python:3.13-alpine`
|
||||||
|
base, stdlib-only) that holds API tokens declared in
|
||||||
|
`bottle.tokens`. The agent dials it as plain HTTP at
|
||||||
|
`http://cred-proxy:9099/<kind>/...`; the proxy strips any
|
||||||
|
inbound `Authorization` header, injects the configured one using
|
||||||
|
a token held only in its own container's environ, and forwards
|
||||||
|
to the real upstream over HTTPS. SSE responses stream back
|
||||||
|
unbuffered. `ANTHROPIC_BASE_URL`, `~/.npmrc`, `~/.gitconfig`
|
||||||
|
`insteadOf` rules for `https://github.com/` and any declared
|
||||||
|
Gitea hosts, and `~/.config/tea/config.yml` all get written to
|
||||||
|
point at the proxy. The agent's `printenv` shows only those
|
||||||
|
URLs — none of the real token values. Brought up only when
|
||||||
|
`bottle.tokens` has entries. Design in
|
||||||
|
`docs/prds/0010-cred-proxy.md`.
|
||||||
|
|
||||||
When the agent exits, `cli.py` tears down every sidecar that was
|
When the agent exits, `cli.py` tears down every sidecar that was
|
||||||
brought up and the two networks; nothing about a bottle persists
|
brought up and the two networks; nothing about a bottle persists
|
||||||
@@ -172,6 +193,19 @@ project entries overriding home entries on key conflict).
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Tokens declared here are held by a per-bottle cred-proxy
|
||||||
|
// sidecar, not the agent. Each entry names the host env var
|
||||||
|
// (`TokenRef`) the CLI reads at launch time; the value goes
|
||||||
|
// into the sidecar's environ via `docker create -e`, never
|
||||||
|
// touches argv or disk. Inside the bottle, the agent's
|
||||||
|
// ANTHROPIC_BASE_URL / npm registry / git insteadOf rules
|
||||||
|
// point at the proxy. See `docs/prds/0010-cred-proxy.md`.
|
||||||
|
"tokens": [
|
||||||
|
{ "Kind": "anthropic", "TokenRef": "CLAUDE_BOTTLE_OAUTH_TOKEN" },
|
||||||
|
{ "Kind": "github", "TokenRef": "GITHUB_PAT" },
|
||||||
|
{ "Kind": "npm", "TokenRef": "NPM_TOKEN" }
|
||||||
|
],
|
||||||
|
|
||||||
// Egress is forced through a per-agent
|
// Egress is forced through a per-agent
|
||||||
// [pipelock](https://github.com/luckyPipewrench/pipelock) sidecar
|
// [pipelock](https://github.com/luckyPipewrench/pipelock) sidecar
|
||||||
// on a Docker `--internal` network — without the proxy the agent
|
// on a Docker `--internal` network — without the proxy the agent
|
||||||
@@ -231,9 +265,13 @@ as `CLAUDE_BOTTLE_OAUTH_TOKEN`:
|
|||||||
export CLAUDE_BOTTLE_OAUTH_TOKEN="<token>"
|
export CLAUDE_BOTTLE_OAUTH_TOKEN="<token>"
|
||||||
```
|
```
|
||||||
|
|
||||||
`cli.py` automatically forwards it to every container as
|
By default `cli.py` forwards the token into the agent container as
|
||||||
`CLAUDE_CODE_OAUTH_TOKEN` via `docker run -e` — no manifest wiring
|
`CLAUDE_CODE_OAUTH_TOKEN`. Declare an `anthropic` entry in
|
||||||
required, and the value is never written to disk or placed on argv.
|
`bottle.tokens` to route via cred-proxy instead: the token then lives
|
||||||
|
only in the cred-proxy sidecar's environ, the agent's
|
||||||
|
`ANTHROPIC_BASE_URL` points at the proxy, and `printenv` inside the
|
||||||
|
agent does not surface the real token. Either way the value is never
|
||||||
|
written to disk or placed on argv on the host.
|
||||||
|
|
||||||
Inside the container, `claude` picks up `CLAUDE_CODE_OAUTH_TOKEN` and
|
Inside the container, `claude` picks up `CLAUDE_CODE_OAUTH_TOKEN` and
|
||||||
authenticates against your subscription. Caveats: the token is bound
|
authenticates against your subscription. Caveats: the token is bound
|
||||||
|
|||||||
@@ -36,6 +36,20 @@
|
|||||||
"files.pythonhosted.org"
|
"files.pythonhosted.org"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"agentic": {
|
||||||
|
"env": {
|
||||||
|
"GIT_AUTHOR_NAME": "Eric Diderich",
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"tokens": [
|
||||||
|
{ "Kind": "anthropic", "TokenRef": "CLAUDE_BOTTLE_OAUTH_TOKEN" },
|
||||||
|
{ "Kind": "github", "TokenRef": "GH_PAT" },
|
||||||
|
{ "Kind": "gitea", "TokenRef": "GITEA_TOKEN",
|
||||||
|
"Url": "https://gitea.dideric.is" },
|
||||||
|
{ "Kind": "npm", "TokenRef": "NPM_TOKEN" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -52,6 +66,12 @@
|
|||||||
"prompt": "You help maintain Gitea-hosted projects. Prefer small, focused commits. Follow Conventional Commits. Run tests before pushing."
|
"prompt": "You help maintain Gitea-hosted projects. Prefer small, focused commits. Follow Conventional Commits. Run tests before pushing."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"agentic-helper": {
|
||||||
|
"bottle": "agentic",
|
||||||
|
"skills": [],
|
||||||
|
"prompt": "You operate against APIs whose credentials live in a per-bottle cred-proxy sidecar. Your environ carries only proxy URLs."
|
||||||
|
},
|
||||||
|
|
||||||
"minimal": {
|
"minimal": {
|
||||||
"bottle": "default",
|
"bottle": "default",
|
||||||
"skills": [],
|
"skills": [],
|
||||||
|
|||||||
Reference in New Issue
Block a user