A lightweight CrowdSec bouncer for Envoy Proxy using the ext_authz (external authorization) filter.
This project provides a seamless way to integrate CrowdSec with Envoy to block malicious IP addresses before they reach your internal services. The bouncer uses CrowdSec's Local API (LAPI) to receive ban decisions and respond to Envoy's external authorization calls.
This bouncer:
- Subscribes to ban decisions from CrowdSec's LAPI via live stream.
- Extracts the client IP from incoming requests.
- Validates the IP against the cached ban list.
- Returns a
403 Forbidden
to Envoy for banned IPs, or200 OK
if the IP is clean.
sequenceDiagram
participant Client
participant Envoy as Envoy Proxy
participant Bouncer as Envoy Bouncer
Client->>Envoy: HTTP Request
Envoy->>Bouncer: ext_authz Check
Note over Bouncer: Extract client IP
alt IP is banned
Bouncer->>Envoy: 403 Forbidden
Envoy->>Client: Blocked
else IP is clean
Bouncer->>Envoy: 200 OK
Envoy->>Client: Allow Request
end
go install github.com/kdwils/envoy-proxy-bouncer@latest
The bouncer can be configured using:
- Configuration file (YAML or JSON)
- Environment variables
- Command line flags
Create a config.yaml
file:
server:
port: 8080 # optional (defaults to 8080)
logLevel: "info" # optional (defaults to info)
bouncer:
apiKey: "your-crowdsec-bouncer-api-key" # required
apiURL: "http://crowdsec:8080" # required
metrics: true # optional (defaults to false) - report metrics to the LAPI instance
trustedProxies: # optional (defaults to 127.0.0.1, ::1)
- 192.168.0.1 # IPv4
- 2001:db8::1 # IPv6
- 10.0.0.0/8 # CIDR range
- 100.64.0.0/10 # CIDR range
tickerInterval: "10s" # optional (defaults to 10s) - how often to check for ban decisions from the LAPI stream
Run with config file:
envoy-proxy-bouncer serve --config config.yaml
All configuration options can be set via environment variables using the prefix ENVOY_BOUNCER_
and replacing dots with underscores:
# Server configuration
export ENVOY_BOUNCER_SERVER_PORT=8080
export ENVOY_BOUNCER_SERVER_LOGLEVEL=debug
# Bouncer configuration
export ENVOY_BOUNCER_BOUNCER_APIKEY=your-api-key
export ENVOY_BOUNCER_BOUNCER_APIURL=http://crowdsec:8080
export ENVOY_BOUNCER_BOUNCER_TRUSTEDPROXIES=192.168.0.1,10.0.0.0/8
export ENVOY_BOUNCER_BOUNCER_TICKERINTERVAL=5s
The configuration is loaded in the following order (last wins):
- Default values
- Configuration file
- Environment variables
- Command line flags
The following configuration options are required:
bouncer.apiKey
: CrowdSec bouncer API keybouncer.apiURL
: CrowdSec API URL
server:
port: 8080
logLevel: "info"
bouncer:
metrics: false
trustedProxies:
- "127.0.0.1"
- "::1"
tickerInterval: "10s"
- Generate an API key from your LAPI instance:
sudo cscli bouncers add envoy-bouncer
- Set the key as an environment variable with your LAPI host:
export ENVOY_BOUNCER_BOUNCER_APIKEY=<your-api-key>
export ENVOY_BOUNCER_BOUNCER_APIURL=<your-lapi-host>
envoy-proxy-bouncer serve
# Test if an ip is banned (multiple IPs can be specified)
envoy-proxy-bouncer bounce -i 192.168.1.1,10.0.0.1
# Manual gRPC request test
grpcurl -plaintext -d @ localhost:8080 envoy.service.auth.v3.Authorization/Check < request.json
An examle request would look like:
{
"attributes": {
"source": {
"address": {
"socketAddress": {
"address": "192.168.1.100",
"portValue": 50555
}
}
},
"request": {
"http": {
"headers": {
"x-forwarded-for": "192.168.1.100, 10.0.0.1"
}
}
}
}
}
Build and run with Docker:
# Build
docker build -t envoy-proxy-bouncer .
# Run
docker run -p 8080:8080 \
-v $(pwd)/config.yaml:/app/config.yaml \
envoy-proxy-bouncer
The bouncer checks for ip addresses in the following order:
- Configured headers (in order specified in config)
- Request's RemoteAddr
For X-Forwarded-For headers with multiple IPs the bouncer uses the first (rightmost) non-trusted ip. For this reason, it is recommended to configure the bouncer with trusted proxies.
- 200 OK: Request allowed
- 403 Forbidden: Request blocked by CrowdSec decision
- 500 Internal Server Error: Bouncer configuration or runtime error
# Run tests
go test ./...
# Build from source
go build -o envoy-proxy-bouncer
starting a shell with the project dependencies:
nix develop .
The bouncer reports metrics to CrowdSec's dashboard including:
- Total requests processed
- Number of requests bounced
These are opt-in and can be enabled by setting metrics: true
in the bouncer config.
From cscli
cscli metrics
I have personally only tested this in a kubernetes cluster with Envoy Gateway installed. If there are other environments that aren't working, feel free to open an issue and i'll try to help.
The bouncer can be deployed in a Kubernetes cluster alongside Envoy Gateway: An flat yaml example lives here.
Add the Helm repository:
helm repo add envoy-proxy-bouncer https://kdwils.github.io/envoy-proxy-crowdsec-bouncer
helm repo update
Install the chart:
helm install bouncer envoy-proxy-bouncer/envoy-proxy-bouncer \
--set crowdsec.apiKey=<your-api-key> \
--set crowdsec.apiURL=<your-crowsdsec-host>:<port>
Acknowledgements:
- Helms schema generated with helm-values-schema-json