Changelog

View on GitHub →

New: Inject Mode for Secrets Transform

Secrets can now be injected directly onto matching requests without requiring the client to send a proxy token. In inject mode, the proxy unconditionally sets a header or query parameter on every request that matches the secret's rules. This is useful when sandboxed workloads should never see credentials at all.

A Go template formatter field controls the header value. The template receives .Value (the resolved secret) and a variadic base64 helper that concatenates and base64-encodes its arguments.

transforms:
  - name: secrets
    config:
      secrets:
        - source:
            type: env
            var: OPENAI_API_KEY
          inject:
            header: "Authorization"
            formatter: "Bearer {{ .Value }}"
          rules:
            - host: "api.openai.com"
              methods: ["POST"]
              paths: ["/v1/*"]

Inject mode also supports query parameters (omit formatter):

- source:
    type: env
    var: MAPS_API_KEY
  inject:
    query_param: "key"
  rules:
    - host: "maps.googleapis.com"

The existing replace behavior now lives under an explicit replace: block. Legacy top-level fields (proxy_value, match_headers, etc.) remain supported for backwards compatibility.

View on GitHub →

New: AWS Secrets Manager Support

Secrets can now be sourced from AWS Secrets Manager in addition to environment variables. Each secret declares its own source, so you can mix env and aws_sm entries in a single pipeline. AWS Secrets Manager entries support configurable TTL with lazy inline refresh.

Breaking change: the secrets transform config format has changed. The global source field has been removed, and each secret now declares its own source and config. Existing configs will need to be updated.

transforms:
  - name: secrets
    config:
      secrets:
        - source: env
          config:
            var: OPENAI_API_KEY
          proxy_value: "pk-proxy-xxx"
          match_headers: ["Authorization"]
          require: true
          rules:
            - host: "api.openai.com"
        - source: aws_sm
          config:
            secret_id: "arn:aws:secretsmanager:us-west-1:673698305641:secret:example-raw-secret-dgDlkC"
            region: "us-east-1"
            ttl: 5m
          proxy_value: "pk-proxy-yyy"
          match_headers: ["x-api-key"]
          rules:
            - host: "api.anthropic.com"

Fix: Wildcard Method Matching in Rules

When a rule's methods are specified as ["*"], it now matches all HTTP methods instead of literally matching the string "*".

rules:
  - host: "api.example.com"
    methods: ["*"]
View on GitHub →

New: CONNECT/SOCKS5 Tunnel Listener

An optional tunnel_listen address accepts HTTP CONNECT and SOCKS5 tunnel requests. The listener peeks at the first byte to distinguish the two protocols, runs the target through the transform pipeline (so allowlists, secrets, etc. apply), then serves traffic through the normal HTTP handler. TLS connections are MITM'd using the configured CA; plain HTTP is served directly; non-HTTP/TLS protocols are rejected.

proxy:
  tunnel_listen: ":1080"

New: require Flag on Secrets Transform

A new require boolean on each secret entry rejects requests that match the configured host but do not contain the proxy token. This prevents sandboxed workloads from bypassing the secret-swap mechanism with alternative credentials. When the proxy token is not found in any scanned location (headers, query, body), the transform returns a 403 instead of passing the request through. Default is false, preserving existing behavior.

transforms:
  - name: secrets
    config:
      source: env
      secrets:
        - var: OPENAI_API_KEY
          proxy_value: "pk-proxy-xxx"
          match_headers: ["Authorization"]
          require: true
          hosts:
            - name: "api.openai.com"
View on GitHub →

New: Annotate Transform

A new annotate transform captures HTTP request header values into audit log annotations based on host, method, and path rules. This is useful for enriching audit logs with request-specific context like request IDs.

Each annotation group specifies rules to match and headers to capture. When a request matches, the specified header values are written as header:<Name> entries in the transform trace. Requests that don't match pass through unchanged. This transform never rejects requests.

transforms:
  - name: annotate
    config:
      annotations:
        - rules:
            - host: "api.openai.com"
              methods: ["POST"]
              paths: ["/v1/*"]
          headers: ["x-request-id", "authorization"]
        - rules:
            - host: "*.anthropic.com"
          headers: ["x-api-key"]

Example audit log annotation output:

{
  "header:X-Request-Id": "req-abc123",
  "header:Authorization": "Bearer sk-ant-..."
}
View on GitHub →

New: OpenTelemetry Audit Log Export

Audit events can now be exported as structured logs via OTEL. This enables integration with observability backends like Datadog, Grafana, or any OTLP-compatible collector.

Export is enabled by setting OTEL_EXPORTER_OTLP_ENDPOINT. The following standard OTEL environment variables are supported:

VariableDescriptionDefault
OTEL_EXPORTER_OTLP_ENDPOINTOTLP collector endpoint (e.g. https://logfire-us.pydantic.dev)(none, export disabled)
OTEL_EXPORTER_OTLP_PROTOCOLTransport protocol: http/protobuf or grpchttp/protobuf
OTEL_EXPORTER_OTLP_HEADERSComma-separated key=value pairs for auth headers(none)
OTEL_RESOURCE_ATTRIBUTESComma-separated key=value resource attributes(none)
OTEL_SERVICE_NAMEService name reported in telemetryiron-proxy

New: Health Check Endpoint

A /healthz endpoint is now served on the metrics listen address (default :9090), returning 200 OK. Useful for liveness probes in container orchestrators.

New: Signed Releases

Release artifacts are now GPG-signed. The public key is included in the repo at public-key.asc.