Skip to content
You are viewing the latest documentation for Solo Enterprise for kgateway. To access the documentation for older versions, use the version switcher.

About WAF

Page as Markdown

Learn more about how WAF is implemented in Solo Enterprise for kgateway.

Solo Enterprise for kgateway includes a built-in Web Application Firewall (WAF) that is powered by the open source Coraza rule engine. The WAF inspects HTTP traffic in real time at the gateway and blocks attacks, such as SQL injection, cross-site scripting (XSS), and remote code execution before they reach your apps. You define security policies in a Kubernetes-native WAFPolicy resource and attach them to routes or gateways.

Enablement

WAF is configured as a shared extension in the EnterpriseKgatewayParameters resource and must be attached to a GatewayClass. You cannot attach a shared extension that is defined in an EnterpriseKgatewayParameters resource to a Gateway.

When you deploy a gateway proxy with that GatewayClass, Solo Enterprise for kgateway automatically spins up a WAF server for you. The WAF server is shared by all gateways with the same GatewayClass.

For more information, see Enable the WAF server.

Common use cases

  • OWASP CRS: Enable the OWASP Core Rule Set (CRS) v4 to get broad protection against common web attacks without writing rules from scratch.
  • IP filtering: Block or allow traffic by client IP address or CIDR range.
  • Custom rules: Write Coraza SecLang rules inline or load them from ConfigMaps to enforce application-specific security policies.

WAF server architecture

The built-in WAF server implements Envoy’s External Processing (ExtProc) API and uses the open source Coraza rule engine to inspect and filter HTTP traffic.

The Coraza rule engine processes HTTP traffic in four sequential phases. Each phase covers a distinct stage of the request-response lifecycle.

PhaseName
1Request headers
2Request body
3Response headers
4Response body

The following diagram shows how a request flows through the four WAF inspection phases. The waf-server can block the request or response at any phase by returning an immediate response to Envoy.

    sequenceDiagram
    participant Client
    participant GW as Gateway
    participant WAF as waf-server (ExtProc)
    participant UP as Upstream

    Client->>GW: HTTP request

    rect rgba(100, 150, 255, 0.15)
        Note over Client,UP: Request Processing
        Note over GW,WAF: Phase 1 — Request Headers
        GW->>WAF: Phase 1 — request headers
        alt Rule triggered
            WAF-->>GW: Block (immediate response)
            GW-->>Client: 403 Forbidden
        else Pass
            WAF-->>GW: Continue
        end
        Note over GW,WAF: Phase 2 — Request Body
        GW->>WAF: Phase 2 — request body
        alt Rule triggered
            WAF-->>GW: Block (immediate response)
            GW-->>Client: 403 Forbidden
        else Pass
            WAF-->>GW: Continue
        end
    end

    GW->>UP: Forwarded request
    UP-->>GW: HTTP response

    rect rgba(100, 200, 130, 0.15)
        Note over Client,UP: Response Processing
        Note over GW,WAF: Phase 3 — Response Headers
        GW->>WAF: Phase 3 — response headers
        alt Rule triggered
            WAF-->>GW: Block (immediate response)
            GW-->>Client: Error response
        else Pass
            WAF-->>GW: Continue
        end
        Note over GW,WAF: Phase 4 — Response Body
        GW->>WAF: Phase 4 — response body
        alt Rule triggered
            WAF-->>GW: Block (immediate response)
            GW-->>Client: Error response
        else Pass
            WAF-->>GW: Continue
        end
    end

    GW-->>Client: HTTP response
  

Coraza variables

Each Coraza phase exposes a different set of Coraza variables that you can use to access data from a request or response. When you specify WAF rules, always specify the earliest phase in which the required data is available. For example, to access request headers, use phase:1.

The following table shows the different phases and the Coraza variables that are available in each phase:

PhaseNameTriggerKey Coraza variables available
1Request headersAfter request headers are received, before the body is bufferedREQUEST_HEADERS, REQUEST_METHOD, REQUEST_URI, REQUEST_PROTOCOL, REMOTE_ADDR, REMOTE_PORT, SERVER_ADDR, SERVER_PORT
2Request bodyAfter the full request body is bufferedEverything from Phase 1, plus REQUEST_BODY, ARGS, ARGS_GET, ARGS_POST, FILES
3Response headersAfter response headers are received from upstreamRESPONSE_HEADERS, RESPONSE_STATUS, RESPONSE_PROTOCOL
4Response bodyAfter the full response body is bufferedEverything from Phase 3, plus RESPONSE_BODY

All request headers and the full request body are buffered before the WAF finishes evaluating them and before the request is forwarded upstream. Expect added latency proportional to body size when body inspection (Phase 2) is enabled.

During Phase 1, the WAF server receives both the request headers and the connection metadata (client IP, client port, server IP, server port) from Envoy. Rules that use REMOTE_ADDR, REMOTE_PORT, SERVER_ADDR, or SERVER_PORT must use phase:1.

