Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

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 kubectl and helm configured
  • A checked-out copy of the iron-proxy repository
  • A stable IP address clients can use to reach the proxy, usually a pinned ClusterIP or LoadBalancer IP
  • 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.key

Create 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.yaml

config.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-ca

Install or upgrade:

helm upgrade --install iron-proxy ./charts/iron-proxy \
  --namespace iron-proxy \
  --values values.yaml

Use 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: TCP

Disable 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.

ValueBehaviorUse When
ca.mode: existingSecretMounts a Secret you created.Production. This is the default.
ca.mode: inlineCreates a Secret from ca.cert and ca.key.GitOps with encrypted values.
ca.mode: noneMounts 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:

  • env or envFrom for Secrets and ConfigMaps you manage
  • secretEnv for small demo secrets managed by the chart
  • extraVolumes and extraVolumeMounts for file-backed secrets, gRPC client certificates, and GCP keyfiles
  • serviceAccount.annotations for 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.com

Metrics

The metrics listener is enabled by default on port 9090. To create a Prometheus Operator ServiceMonitor, enable:

metrics:
  serviceMonitor:
    enabled: true
    labels:
      release: prometheus

Verify 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.yaml

After 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/healthz

Important Values

ValueDefaultDescription
modestandalonestandalone or managed.
replicaCount1Number of proxy replicas. Use a shared Service IP and identical stateless config when scaling.
image.repositoryironsh/iron-proxyContainer image repository.
image.tagchart app versionContainer image tag. Pin a released version for production.
configsample configStandalone-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.modeexistingSecretexistingSecret, inline, or none.
ca.existingSecret""Secret with ca.crt and ca.key. Required for existingSecret mode.
service.typeClusterIPKubernetes Service type.
service.clusterIP""Static ClusterIP. Usually matches proxy_ip.
listeners.*variesEnabled state, port, and protocol for each listener.
serviceAccount.annotations{}Cloud identity annotations for secret backends.
resources{}Pod resource requests and limits.
metrics.serviceMonitor.enabledfalseCreate a Prometheus Operator ServiceMonitor.