ironsh/iron-proxy

By ironsh

Updated 9 days ago

An egress firewall for untrusted workloads with default-deny, secret injection, and audit logging.

Image
Networking
Security
0

10K+

ironsh/iron-proxy repository overview

Quick reference

What is iron-proxy?

iron-proxy is an egress firewall for untrusted workloads. It sits between your container and the internet as a MITM proxy with a built-in DNS server, enforcing default-deny egress, injecting secrets so workloads never hold real credentials, and producing structured JSON audit logs for every request.

How to use this image

Generate a CA

iron-proxy terminates TLS by generating leaf certificates on the fly, signed by a CA you provide. Client containers must trust this CA.

$ mkdir -p certs
$ openssl genrsa -out certs/ca.key 4096
$ openssl req -x509 -new -nodes \
    -key certs/ca.key \
    -sha256 -days 3650 \
    -subj "/CN=iron-proxy CA" \
    -addext "basicConstraints=critical,CA:TRUE" \
    -addext "keyUsage=critical,keyCertSign" \
    -out certs/ca.crt

Start iron-proxy

$ docker run -d --name iron-proxy \
  -v $(pwd)/proxy.yaml:/etc/iron-proxy/proxy.yaml:ro \
  -v $(pwd)/certs/ca.crt:/etc/iron-proxy/ca.crt:ro \
  -v $(pwd)/certs/ca.key:/etc/iron-proxy/ca.key:ro \
  -e OPENAI_API_KEY=sk-real-key \
  ironsh/iron-proxy:latest -config /etc/iron-proxy/proxy.yaml

Route containers through the proxy

The simplest approach is DNS-based routing — point the container's DNS at iron-proxy and all hostname lookups resolve to the proxy IP, routing traffic through it automatically:

$ docker run --rm \
  --dns 172.20.0.2 \
  -v $(pwd)/certs/ca.crt:/usr/local/share/ca-certificates/iron-proxy.crt:ro \
  alpine sh -c "update-ca-certificates 2>/dev/null && curl https://httpbin.org/get"

For stronger enforcement, layer nftables rules to block non-proxy egress, or use TPROXY for kernel-level interception. See the examples/ directory for working setups of each approach.

Docker Compose example

services:
  proxy:
    image: ironsh/iron-proxy:latest
    command: ["-config", "/etc/iron-proxy/proxy.yaml"]
    environment:
      - OPENAI_API_KEY=sk-real-openai-key-do-not-share
    volumes:
      - ./proxy.yaml:/etc/iron-proxy/proxy.yaml:ro
      - ./certs/ca.crt:/etc/iron-proxy/ca.crt:ro
      - ./certs/ca.key:/etc/iron-proxy/ca.key:ro
    networks:
      demo:
        ipv4_address: 172.20.0.2

  client:
    image: alpine:latest
    dns:
      - 172.20.0.2
    volumes:
      - ./certs/ca.crt:/usr/local/share/ca-certificates/iron-proxy.crt:ro
    networks:
      demo:
        ipv4_address: 172.20.0.4

networks:
  demo:
    ipam:
      config:
        - subnet: 172.20.0.0/24

A full working demo with allowed, blocked, and secret-swap scenarios is available in the examples/docker-compose directory.

Configuration

iron-proxy takes a single YAML config file. See iron-proxy.example.yaml for a copy-pasteable starting point.

dns:
  listen: ":53"
  proxy_ip: "10.16.0.1"
  passthrough:
    - "*.internal.corp"

proxy:
  http_listen: ":80"
  https_listen: ":443"

tls:
  ca_cert: "/etc/iron-proxy/ca.crt"
  ca_key: "/etc/iron-proxy/ca.key"

transforms:
  - name: allowlist
    config:
      domains:
        - "api.openai.com"
        - "*.anthropic.com"

  - name: secrets
    config:
      source: env
      secrets:
        - var: OPENAI_API_KEY
          proxy_value: "proxy-token-123"
          match_headers: ["Authorization"]
          hosts:
            - name: "api.openai.com"

log:
  level: "info"
Allowlist

Default-deny. Requests must match at least one domain glob or CIDR to proceed. Unmatched requests get a 403 Forbidden.

Secret injection

Set real secrets as environment variables on the iron-proxy container. Give the workload a proxy token instead. The secrets transform scans outbound requests and replaces proxy tokens with real values before forwarding upstream — the workload never sees the real key.

License

Apache License 2.0

Tag summary

Content type

Image

Digest

sha256:1b5de5556

Size

19.7 MB

Last updated

9 days ago

docker pull ironsh/iron-proxy