Deploy on Kubernetes
Use the iron-proxy Helm chart to run iron-proxy as a Kubernetes Deployment with a Service, health probes, optional Prometheus scraping, and either standalone or control-plane managed configuration.
The chart lives in the iron-proxy repository under charts/iron-proxy.
Prerequisites
- A Kubernetes cluster with
kubectlandhelmconfigured - A checked-out copy of the
iron-proxyrepository - A stable IP address clients can use to reach the proxy, usually a pinned
ClusterIPorLoadBalancerIP - A stable CA certificate and key if you use MITM TLS mode
Install In Standalone Mode
Standalone mode renders .Values.config into a ConfigMap and starts iron-proxy with that file. This is the default mode.
Generate a CA once and store it in a Secret:
iron-proxy generate-ca -outdir ./ca -name "Acme egress CA"
kubectl create namespace iron-proxy
kubectl -n iron-proxy create secret generic iron-proxy-ca \
--from-file=ca.crt=./ca/ca.crt \
--from-file=ca.key=./ca/ca.keyCreate a values.yaml file:
mode: standalone
service:
type: ClusterIP
clusterIP: 10.96.10.10
ca:
mode: existingSecret
existingSecret: iron-proxy-ca
config:
dns:
proxy_ip: "10.96.10.10"
passthrough:
- "*.cluster.local"
- "*.svc"
tls:
mode: "mitm"
ca_cert: "/etc/iron-proxy/tls/ca.crt"
ca_key: "/etc/iron-proxy/tls/ca.key"
transforms:
- name: allowlist
config:
domains:
- "api.openai.com"
- "api.anthropic.com"
log:
level: "info"Install the chart from the repository checkout:
helm install iron-proxy ./charts/iron-proxy \
--namespace iron-proxy \
--values values.yamlconfig.dns.proxy_ip must match the address clients use to reach the proxy. For in-cluster DNS interception, pin service.clusterIP and use the same value for config.dns.proxy_ip.
Install In Managed Mode
Managed mode connects iron-proxy to the control plane. The proxy authenticates with a bearer token, then pulls transforms, secrets, and routing policy from the control plane. The chart does not render a proxy.yaml in this mode.
Create a Secret with the proxy token:
kubectl -n iron-proxy create secret generic iron-proxy-token \
--from-literal=token="$IRON_PROXY_TOKEN"Create a managed-mode values.yaml file:
mode: managed
service:
type: ClusterIP
clusterIP: 10.96.10.10
managed:
existingTokenSecret: iron-proxy-token
tokenSecretKey: token
controlPlaneURL: https://api.iron.sh
proxyIP: "10.96.10.10"
logLevel: info
ca:
mode: existingSecret
existingSecret: iron-proxy-caInstall or upgrade:
helm upgrade --install iron-proxy ./charts/iron-proxy \
--namespace iron-proxy \
--values values.yamlUse managed.controlPlaneURL when the proxy should talk to a self-hosted iron-control instance instead of the hosted control plane.
Listener Ports
The listeners block is the single source of truth for ports. Each enabled listener is exposed on the Service, exposed as a container port, and passed to iron-proxy as a bind address.
listeners:
dns:
enabled: true
port: 53
protocol: UDP
http:
enabled: true
port: 80
protocol: TCP
https:
enabled: true
port: 443
protocol: TCP
metrics:
enabled: true
port: 9090
protocol: TCP
tunnel:
enabled: true
port: 8080
protocol: TCP
postgres:
enabled: false
port: 5432
protocol: TCP
management:
enabled: false
port: 9092
protocol: TCPDisable listeners.dns.enabled when clients use explicit HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY settings instead of DNS interception. When DNS is disabled, proxy_ip is not required.
The container runs as non-root and uses NET_BIND_SERVICE so it can bind ports 53, 80, and 443. If your cluster policy forbids that capability, move the listeners to ports above 1024.
CA Modes
MITM mode requires a CA certificate and private key. Clients must trust the CA certificate.
| Value | Behavior | Use When |
|---|---|---|
ca.mode: existingSecret | Mounts a Secret you created. | Production. This is the default. |
ca.mode: inline | Creates a Secret from ca.cert and ca.key. | GitOps with encrypted values. |
ca.mode: none | Mounts no CA. | SNI-only mode or a config that points elsewhere. |
For SNI-only mode:
ca:
mode: none
config:
tls:
mode: "sni-only"Managed mode uses managed.tlsMode: sni-only instead of config.tls.mode.
Secrets And Cloud Identity
Use standard Kubernetes Secret and identity mechanisms for credentials that iron-proxy needs at runtime:
envorenvFromfor Secrets and ConfigMaps you managesecretEnvfor small demo secrets managed by the chartextraVolumesandextraVolumeMountsfor file-backed secrets, gRPC client certificates, and GCP keyfilesserviceAccount.annotationsfor EKS IRSA or GKE Workload Identity
Example:
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: upstream-api-keys
key: openai
config:
transforms:
- name: secrets
config:
secrets:
- source:
type: env
var: OPENAI_API_KEY
inject:
header: Authorization
formatter: "Bearer {{ .Value }}"
rules:
- host: api.openai.comMetrics
The metrics listener is enabled by default on port 9090. To create a Prometheus Operator ServiceMonitor, enable:
metrics:
serviceMonitor:
enabled: true
labels:
release: prometheusVerify The Release
Check the rendered manifests before installing:
helm lint ./charts/iron-proxy
helm template iron-proxy ./charts/iron-proxy \
--namespace iron-proxy \
--values values.yamlAfter installing, check the Service and health endpoint:
kubectl -n iron-proxy get svc iron-proxy
kubectl -n iron-proxy port-forward svc/iron-proxy 9090:9090
curl http://localhost:9090/healthzImportant Values
| Value | Default | Description |
|---|---|---|
mode | standalone | standalone or managed. |
replicaCount | 1 | Number of proxy replicas. Use a shared Service IP and identical stateless config when scaling. |
image.repository | ironsh/iron-proxy | Container image repository. |
image.tag | chart app version | Container image tag. Pin a released version for production. |
config | sample config | Standalone-mode iron-proxy config rendered into proxy.yaml. |
configExistingConfigMap | "" | Existing ConfigMap with a proxy.yaml key. |
managed.existingTokenSecret | "" | Existing Secret that holds the proxy token. |
managed.proxyIP | "" | Required in managed mode when DNS is enabled. Sets IRON_DNS_PROXY_IP. |
ca.mode | existingSecret | existingSecret, inline, or none. |
ca.existingSecret | "" | Secret with ca.crt and ca.key. Required for existingSecret mode. |
service.type | ClusterIP | Kubernetes Service type. |
service.clusterIP | "" | Static ClusterIP. Usually matches proxy_ip. |
listeners.* | varies | Enabled state, port, and protocol for each listener. |
serviceAccount.annotations | {} | Cloud identity annotations for secret backends. |
resources | {} | Pod resource requests and limits. |
metrics.serviceMonitor.enabled | false | Create a Prometheus Operator ServiceMonitor. |