Configuration¶
rescaled WAF is being configured with a central YAML configuration file that needs to be provided when starting the processor.
The application accepts its configuration from the following sources (highest priority to the lowest priority):
- CLI flags
- Environment variables
- This YAML config file
- Compiled defaults
Full Configuration Example¶
server:
# Host address to listen on for gRPC requests.
host: "127.0.0.1"
# Port to listen on for gRPC requests.
port: 50051
log:
# Log level: debug, info, warn, error.
level: "info"
# Log format: json (recommended) or text.
format: "json"
# HTTP health/readiness endpoint.
health:
# Host address for the HTTP health server.
host: "127.0.0.1"
# Port for the /healthz endpoint.
port: 8081
# Feature toggles. Each feature can be independently enabled/disabled.
features:
# GeoIP geolocation lookup using a MMDB database.
geoip:
# Master toggle for the GeoIP feature.
enabled: false
# Database configuration.
database:
# Source type: "file" (local path) or "url" (HTTP download).
source: "file"
# Path to the MMDB file (required when source is "file").
path: "/data/GeoLite2-City.mmdb"
# Download URL for the MMDB file (required when source is "url").
# url: "https://example.com/GeoLite2-City.mmdb"
# How often to re-download/reload the database.
# Go duration string (e.g. "24h", "6h30m"). "0" = no refresh.
refresh_interval: "0"
# Inject X-Rescaled-Geo-* headers into upstream requests.
upstream_headers:
enabled: true
# Make GeoIP data available for policy/rule evaluation.
policy_usage:
enabled: true
# Header containing the client's real IP address.
# Default: x-envoy-external-address (set by Envoy from XFF processing).
client_ip_header: "x-envoy-external-address"
# ASN (Autonomous System Number) lookup using a MMDB database.
asn:
# Master toggle for the ASN feature.
enabled: false
# Database configuration.
database:
# Source type: "file" (local path) or "url" (HTTP download).
source: "file"
# Path to the MMDB file (required when source is "file").
path: "/data/GeoLite2-ASN.mmdb"
# Download URL for the MMDB file (required when source is "url").
# url: "https://example.com/GeoLite2-ASN.mmdb"
# How often to re-download/reload the database.
# Go duration string (e.g. "24h", "6h30m"). "0" = no refresh.
refresh_interval: "0"
# Inject X-Rescaled-ASN-* headers into upstream requests.
upstream_headers:
enabled: true
# Make ASN data available for policy/rule evaluation.
policy_usage:
enabled: true
# Header containing the client's real IP address.
# Default: x-envoy-external-address (set by Envoy from XFF processing).
client_ip_header: "x-envoy-external-address"
# Inject a response header reporting total WAF processing time in milliseconds.
processing_duration:
# Master toggle for the processing duration header.
enabled: false
# Name of the response header to inject.
header_name: "x-rescaled-processing-time-ms"
# Prometheus metrics endpoint. When enabled, serves metrics on the
# health server (same port as /healthz).
metrics:
enabled: false
# Path for the metrics endpoint.
path: "/metrics"
# Automatic challenge issuance based on accumulated request weight.
# When enabled, WEIGH rules adjust a per-request weight score during
# evaluation. If no terminal action fires and the accumulated weight
# meets or exceeds a threshold, the visitor is automatically challenged.
auto_challenge:
# Master toggle for weight-based auto-challenge.
enabled: false
# Weight thresholds. The highest threshold that the accumulated weight
# meets or exceeds is selected. Each threshold specifies the challenge
# algorithm ("metarefresh", "preact", or "pow") and difficulty (0–64).
# thresholds:
# - name: light-check
# threshold: 10
# challenge: metarefresh
# difficulty: 1
# - name: moderate-check
# threshold: 25
# challenge: preact
# difficulty: 3
# - name: heavy-check
# threshold: 40
# challenge: pow
# difficulty: 6
# IP blocking based on accumulated HIT scores from policy rules.
# When enabled, HIT rules increment a per-IP suspicion score that persists
# across requests within the configured time window. When a threshold is
# reached, the IP is blocked for the configured duration.
ip_blocking:
# Master toggle for IP blocking.
enabled: false
# How long HIT scores persist per IP. Each new HIT refreshes the TTL.
score_ttl: "1h"
# Block thresholds (sorted by severity). The highest matching threshold
# determines the block duration.
# thresholds:
# - name: light-offender
# threshold: 10
# duration: "5m"
# - name: heavy-offender
# threshold: 50
# duration: "1h"
# - name: persistent-offender
# threshold: 100
# duration: "24h"
#
# Named IP lists to block on a static basis (references ip_lists keys).
# static_lists:
# - "known-bad"
#
# Custom response for blocked IPs. Falls back to policy.defaults.deny.
# response:
# status_code: 403
# body_from_file: "/etc/rescaled-waf/pages/blocked.html"
# headers:
# X-Blocked-By: rescaled-waf
#
# Persist blocklist and scores to disk on shutdown, reload on startup.
persistence:
enabled: false
# file_path: "/var/lib/rescaled-waf/ip-block-state.json"
# Named IP lists for use in policy rules.
# Each key is the list name that rules reference.
ip_lists:
# Example: inline list of known IPs/subnets.
# known-bad:
# source: "inline"
# entries:
# - "192.168.1.0/24"
# - "10.0.0.1"
# - "2001:db8::/32"
#
# Example: URL-sourced list with periodic refresh.
# tor-exits:
# source: "url"
# url: "https://datafeed.waf.rescaled.com/tor-exits"
# refresh_interval: "1h"
rfc1918:
source: "inline"
entries:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ipv6-ula-link-local:
source: "inline"
entries:
- fc00::/7
- fe80::/10
# Policy rules define how requests are evaluated and acted upon.
# Rules are evaluated in order; the first terminal match (ALLOW, DENY,
# CHALLENGE) determines the outcome. Non-terminal actions (HIT, LOG) are
# collected along the way. If no terminal action is triggered, the request
# is being passed through upstream.
policy:
# Challenge operational settings. Required when CHALLENGE rules are configured.
challenge:
# HMAC-SHA256 secret for signing challenge tokens and pass cookies.
# Must be at least 32 characters. Required when any CHALLENGE rule exists.
secret: ""
# How long a pass cookie remains valid after successful verification.
cookie_ttl: "24h"
# How long a challenge token is valid (time to complete the challenge).
challenge_ttl: "1m"
# Cookie domain (empty = current domain only).
cookie_domain: ""
# Set Secure flag on the pass cookie (requires HTTPS).
cookie_secure: true
# Path to the HTML file for the meta refresh challenge page.
# The file must contain the placeholder {{META_REFRESH_TAG}}.
# Required when any CHALLENGE rule uses the "metarefresh" algorithm.
metarefresh_html: ""
# Path to the HTML file for the preact challenge page.
# The file must contain the placeholders {{CHALLENGE_DATA}} and {{CHALLENGE_SCRIPT}}.
# Required when any CHALLENGE rule uses the "preact" algorithm.
preact_html: ""
# Path to the HTML file for the proof-of-work challenge page.
# The file must contain the placeholders {{CHALLENGE_DATA}} and {{CHALLENGE_SCRIPT}}.
# Required when any CHALLENGE rule uses the "pow" algorithm
# (including when pow is the resolved default).
pow_html: ""
# Default parameters for each action type. Individual rules may override.
defaults:
challenge:
# Challenge algorithm: "pow" (proof-of-work), "preact", or "metarefresh".
algorithm: "pow"
# Difficulty level (0–64).
difficulty: 4
deny:
# HTTP status code for DENY responses.
status_code: 403
# Path to an HTML file to serve as the DENY response body.
body_file: ""
# Inline plain-text body (alternative to body_file; mutually exclusive).
# plain_text_body: "Access Denied"
# Default response headers for all DENY responses.
# Per-rule response.headers fully replace these (no merging).
# headers:
# X-Blocked-By: rescaled-waf
hit:
# Default suspicion score increment per HIT (if no amount specified).
amount: 1
log:
# Default log level for LOG actions (debug, info, warn, error).
level: "info"
# Rule definitions. Each rule needs a unique name, an action, and exactly
# one scope field that determines which requests match.
#
# Supported actions: ALLOW, DENY, CHALLENGE, HIT, LOG, WEIGH
#
# Supported scope fields:
# all: {} - matches every request
# path: "/exact/path" - exact path match
# path_regex: "^/api/.*" - regex path match
# user_agent: "ExactBot" - exact User-Agent match
# user_agent_regex: "bot" - regex User-Agent match
# ip_list: "list-name" - client IP in a named IP list
# geoip: "US" - GeoIP country code (or list: ["US", "CA"])
# networks: 15169 - ASN number (or list: [15169, 13335])
# expression: '<CEL expr>' - single CEL expression
# expression: - multiple CEL expressions (all must match)
# all:
# - 'method == "POST"'
# - 'path.startsWith("/api")'
# expression: - multiple CEL expressions (any must match)
# any:
# - 'geoCountry == "CN"'
# - 'geoCountry == "RU"'
#
# CEL expression variables:
# remoteAddress, host, method, path, userAgent, contentLength,
# headers (map), query (map)
# geoCountry, geoCountryName, geoCity, geoContinent (when GeoIP enabled)
# asnNumber, asnOrg (when ASN enabled)
#
# CEL custom functions:
# missingHeader(headers, "Name") - true if header is absent
# randInt(n) - random int in [0, n)
# regexSafe(s) - escape regex metacharacters
# ip_list("name") - IP list container for 'in' operator
#
# Rules can also be imported from external YAML files:
# - import: "/path/to/rules.yaml"
rules: []