Basic concepts of the ALB WAF
Last updated on
A web application firewall acts as a security shield for your web applications. Operating at Layer 7 (the application layer), the ALB WAF inspects incoming traffic and blocks malicious requests such as bots, and common exploits before they can harm your backend services. It ensures safe traffic passes through while keeping threats at bay.
The STACKIT ALB WAF utilizes the Coraza engine and integrates seamlessly with the STACKIT Application Load Balancer (ALB).
To see, which features the STACKIT ALB WAF currently supports, check out the ALB WAF features overview.
Core concepts
Section titled “Core concepts”Understanding how the ALB WAF processes and references objects is key to configuring your security policies.
Firewall configuration
Section titled “Firewall configuration”The ALB WAF config is the central configuration object that holds your firewall settings. It serves as a container where you reference your desired managed rule sets or custom rule groups.
- Limits: By default, you can store up to 150 unique ALB WAF configs per project.
- Scope: A single ALB WAF config can be assigned to multiple listeners.
Managed rule sets
Section titled “Managed rule sets”Managed rule sets are pre-configured, rule collections that protect against widespread vulnerabilities. The first and primary collection is the OWASP Core Ruleset (CRS), which protects your applications against the OWASP Top 10 threats (including SQL Injection and Cross-Site Scripting).
- Customization: Instead of writing complex rules from scratch, you can globally enable, disable, or log individual rules within the managed set with the API.
Custom rule groups
Section titled “Custom rule groups”Custom rule groups allow you to define collections of specialized security rules tailored to your needs.
- Abstracted Layout: To reduce complexity, rules are configured using a structured JSON model with the API.
- Limits: By default, you can store up to 150 unique custom rule configurations per project.
- Evaluation Order: Custom rules are evaluated before managed rule sets, allowing you to define exceptions or whitelist specific payloads early in the inspection chain.
Listener integration
Section titled “Listener integration”ALB WAF protection is activated on a per-listener basis. An ALB listener holds a property field called wafConfigName. When this reference is populated with a valid ALB WAF config name, the firewall immediately starts inspecting all traffic passing through that specific port.
How to build your firewall configuration
Section titled “How to build your firewall configuration”Applying ALB WAF protection to your Application Load Balancer follows a structured three-step life cycle.
-
Create your rules: Before creating your ALB WAF config, you must configure at least one of the following:
- Managed Rule Set: configure your baseline protection rules (for example, OWASP CRS).
- Custom Rule Group: Define your custom rule group that you want to use.
-
Assemble the ALB WAF config: Create your main ALB WAF config entity. In your API request body, assign a unique name to the config and link the identifiers of the managed rule sets or custom rule groups you created in the first step.
-
Associate the ALB WAF config with an ALB listener: Activate the firewall by binding your config to the Application Load Balancer:
- When creating or updating an ALB listener, provide your ALB WAF config name in the
wafConfigNamefield within the listener’s configuration block. - The ALB will automatically initialize the Coraza engine and apply your ALB WAF config to the listener traffic path.
- When creating or updating an ALB listener, provide your ALB WAF config name in the
Observability
Section titled “Observability”The ALB WAF integrates with the Observability pipeline of the STACKIT Application Load Balancer. Envoy system logs and ALB metrics are covered in the Observability section of Basic concepts of the ALB; this section documents the records specific to the ALB WAF.
ALB WAF logs
Section titled “ALB WAF logs”When an ALB listener has an ALB WAF configuration attached, the ALB additionally emits ALB WAF logs produced by the embedded Coraza engine. All ALB WAF records share the tag wasm log coraza-filter <waf-config-name> coraza-filter_vm_id: and are shipped under the component="waf" label, so you can isolate them from Envoy system logs with a single label selector in your Observability queries.
Two record kinds are emitted per inspected transaction:
- Rule-match records — one line per rule that matches the request or response. They carry the human-readable message, the rule metadata (
id,severity,tag,ver, and so on), and the request context (hostname,uri,unique_id). - Audit records — a single
AuditLog:{...}JSON line summarizing the full transaction (client, request, response, engine state, active rule sets, and whether the transaction was interrupted). Use audit records for structured downstream processing.
Requests that reach the anomaly-score threshold produce an additional blocking-evaluation entry (rule IDs in the 949xxx range from the OWASP Core Rule Set) and, when the transaction is stopped, a Transaction interrupted line with action="deny" and the interrupting phase.
Anatomy of a rule-match record
Section titled “Anatomy of a rule-match record”Each rule-match record is a syslog line followed by an Envoy WASM wrapper and the Coraza payload. The payload begins with the client address and an action phrase (for example, Warning. for detections or Access denied (phase N). for blocks), followed by the rule message and a series of bracketed key-value fields.
The following fields appear on every rule-match record:
| Field | Description | Example |
|---|---|---|
client | Source IP and, where available, port of the connecting client. | 89.248.168.239 |
file | Path of the SecLang file that declared the rule. Custom rule groups appear under their own file name; managed rules use the @owasp_crs/ root. | @owasp_crs/REQUEST-911-METHOD-ENFORCEMENT.conf |
line | Line number inside the SecLang file for cross-reference. | 142 |
id | Numeric rule identifier. OWASP CRS uses fixed ranges (for example, 911xxx for method enforcement, 949xxx for anomaly-score blocking). | 911100 |
msg | The msg: field declared in the rule; the human-readable reason for the match. | Method is not allowed by policy |
data | The logdata: value expanded at match time — usually the offending input (MATCHED_VAR). | DELETE |
severity | Rule severity as declared by the author (emergency, critical, error, warning, notice, info, debug). | critical |
ver | Rule set version tag. | OWASP_CRS/4.14.0 |
tag | One or more classification tags (attack class, OWASP category, CAPEC or PCI reference, paranoia level). | attack-generic, paranoia-level/1, PCI/12.1 |
hostname | Host that received the request (ALB internal address). | 10.0.0.53 |
uri | Request URI that triggered evaluation. | /api/orders/42 |
unique_id | Correlation ID shared across every log line — rule-match, blocking-evaluation, Transaction interrupted, and AuditLog — for one transaction. | NLksGGQmUYxKYMEEKzD |
The unique_id is the primary correlation key. Filter on it to reconstruct every log line produced for a single request.
Example: DELETE blocked by a method-enforcement rule
Section titled “Example: DELETE blocked by a method-enforcement rule”The following OWASP CRS rule blocks any HTTP method that is not present in the tx.allowed_methods allow-list and adds the critical anomaly score to the phase-1 total:
SecRule REQUEST_METHOD "!@within %{tx.allowed_methods}" \ "id:911100,\ phase:1,\ block,\ msg:'Method is not allowed by policy',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'attack-generic',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'OWASP_CRS/METHOD-ENFORCEMENT',\ tag:'capec/1000/210/272/220/274',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.14.0',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"A DELETE /api/orders/42 request from 203.0.113.17 produces the following record sequence, correlated by unique_id="AbCdEfGhIjKlMnOpQrS":
- Method-enforcement match (
id:911100) — records the disallowed method and raises the phase-1 anomaly score. - Blocking evaluation (
id:949111) — the accumulated score exceeds the inbound threshold and the request is denied. - Transaction interruption — one-line summary with
action="deny"and the interruptingphase. - Audit record —
AuditLog:{...}JSON with the full transaction state andis_interrupted:true.
Abbreviated view (syslog prefix and Envoy wrapper trimmed to ...) showing the Coraza payload only:
... coraza-filter my-coraza: [client "203.0.113.17"] Coraza: Warning. Method is not allowed by policy [file "@owasp_crs/REQUEST-911-METHOD-ENFORCEMENT.conf"] [line "142"] [id "911100"] [msg "Method is not allowed by policy"] [data "DELETE"] [severity "critical"] [ver "OWASP_CRS/4.14.0"] [tag "OWASP_CRS/METHOD-ENFORCEMENT"] [hostname "10.0.0.53"] [uri "/api/orders/42"] [unique_id "AbCdEfGhIjKlMnOpQrS"]... coraza-filter my-coraza: [client "203.0.113.17"] Coraza: Access denied (phase 1). Inbound Anomaly Score Exceeded in phase 1 (Total Score: 5) [file "@owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "11900"] [id "949111"] [msg "Inbound Anomaly Score Exceeded in phase 1 (Total Score: 5)"] [severity "emergency"] [hostname "10.0.0.53"] [uri "/api/orders/42"] [unique_id "AbCdEfGhIjKlMnOpQrS"]... coraza-filter my-coraza: Transaction interrupted tx_id="AbCdEfGhIjKlMnOpQrS" context_id=127 action="deny" phase="http_request_headers"Full raw record set as it appears in the Observability log stream:
Mar 09 15:17:08 my-alb-abcdef123-804c9 envoy[779444]: [2026-03-09 15:17:08.522][779453][warning][wasm] [source/extensions/common/wasm/context.cc:1140] wasm log coraza-filter my-coraza coraza-filter_vm_id: [client "203.0.113.17"] Coraza: Warning. Method is not allowed by policy [file "@owasp_crs/REQUEST-911-METHOD-ENFORCEMENT.conf"] [line "142"] [id "911100"] [rev ""] [msg "Method is not allowed by policy"] [data "DELETE"] [severity "critical"] [ver "OWASP_CRS/4.14.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "OWASP_CRS/METHOD-ENFORCEMENT"] [tag "capec/1000/210/272/220/274"] [tag "PCI/12.1"] [hostname "10.0.0.53"] [uri "/api/orders/42"] [unique_id "AbCdEfGhIjKlMnOpQrS"]Mar 09 15:17:08 my-alb-abcdef123-804c9 envoy[779444]: [2026-03-09 15:17:08.523][779453][critical][wasm] [source/extensions/common/wasm/context.cc:1146] wasm log coraza-filter my-coraza coraza-filter_vm_id: [client "203.0.113.17"] Coraza: Access denied (phase 1). Inbound Anomaly Score Exceeded in phase 1 (Total Score: 5) [file "@owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "11900"] [id "949111"] [rev ""] [msg "Inbound Anomaly Score Exceeded in phase 1 (Total Score: 5)"] [data ""] [severity "emergency"] [ver "OWASP_CRS/4.14.0"] [maturity "0"] [accuracy "0"] [tag "anomaly-evaluation"] [tag "OWASP_CRS"] [hostname "10.0.0.53"] [uri "/api/orders/42"] [unique_id "AbCdEfGhIjKlMnOpQrS"]Mar 09 15:17:08 my-alb-abcdef123-804c9 envoy[779444]: [2026-03-09 15:17:08.523][779453][info][wasm] [source/extensions/common/wasm/context.cc:1137] wasm log coraza-filter my-coraza coraza-filter_vm_id: Transaction interrupted tx_id="AbCdEfGhIjKlMnOpQrS" context_id=127 action="deny" phase="http_request_headers"Mar 09 15:17:08 my-alb-abcdef123-804c9 envoy[779444]: [2026-03-09 15:17:08.523][779453][info][wasm] [source/extensions/common/wasm/context.cc:1137] wasm log coraza-filter my-coraza coraza-filter_vm_id: AuditLog:{"transaction":{"timestamp":"2026/03/09 15:17:08","unix_timestamp":1773069428523000000,"id":"AbCdEfGhIjKlMnOpQrS","client_ip":"203.0.113.17","client_port":41022,"host_ip":"10.0.0.53","host_port":443,"server_id":"188.34.102.37","request":{"method":"DELETE","protocol":"HTTP/1.1","uri":"/api/orders/42","http_version":"","headers":{":authority":["api.example.com"],":method":["DELETE"],":path":["/api/orders/42"],":scheme":["https"]},"body":"","files":null,"args":{},"length":0},"response":{"protocol":"","status":0,"headers":{},"body":""},"producer":{"connector":"","version":"","server":"","rule_engine":"On","stopwatch":"1773069428523000000 1660000; combined=1515000, p1=1424000, p2=0, p3=0, p4=0, p5=91000","rulesets":["OWASP_CRS/4.14.0"]},"highest_severity":"","is_interrupted":true}}