Header and body processing modes

By default, the WAF server inspects request headers (Phase 1) and response headers (Phase 3). You can use the processingConfig setting in your WAFPolicy resource to change which phases are active during WAF rule processing.

Note that body inspection adds latency and memory overhead to the WAF server because the full body must be buffered before it can be inspected.

The following table shows the different WAF processing configuration modes and how they map to the Coraza rule phases.

Request/responseWAF processing modeCoraza phaseNotes
RequestHeaders (default)Phase 1Inspects request headers only. This mode is turned on by default.
RequestHeadersAndBodyPhases 1 and 2Inspects request headers and body. The full request body is buffered before the upstream receives the request.
ResponseHeaders (default)Phase 3Inspects response headers only. This mode is turned on by default.
ResponseHeadersAndBodyPhases 3 and 4Inspects response headers and body. The full response body is buffered before the client receives the response.
ResponseNoneSkips all response inspection. Phases 3 and 4 are not run.
Skipping request headers is not supported. The minimum request mode is Headers. Request headers carry connection metadata, such as the client IP address and port that the WAF processing depends on.

For an example, see Request and response body inspection.

Body buffering

The WAF server does not support streaming. Envoy buffers the full request or response body before forwarding it to the WAF server for inspection. Body buffering is triggered when you configured the respective body processing mode in the processingConfig field of your WAFPolicy.

The ListenerPolicy provides the following settings to set the body buffer size:

  • perConnectionBufferLimitBytes: The total buffer limit per connection. The default is 1MiB (1048576 bytes). For HTTP/1.1 traffic, this is effectively a per-request limit. For HTTP/2, a single connection can carry multiple concurrent request streams. Because of that, the limit is shared across all multiplexed streams. When the limit is exceeded, requests are rejected with a 413 response.
  • maxRequestSize: The buffer limit for an individual request or response, regardless of protocol.

To increase both the perConnectionBufferLimitBytes and maxRequestSize settings, create a ListenerPolicy that targets your Gateway:

apiVersion: gateway.kgateway.dev/v1alpha1
kind: ListenerPolicy
metadata:
  name: waf-buffer-limit
  namespace: kgateway-system
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http
  default:
    perConnectionBufferLimitBytes: 10485760
  buffer: 
    maxRequestSize: '1024'

Both settings can be used together. If you increase maxRequestSize above the default 1MiB perConnectionBufferLimitBytes, you must also raise perConnectionBufferLimitBytes; otherwise the connection limit is reached first and requests are rejected with a 413 response.

For more information, see Buffering.

WAF rule definition

The Coraza rule engine implements the OWASP Coraza Seclang directive language, which is compatible with ModSecurity v3 directives. You use this language to write your WAF rules. The WAF server evaluates each request and response against those rules.

To provide your WAF rules to the WAF server, Solo Enterprise for kgateway uses a dedicated WAFPolicy resource. You can define your rules as follows:

  • Inline: Write directives directly in the WAFPolicy resource as strings.
  • ConfigMap: Store directives in a Kubernetes ConfigMap and reference it from the WAFPolicy. This approach makes it easier to manage and update rules without modifying the policy itself, because the WAF server watches for ConfigMap changes and reloads rules automatically.

Custom Coraza rules

Write custom WAF rules by using the Coraza Seclang directive language, which is compatible with ModSecurity v3 directives.

For more information, see Custom Coraza rules.

IP-based filtering

You can use Coraza’s REMOTE_ADDR variable to block or allow traffic based on the client IP address. By default, REMOTE_ADDR is set to the socket-level peer IP. You can configure the gateway to derive the REMOTE_ADDR variable value from the X-Forwarded-For header instead. For more information, see IP-based filtering.

OWASP Core Rule Set (CRS)

You can optionally enable the OWASP Core Rule Set (CRS) in your WAFPolicy. CRS is an open source set of generic detection rules that protect against a wide range of attacks, including the OWASP Top Ten. Solo Enterprise for kgateway bundles CRS version 4. For the full explanation and a setup example, see OWASP Core Rule Set.

Disable WAF for a route

If a WAF policy is applied at the Gateway level, you can disable it for specific routes by setting entWAF.disable in the route-level EnterpriseKgatewayTrafficPolicy.

apiVersion: enterprisekgateway.solo.io/v1alpha1
kind: EnterpriseKgatewayTrafficPolicy
metadata:
  name: httpbin-no-waf
  namespace: httpbin
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: httpbin
  entWAF:
    disable: {}

Fail-closed behavior

The WAF server fails closed by default. If a WAFPolicy contains invalid directives that fail the Coraza WAF engine compilation, the server denies all requests that match the policy with a 500 response until the policy is corrected. To detect invalid policies before they affect traffic, check the WAFPolicy status. For more information, see Debug WAF.

Next

Was this page helpful?