Skip to main content

Crate ironflow_auth_proxy

Crate ironflow_auth_proxy 

Source
Expand description

§ironflow-auth-proxy

HTTP service that keeps the Claude credential out of ironflow agent pods.

The worker (K8sEphemeralProvider::auth_proxy) asks the admin API for an opaque token bound to one run and one step, and hands only that token to the pod. Claude Code sends it as Authorization: Bearer to this proxy, which swaps it for the real credential and relays the request to api.anthropic.com, streaming the answer back.

The same mechanism keeps other secrets (a GitHub or GitLab token, an API key) out of the pod: a grant can hold a proxied secret with a host allowlist instead of the Claude credential. The pod calls /r/<host>/<path> with its opaque token (as Authorization: Bearer, x-api-key, Private-Token or the password of Authorization: Basic), and the proxy relays to https://<host>/<path> with the real secret injected the way the grant says (bearer, Private-Token, x-api-key, a named header or Basic). A host outside the allowlist (exact names or a leading *., no port, no IP) gets a 403, so does a Claude token on /r/ and a secret token on the Anthropic API. Redirects are returned to the pod, never followed.

One listener serves:

  • GET /healthz - liveness;
  • GET /metrics - Prometheus metrics, when a recorder handle is given (AuthProxyState::with_metrics): REQUESTS_TOTAL counts the /r/ requests by secret name and result;
  • /admin/v1/... - token issuance and revocation, behind Authorization: Bearer <IRONFLOW_AUTH_PROXY_ADMIN_KEY>;
  • /r/<host>/<path> - the relay of proxied secrets: an unknown, expired or revoked token gets a 401, a host outside the allowlist or a path with .., // or percent-encoding a 403, CONNECT, TRACE or OPTIONS a 405. Each request logs one secret relay event with its result (relayed, forbidden_host, forbidden_path, forbidden_method, unknown_token, expired, revoked, upstream_error, unavailable);
  • anything else - the Anthropic relay: an unknown, expired or revoked token gets a 401, a path outside /v1/ or a request for another host a 403, a method other than GET/POST a 405.

Grants live in a registry with two backends:

  • in memory (default): a single replica, tokens lost on restart;
  • PostgreSQL, when DATABASE_URL_ENV is set (registry_from_config): shared by several replicas and surviving restarts. Only the token SHA-256 is stored, never the token, and the credential is AES-256-GCM encrypted at rest with the IRONFLOW_SECRET_KEYS key ring.

Logs never contain a token, a credential, a secret, a header or a query string, only the short token id.

§Examples

use std::env::var;
use std::time::Duration;

use ironflow_auth_proxy::{
    AuthProxyConfig, AuthProxyState, DATABASE_URL_ENV, registry_from_config, serve, spawn_purge,
};
use ironflow_store::crypto::KeyRing;
use tokio::net::TcpListener;

let database_url = var(DATABASE_URL_ENV).ok();
let registry = registry_from_config(database_url.as_deref(), KeyRing::from_env()?).await?;
let config = AuthProxyConfig::new("0123456789abcdef0123456789abcdef");
let state = AuthProxyState::with_registry(config, registry)?;
let purge = spawn_purge(state.registry().clone(), Duration::from_secs(60));
let listener = TcpListener::bind("0.0.0.0:8080").await?;
serve(listener, state).await?;
purge.abort();

Structs§

AuthProxyConfig
Configuration of the proxy. Its Debug output never shows the admin key.
AuthProxyState
Shared state of the proxy: the token registry, the configuration and the upstream HTTP client. Cheap to clone.

Enums§

RegistryConfigError
Why the token registry could not be built. No variant carries the database URL, a key or a credential.

Constants§

DATABASE_URL_ENV
Environment variable holding the PostgreSQL URL of the shared token registry. Unset (or empty), tokens live in memory.
DEFAULT_MAX_BODY_BYTES
Default largest request body relayed: 32 MiB.
MIN_ADMIN_KEY_LEN
Shortest admin key accepted.
REQUESTS_TOTAL
Prometheus counter of the requests to the /r/ relay, labelled by secret (its name, empty for an unknown token) and result.

Functions§

registry_from_config
Build the token registry: in memory when database_url is None or blank, otherwise shared in PostgreSQL, the credentials encrypted with key_ring. Opening the database runs the store migrations.
router
The proxy router: health, metrics, admin API and relays.
serve
Serve the proxy on listener until ctrl-c or SIGTERM, letting in-flight requests finish.
spawn_purge
Spawn a task dropping the expired grants of registry every interval.