Skip to content

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.

Understanding how the ALB WAF processes and references objects is key to configuring your security policies.

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 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 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.

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.

Applying ALB WAF protection to your Application Load Balancer follows a structured three-step life cycle.

  1. 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.
  2. 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.

  3. 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 wafConfigName field 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.

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.

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.

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:

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":

  1. Method-enforcement match (id:911100) — records the disallowed method and raises the phase-1 anomaly score.
  2. Blocking evaluation (id:949111) — the accumulated score exceeds the inbound threshold and the request is denied.
  3. Transaction interruption — one-line summary with action="deny" and the interrupting phase.
  4. Audit recordAuditLog:{...} JSON with the full transaction state and is_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}}