Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

aasm proxy

Manage the aa-proxy sidecar — its lifecycle, the per-host CA trust, and log tailing. The proxy intercepts outbound HTTPS via MitM and denies traffic that fails policy, without agent code changes — one of the three enforcement mechanisms.

Synopsis

aasm proxy <SUBCOMMAND> [OPTIONS]
SubcommandPurpose
startSpawn the proxy sidecar (background or foreground).
stopStop the running proxy.
statusShow whether the proxy is running.
install-caInstall the proxy CA into the OS trust store.
uninstall-caRemove the proxy CA from the OS trust store.
logsTail the proxy log file.
revoke-credentialRevoke a brokered provider credential in the running proxy (Unix).

aasm proxy start

Spawn aa-proxy in the background (or foreground with --no-detach). The binary is resolved from $PATH, then ~/.cargo/bin — trusted, absolute locations only. A cwd-relative ./target/release fallback was deliberately removed as a security fix (AAASM-4020): resolving relative to the current working directory would let whoever controls where aasm runs substitute an attacker-planted aa-proxy.

FlagTypeDefaultDescription
--listen <LISTEN>string127.0.0.1:8899 (env AA_PROXY_ADDR)Address the proxy listens on. Must be loopback with a named port — see below.
--allow-remote-clientsflagoffState that a non-loopback --listen is intended. Does not currently permit one — see below.
--gateway <GATEWAY>stringenv AA_GATEWAY_URLGateway URL to forward policy decisions to.
--ca-dir <CA_DIR>pathenv AA_CA_DIRDirectory for CA certificate and key storage.
--no-detachflagoffRun in the foreground instead of daemonizing.
--log-file <LOG_FILE>path—Redirect proxy stdout/stderr to this file (background mode only).
aasm proxy start --listen 127.0.0.1:8899 --gateway http://localhost:50051

The listen address must be loopback, and must name its port

--listen is checked before anything is spawned and before a state file is written, so a refused start leaves nothing behind (AAASM-5348). Two addresses that used to start a proxy no longer do:

  • A non-loopback address — 0.0.0.0, a LAN address, [::]. The proxy reads intercepted traffic under a CA this machine trusts and injects your provider credentials into forwarded requests, so anything that can reach the listener can do both.
  • Port 0 — it asks the OS for any free port, but the recorded endpoint would still say 0. The proxy would bind a real port that nothing can name: aasm run refuses a port-0 endpoint, aasm proxy stop could not reach the process, and the start would report failure while the proxy kept running.

Both previously succeeded and produced an endpoint aasm run would then refuse to route a governed tool at — a proxy that worked for everything except the one job it exists to do. aasm proxy start and aasm run now apply the same test, so an address one accepts is an address the other trusts.

--allow-remote-clients states intent, and still refuses

Intent is not authorization. A proxy reachable from other hosts also needs TLS on its listener and client authentication — aa-proxy implements neither, so the flag currently changes only which refusal you get:

$ aasm proxy start --listen 0.0.0.0:8899 --allow-remote-clients
error: refusing to listen on 0.0.0.0:8899: --allow-remote-clients was given, but
a proxy reachable from other hosts also requires protection aa-proxy does not
implement: TLS on the proxy listener, client authentication and authorization.
Being reachable is not being trusted — without those, every host that can route
to 0.0.0.0:8899 is an authorized client of an interception endpoint that holds
CA material and provider credentials. Listen on a loopback address instead.

The flag exists rather than being omitted because a refusal that names the two missing protections is more useful than one that says only “not supported”, and because the guard relaxes on its own once either protection is implemented. To reach another machine’s proxy today, forward the loopback port over SSH.

AA_PROXY_ADDR is not covered by this check. The guard lives in aasm proxy start; running the aa-proxy binary directly with a non-loopback AA_PROXY_ADDR — which is what the container image and the self-hosting example do — still binds it. Tracked as AAASM-5370.


aasm proxy stop

Stop the running proxy sidecar. Takes no flags.

aasm proxy stop

aasm proxy status

Show whether the proxy sidecar is running (confirmed via a TCP connect probe).

FlagTypeDefaultDescription
--jsonflagoffEmit machine-readable JSON output.
aasm proxy status --json

aasm proxy install-ca

Install the proxy CA certificate into the OS trust store so intercepted TLS connections validate.

FlagTypeDefaultDescription
--ca-dir <CA_DIR>pathenv AA_CA_DIRDirectory where the CA certificate and key are stored.
--yesflagoffSkip the confirmation prompt.
aasm proxy install-ca --yes

aasm proxy uninstall-ca

Remove the proxy CA certificate from the OS trust store. Same options as install-ca.

FlagTypeDefaultDescription
--ca-dir <CA_DIR>pathenv AA_CA_DIRDirectory where the CA certificate and key are stored.
--yesflagoffSkip the confirmation prompt.
aasm proxy uninstall-ca --yes

aasm proxy logs

Tail the proxy log file, with optional level/time filtering.

