Running behind a reverse proxy
When the Airflow webserver is reached through an ingress controller or another reverse proxy, every
request arrives from the proxy rather than from the client. Unless the webserver is told to trust
the proxy, it records the proxy’s address as the client address, and it treats a TLS-terminated
request as plain HTTP — which, among other things, means session cookies are not marked as
Secure.
Set trustedProxies on the webserver role to the addresses your proxy sends requests from:
spec:
webservers:
roleConfig:
listenerClass: external-stable
trustedProxies:
- 10.244.0.0/16 (1)
roleGroups:
default:
replicas: 1
| 1 | IP addresses (10.0.0.1), CIDR networks (10.244.0.0/16), and are accepted. must be
the only entry in the list: combining it with other entries is rejected, since it would silently
degrade to trusting only those other entries. |
On Airflow 3.x the operator starts the api-server with --proxy-headers and restricts the headers
to the listed peers. Airflow 2.x has no equivalent restriction: see
Airflow 2.x has no peer restriction.
Choosing the value
Use the narrowest range that covers your proxy, and give it as a network address (host bits zero,
e.g. 10.244.0.0/16) or as a bare host IP (no /prefix at all, e.g. 10.244.0.5).
For an ingress controller running in the cluster, list the Pod addresses as bare host IPs rather than guessing a network:
kubectl get pods -n ingress-nginx -o jsonpath='{.items[*].status.podIP}'
If your ingress controller’s Pods share a known, stable CIDR (for example a dedicated node pool or a documented Pod CIDR range for that namespace), you can use that network instead — but confirm it against your cluster’s actual CNI configuration rather than inferring it from a single Pod IP, since a Pod IP alone does not tell you where the network boundary is.
* trusts forwarded headers from any peer that can reach the webserver. Only use it when access
to the webserver is restricted by other means — with a cluster-internal or
external-unstable ListenerClass, clients reach the Pod directly and can set the headers
themselves.
| A peer that is trusted can set the client address that ends up in the webserver’s access log. Do not list ranges wider than the proxies you operate. |
Airflow 2.x has no peer restriction
Airflow 2.x’s webserver has no analogue support for trusted network addresses. Once enabled, it
unconditionally trusts X-Forwarded- from *any peer, the same as trustedProxies: ["*"] on 3.x.
This means that for Airflow 2.x, trustedProxies: [""] is the only valid configuration. Using
any other value than will lead the operator to reject reconciliation.
Interaction with overrides
On Airflow 3.x, the operator sets FORWARDED_ALLOW_IPS from this field, before envOverrides are
applied — so an envOverrides entry for that variable wins over the value derived from
trustedProxies. This override only takes effect while trustedProxies is non-empty: an empty
list means the api-server is not started with --proxy-headers at all, so uvicorn never installs
the middleware that reads FORWARDED_ALLOW_IPS, and the override has no effect regardless of its
value.
On Airflow 2.x, the same applies to AIRFLOWWEBSERVERENABLE_PROXY_FIX and
AIRFLOWWEBSERVERPROXY_FIX_X_FOR.