Quickstart
This guide uses the docker-compose example from the iron-proxy repo. By the end you’ll have a running proxy that allowlists specific hosts, blocks everything else, and swaps proxy tokens for real secrets.
Prerequisites
- Docker and Docker Compose
- Git
Clone the Repo
git clone https://github.com/ironsh/iron-proxy.git
cd iron-proxy/examples/docker-composeStart the Proxy and Demo Client
docker compose upThis starts two containers on a shared bridge network:
- proxy: builds iron-proxy from source, generates a CA certificate on startup, and listens on
172.20.0.2 - client: an Alpine container that uses the proxy’s DNS and runs a series of demo requests
Watch the Output
The client runs five requests that demonstrate core functionality:
1. Allowed request. httpbin.org is in the allowlist, so the request succeeds:
> curl https://httpbin.org/get2. Blocked request. example.com is not in the allowlist:
> curl https://example.com/
# Returns 403 Forbidden3. Secret swap in Authorization header. The client sends a proxy token, and iron-proxy replaces it with the real key before forwarding:
> curl -H "Authorization: Bearer proxy-openai-abc123" https://httpbin.org/headers
# httpbin echoes back the real OPENAI_API_KEY value4. Secret swap in custom header. INTERNAL_TOKEN is configured to match all headers:
> curl -H "X-Internal: proxy-internal-tok" https://httpbin.org/headers5. Secret swap in query parameter. Query parameters are always scanned:
> curl "https://httpbin.org/get?token=proxy-openai-abc123&q=hello"Check the Audit Logs
View the proxy’s structured JSON logs:
docker compose logs proxyEach request produces a log entry like:
{
"host": "httpbin.org",
"method": "GET",
"path": "/headers",
"action": "allow",
"status_code": 200,
"duration_ms": 142,
"request_transforms": [
{
"name": "allowlist",
"action": "continue"
},
{
"name": "secrets",
"action": "continue",
"annotations": {
"swapped": [
{
"secret": "OPENAI_API_KEY",
"locations": ["header:Authorization"]
}
]
}
}
]
}Blocked requests include a rejected_by field and log at WARN level.
What Just Happened
Docker Setup
The Compose file creates a bridge network (172.20.0.0/24) with two services and a shared volume for the CA certificate:
services:
proxy:
build:
context: ../..
dockerfile: examples/docker-compose/Dockerfile
environment:
- OPENAI_API_KEY=sk-real-openai-key-do-not-share
- INTERNAL_TOKEN=real-internal-secret-value
volumes:
- certs:/certs
networks:
demo:
ipv4_address: 172.20.0.2
client:
image: alpine:latest
depends_on:
- proxy
dns:
- 172.20.0.2
volumes:
- ./client.sh:/demo/client.sh:ro
- certs:/certs:ro
entrypoint: ["/bin/sh", "/demo/client.sh"]
networks:
demo:
ipv4_address: 172.20.0.4
volumes:
certs:
networks:
demo:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24The key wiring:
dns: [172.20.0.2]on the client points all DNS lookups at the proxy. The proxy’s DNS server returns its own IP for every lookup, so all HTTP/HTTPS traffic routes through it.environmenton the proxy holds real secrets. The client never has access to these values.certsvolume is shared between both services. The proxy generates a CA cert on startup and writes it here. The client reads it so it can trust the proxy’s TLS certificates.
Proxy Config
The proxy is configured via proxy.yaml:
# Built-in DNS server. Returns proxy_ip for all lookups so
# all outbound traffic routes through the proxy.
dns:
listen: ":53"
proxy_ip: "172.20.0.2"
proxy:
http_listen: ":80"
https_listen: ":443"
# CA cert used to mint leaf certificates on the fly for TLS
# interception. The client trusts this CA via the shared volume.
tls:
ca_cert: "/certs/ca.crt"
ca_key: "/certs/ca.key"
# Transforms run in order on every request.
transforms:
# Only requests to these domains are allowed.
# Everything else gets a 403.
- name: allowlist
config:
domains:
- "httpbin.org"
# Read real secret values from the proxy container's environment.
# Each secret maps a proxy token to an env var. When the proxy
# sees a token in a request, it swaps in the real value before
# forwarding upstream.
- name: secrets
config:
source: env # read secrets from environment variables
secrets:
- var: OPENAI_API_KEY # env var on the proxy container
proxy_value: "proxy-openai-abc123" # token the client sends
match_headers: ["Authorization"] # only scan this header
match_body: false
hosts:
- name: "httpbin.org"
- var: INTERNAL_TOKEN
proxy_value: "proxy-internal-tok"
match_headers: [] # empty list = scan all headers
match_body: false
hosts:
- name: "httpbin.org"
log:
level: "info"