FlagTypeDefaultDescription
-f, --followflagoffStream new log entries continuously (like tail -f).
--lines <LINES>integer50Number of lines to show from the end of the log.
--level <LEVEL>string—Filter to lines at or above this level: error, warn, info, debug.
--since <DURATION>string—Show only entries since a relative duration (e.g. 5m, 1h, 30s).
aasm proxy logs --follow --level warn --since 10m

aasm proxy revoke-credential

Revoke the provider credential the running proxy injects for a host. Every later request to that host is refused with 403 and a credential_revoked body instead of being forwarded, so the agent’s own headers are never passed through in its place. The request that is already in flight when you revoke completes.

FlagTypeDefaultDescription
--host <HOST>stringrequiredThe host whose credential to revoke, for example api.anthropic.com.
--socket <PATH>paththe proxy’s control socketControl socket of the running proxy.
--agent <ID>string—Revoke in the proxy aasm run started for this registered agent id, instead of the standalone proxy. Revokes in every launch of that agent whose proxy still answers (not only the newest), and fails if any of them cannot be reached. Cannot be combined with --socket.
aasm proxy revoke-credential --host api.anthropic.com

aasm proxy start gives the proxy a control socket and a durable revocation record beside its state file (AA_PROXY_CONTROL_SOCKET, AA_PROXY_REVOCATIONS_FILE). A revocation is written to that record, so restarting the proxy re-applies it before the proxy accepts a connection. A record that cannot be read, is writable by group or others, or has an invalid line stops the proxy from starting, because not knowing what was revoked must not read as nothing being revoked.

Exit codeMeaning
0Revoked (or already revoked) and written to the durable record.
1Nothing was revoked: no credential is configured for the host, the request was refused, or the proxy could not be reached.
3Revoked in the running proxy but not written to a durable record, so a restart can bring the credential back.

What this does and does not do:

  • It can only remove access. There is no command to install, rotate or read a credential, and nothing the command prints is derived from a secret.
  • A host with no configured credential is reported and left alone, so a mistyped host does not start refusing traffic.
  • The control socket is owner-only and refuses any peer that is not the proxy’s own user, but it does not authenticate the operator: a process running as the same user can connect. Because the protocol can only remove access, a connecting process can only deny service. A second aasm proxy start is refused while a recorded proxy is still running, and aa-proxy will not replace a control socket that something still answers on. If the state directory is not private to this user, or the socket path would be too long for a Unix socket address, the control surface is unavailable: aasm proxy start refuses to start a proxy that would broker a provider credential (AA_PROXY_PROVIDER_KEYS set), because a credential that cannot be revoked while the proxy runs must not be started silently, and otherwise starts the proxy without it and says so.
  • A per-launch proxy started by aasm run has a control socket inside its own private launch directory, reached with --agent. That proxy lives for one launch and is never restarted, so it keeps no durable record: revoking there exits 3 (revoked in the running proxy, memory only), which is accurate and expected. A later aasm run starts from whatever credentials it is given, so stop provisioning a credential to stop it reaching future launches. --agent finds sockets by directory name under the launch state directory, trusting only directories this user owns and nobody else can write, and revokes in every live one. That is not a defence against a process running as the same user: it can unlink the real ctl.sock and bind its own, which leaves the real proxy unreachable while the impostor answers “revoked”. --agent and --socket do not verify who answers, because no launch record the agent cannot forge exists without a confined launch; under isolation none, revoking a per-launch proxy is best-effort against a hostile same-user agent. The default standalone form does verify: it requires the answering process to be the proxy recorded in the state file, and refuses without sending anything otherwise. Even that is bounded by the existing proxy trust model, which a same-user process that can forge the state file can still defeat. When the launch directory’s socket path is too long for a Unix socket address (about 100 bytes), a launch that brokers a provider credential uses a short socket under /tmp/aa-ctl-<uid>/ instead, named from the launch directory so --agent finds it again. That directory is created owner-only and checked on every use (a real directory, not a symlink, owned by this user, no group or other access); one that fails the check is refused, never adopted. A launch that brokers a credential is refused unless a working revoke path exists: after the proxy reports ready it must answer a ping as the very process aasm started, otherwise it is stopped and the launch fails. A launch that brokers no credential keeps the old behaviour (a control socket when the launch directory path fits, none otherwise, and no extra directory is created). If aasm is killed hard, a leftover fallback socket file can remain; discovery ignores it unless its launch directory exists.
  • aasm run and aasm proxy ... take the operator’s provider keys from AA_PROXY_PROVIDER_KEYS, overwrite the exec-time copy in their own process, remove the variable from the governed tool’s and the proxy’s environment, and hand the keys to aa-proxy once over its standard input. This keeps the keys out of ps -Eww and /proc/<pid>/environ, which any process of the same user can read. It does not stop a same-user process that attacks actively (a debugger where permitted, killing or replacing the proxy), it does not scrub other aasm commands, and an aa-proxy started directly still reads the environment variable (with a warning). A separate user or a sandbox backend is the real boundary.

Last updated: 2026-10-28 by Chisanan232