How to Use X-Forwarded-For for IP Filtering in Traefik
When deploying applications behind proxies or load balancers, it’s important to correctly handle client IP addresses. Traefik, a popular reverse proxy and load balancer, provides a way to filter requests based on IP addresses using the X-Forwarded-For header. This is especially useful when Traefik is behind a trusted proxy or load balancer, and you want to allow or deny traffic based on the original client IP.
In this blog, we’ll walk through how to configure Traefik to filter requests based on the original client IP using the X-Forwarded-For header and the `IPAllowlist` middleware.
Why “X-Forwarded-For”?
When Traefik is behind a proxy (e.g., AWS ELB, NGINX, or another reverse proxy), the client’s IP address is often replaced by the proxy’s IP. To preserve the original client IP, the proxy adds the X-Forwarded-For header, which contains the original client’s IP address. Traefik can then use this header to make decisions based on the real client IP.
Step-by-Step Configuration
1. Enable X-Forwarded-For Support in Traefik
First, you need to configure Traefik to trust the proxy and use the X-Forwarded-For header. This can be done by enabling the forwardedHeaders.insecure option for the entry points that handle HTTP and HTTPS traffic.
In your Traefik static configuration (e.g., values.yaml for Helm), add the following arguments:
additionalArguments:
- "--entryPoints.web.forwardedHeaders.insecure"
- "--entryPoints.websecure.forwardedHeaders.insecure"
This tells Traefik to trust the X-Forwarded-For header for the web (HTTP) and websecure (HTTPS) entry points, even if the proxy is not explicitly trusted.
2. Configure the “IPAllowlist” Middleware
Next, define an IPAllowlist middleware in your dynamic configuration to filter requests based on the original client IP. This middleware inspects the `X-Forwarded-For` header and allows or denies traffic based on a specified IP allowlist.
Here’s an example of a Kubernetes Middleware resource that uses the X-Forwarded-For header to filter IPs:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ipallowlist-express
namespace: kube-system
spec:
ipAllowList:
sourceRange:
- 1.1.1.1/32
- 2.2.2.2/32
# Use the first IP in the X-Forwarded-For header (the original client IP)
ipStrategy:
depth: 1y
Key Points:
- sourceRange: This defines the list of allowed IP ranges. In this example, only the IPs `1.1.1.1` and `2.2.2.2` are allowed.
- ipStrategy.depth: This option determines which IP in the X-Forwarded-For chain to use. Setting depth: 1 means Traefik will use the first IP in the X-Forwarded-For header, which is the original client IP.
3. Apply the Middleware to Your Services
Once the IPAllowlist middleware is defined, you can apply it to your services or routes. For example, in Kubernetes, you can reference the middleware in an IngressRoute:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-app
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`myapp.example.com`)
kind: Rule
services:
- name: my-app-service
port: 80
middlewares:
- name: ipallowlist-express
namespace: kube-system
This configuration ensures that only requests from the allowed IPs (`1.1.1.1` and `2.2.2.2`) are forwarded to the my-app-service. Traefik will use the `X-Forwarded-For` header to determine the original client IP.
Summary
By combining Traefik’s IPAllowlist middleware with the X-Forwarded-For header, you can effectively filter requests based on the original client IP, even when Traefik is behind a proxy or load balancer. Here’s a quick recap of the steps:
1. Enable X-Forwarded-For support: Configure Traefik to trust the X-Forwarded-For header using the forwardedHeaders.insecure option.
2. Define the IPAllowlist middleware: Create a middleware that inspects the X-Forwarded-For header and filters requests based on an IP allowlist.
3. Apply the middleware: Attach the middleware to your services or routes to restrict access based on the original client IP.
With this setup, you can ensure that only traffic from trusted IPs is allowed, even in complex environments where multiple proxies are involved.