iron-proxy
github.com/paradigmxyz/iron-proxy- Category
- Cybersecurity
- Rank
- No. 1050Tools index
Previous survey · No. 1066 ·
- Pricing
- Open Source
- Type
- TOOL
- Use case
- Security & Identity
- Builder
- @gakonst
- GitHub
- 854 stars
- Latest release
- v0.56.0
- Date
About
iron-proxy is a man-in-the-middle egress proxy that sits at the network boundary of untrusted workloads such as CI jobs, AI coding agents, and sandboxed containers. It enforces a default-deny policy so a workload can only reach explicitly allowlisted destinations, terminating TLS with on-the-fly certificates and shipping its own DNS server. Its distinguishing feature is boundary-level secret injection: the workload holds only a proxy token, and the real credential is swapped in after the request leaves the sandbox, with every request written to a structured audit log.
What it does
A single Go program that stands between a sandboxed job and the internet and decides what traffic gets out. Containers point their DNS at it, so every hostname resolves to the proxy. It then decrypts HTTPS using certificates it signs on the spot from a CA you supply, runs each request through an ordered chain of rules, and forwards only what passes. That chain can block hosts, turn placeholder credentials into real ones pulled from environment variables, AWS or 1Password, and log every decision as JSON. Optional extras police MCP tool calls and Postgres sessions.
Why it's ranked here
The design answers a real agent problem: a prompt-injected agent can only leak a placeholder token, because the real key is added after the request leaves the sandbox. The code backs that pitch with specifics. Cloud metadata addresses and loopback are refused by default even for allowed hosts, managed deployments refuse traffic until their first config arrives, and MCP calls are checked on every POST whatever content type the client declares. It is Apache 2.0 licensed, ships as one binary or Docker image, and publishes a private disclosure address with a PGP key. A narrow tool, defended in depth, for a gap its README says most teams cannot see.
What's good
Secrets work in two modes. Inject mode adds the header itself, so the client sends nothing. Replace mode swaps a placeholder and can reject any request that lacks it, which stops a workload from slipping in a different credential. Header names keep their exact casing on the wire, which matters for vendors that reject the normalised form. The allowlist has a warn mode that logs would-be blocks without breaking traffic, a sensible way to roll rules out. The MCP policy goes past blocking calls: it limits tools by argument values and strips disallowed tools from the list the agent sees, including on streaming responses.
Tradeoffs
Full inspection means every client container must trust a CA whose private key sits on the proxy. The no-CA mode sees only hostnames, so credential swapping has nothing to act on. For stronger enforcement than DNS redirection, the README itself recommends adding firewall rules. Behind a corporate upstream proxy, the address deny list checks that proxy rather than the final target, and raw tunnels still dial directly; the example config says so. Postgres protection breaks unless PgBouncer runs in session mode. Request bodies buffer to 1 MiB by default, and a larger MCP call is refused. In managed mode, audit logs default to the vendor's hosted ingest service.
How to use it well
Fits teams running CI jobs or coding agents in containers who want an allowlist and credential isolation without writing Squid ACLs or Envoy filters. Start from the bundled Docker Compose demo, then run the allowlist in warn mode against real traffic before enforcing. Use replace mode with the reject-if-missing flag for every key an agent touches, and add firewall rules so a workload cannot skip the DNS redirect by dialing an IP directly. It controls outbound traffic only, by its own description; isolating what the job does inside its container is a separate problem, and domains you mark as passthrough bypass the proxy entirely.
Technical notes+
cmd/iron-proxy/main.go registers twelve built-in transforms by blank import (allowlist, annotate, awsauth, bodycapture, gcpauth, gcpidtoken, grpc, headerallowlist, hmacsign, judge, oauth, secrets), picks standalone or managed mode by whether a control-plane token is present (the -token flag or IRON_PROXY_TOKEN), and in managed mode passes Ready: managedReady(poller) so the proxy fails closed until the first sync; when the control plane supplies an ingest token, OTEL audit export defaults to the vendor's hosted logs endpoint. internal/config/config.go applies defaults (1 MiB request body cap, uncapped responses, 30s upstream header timeout, 1000-entry leaf cert LRU, 72h leaf expiry, metrics on :9090), and Validate requires dns.proxy_ip when DNS is enabled and both CA paths in mitm mode; CIDRList records Set so an explicit empty list disables the IMDS and loopback default. internal/mcp/intercept.go inspects every POST irrespective of Content-Type, denies bodies shorter than their declared Content-Length as oversize_body, filters tools/list results only for ids recorded from tools/list requests, and reads SSE through StreamingReader so a long-lived listener stream does not block; internal/mcp/policy.go defaults denials to JSON-RPC error -32001. internal/headers/headers.go writes the header map directly to bypass Go's canonicalisation. internal/hostmatch/rule.go makes host and cidr mutually exclusive per rule and requires paths to start with a slash. go.mod declares module github.com/ironsh/iron-proxy on go 1.26.1, while the catalogued repository sits under paradigmxyz; dependencies include pg_query_go for the SQL AST walk, miekg/dns, and clients for Vault, AWS Secrets Manager and SSM, and 1Password. The README lists two IPv6 metadata addresses in the default deny list; the comment in iron-proxy.example.yaml lists only one.
Observed
- License
- Apache License 2.0
- Language
- Go (module declares go 1.26.1)
- Distribution
- Single binary; Docker images on Docker Hub; prebuilt binaries for Linux and macOS on amd64 and arm64; buildable from source with go build
- Configuration
- One YAML file passed with -config, with IRON_* environment variable overrides
- Interfaces
- DNS server, HTTP/HTTPS proxy, optional CONNECT/SOCKS5 tunnel listener, optional Postgres listener, metrics endpoint, optional management HTTP API
- TLS modes
- mitm (default, clients must trust a supplied CA) or sni-only (hostname only, no CA, no TLS termination)
- Secret sources
- Environment variables, AWS Secrets Manager, AWS SSM Parameter Store, 1Password, 1Password Connect
- Default upstream deny list
- Cloud instance metadata addresses and loopback, applied even to allowlisted hosts
- MCP policy
- Per-server tool allowlist with argument constraints; disallowed tools filtered from tool listings
- Security reporting
- Private email disclosure with a PGP key, per SECURITY.md
- Integration test targets
- egress-rules.yaml allowlists AWS, GCP, 1Password, Anthropic and OpenAI endpoints for integration tests
Read from README.md, go.mod, cmd/iron-proxy/main.go, internal/config/config.go, internal/hostmatch/rule.go, internal/mcp/policy.go, internal/mcp/intercept.go, internal/headers/headers.go, egress-rules.yaml, iron-proxy.example.yaml, SECURITY.md, LICENSE.
Tags
Tech Stack
Comments (0)
No comments yet
Editorially curated, with community endorsements as a secondary signal. Corrections welcome.