All Products
Search
Document Center

Alibaba Cloud Service Mesh:Enable WAF on an ASM ingress gateway with the Coraza Wasm plug-in

Last Updated:Mar 11, 2026

VirtualService routing rules and AuthorizationPolicy access controls do not cover application-layer threats such as SQL injection, cross-site scripting (XSS), or other OWASP Top 10 attacks. The Coraza WebAssembly (Wasm) plug-in solves this by adding a Web Application Firewall (WAF) directly inside the gateway's Envoy process. Every inbound request is inspected and malicious traffic is blocked before it reaches your services -- no external sidecar or extra network hop required.

Coraza is an open-source, OWASP-maintained WAF engine that uses ModSecurity SecRule syntax. To deploy it, package the Coraza Wasm binary as an OCI image and push it to a container registry. Then apply a WasmPlugin resource to load it into the Envoy filter chain.

How it works

  1. Package the Coraza Wasm binary as an OCI image and push it to a container registry.

  2. Create a Kubernetes Secret so the ASM gateway can pull the image.

  3. Apply a WasmPlugin resource that loads the plug-in into the gateway's Envoy filter chain and configures SecRule directives.

  4. The gateway evaluates every inbound request against the configured rules and returns 403 Forbidden for any request that matches a deny rule.

Prerequisites

Before you begin, make sure that you have:

Wasm plug-in loading methods

ASM supports three ways to load a Wasm plug-in. This tutorial uses the OCI image method.

Method

How it works

When to use

OCI image (used in this tutorial)

Package the .wasm binary as an OCI image and push it to a container registry. The gateway pulls the image from the image repository.

Recommended for most production deployments. Versioned, auditable, and works with existing registry infrastructure.

ConfigMap

Store the .wasm binary in a Kubernetes ConfigMap and mount it into the gateway pod. The gateway loads the file from the local file system.

Quick prototyping or air-gapped environments where a registry is unavailable. Limited by the ConfigMap 1 MiB size limit.

HTTP download

Host the .wasm binary on cloud storage or any HTTP-accessible endpoint. The gateway downloads it over the network.

Environments where a centralized artifact server already serves binaries over HTTP.

Step 1: Build and push the Coraza Wasm OCI image

Download and prepare the plug-in binary

  1. Download the Coraza Wasm plug-in and decompress it:

       wget https://github.com/corazawaf/coraza-proxy-wasm/releases/download/0.3.0/coraza-proxy-wasm-0.3.0.zip
       unzip coraza-proxy-wasm-0.3.0.zip
  2. Rename the binary to plugin.wasm. ASM requires this exact file name:

       mv coraza-proxy-wasm.wasm plugin.wasm
  3. Create a Dockerfile in the same directory:

       FROM scratch
       ADD ./plugin.wasm ./plugin.wasm
  4. Build the OCI image:

       docker build -t coraza-proxy-wasm:latest .

Push the image to Container Registry

  1. Create a namespace in Container Registry:

    1. Log on to the Container Registry console. In the left-side navigation pane, click Instances.

    2. On the Instances page, click the card of your Container Registry Enterprise Edition instance.

    3. In the left-side navigation pane, choose Repository > Namespace. Click Create Namespace, set Namespace to wasm, and click OK.

  2. Enable Internet access for the registry: In the left-side navigation pane, choose Repository > Access Control. Click the Internet tab, turn on Enable Access over Internet, and add Internet whitelists based on your requirements. If you do not need whitelist-based control, delete the default whitelist.

    Note

    This example uses the public endpoint. For production use, configure Virtual Private Cloud (VPC) access for better security and network performance. For more information, see Configure a VPC ACL.

  3. Log in to the registry: Enter your password when prompted. Replace the following placeholders with your actual values:

    Placeholder

    Description

    Example

    <your-username>

    Logon username for the Container Registry instance

    admin@china

    <your-registry-endpoint>

    The endpoint of your Container Registry instance

    enterprise-registry.cn-hangzhou

       docker login --username=<your-username> <your-registry-endpoint>.cr.aliyuncs.com
  4. Tag and push the image: Replace <image-id> with the image ID returned by docker build in the previous section.

       docker tag <image-id> <your-registry-endpoint>.cr.aliyuncs.com/wasm/coraza-proxy-wasm:latest
       docker push <your-registry-endpoint>.cr.aliyuncs.com/wasm/coraza-proxy-wasm:latest
  5. Verify the image was pushed: If the image with the latest tag appears, the push was successful.

    1. In the Container Registry console, open your Enterprise Edition instance.

    2. In the left-side navigation pane, choose Repository > Repositories. Click coraza-proxy-wasm.

    3. In the left-side navigation pane, click Tags.

Step 2: Create a Secret for image pulls

The repository is private, so the ASM gateway needs credentials to pull the Wasm image. Create a Kubernetes Secret with the registry credentials:

kubectl create secret docker-registry coraza-wasm-proxy \
  -n istio-system \
  --docker-server=<your-registry-endpoint>.cr.aliyuncs.com \
  --docker-username=<your-username> \
  --docker-password=<your-password>
Important

The Secret must be in the same namespace as the WasmPlugin resource. This tutorial uses istio-system. Adjust the -n value if your plug-in targets a different namespace.

Verify the Secret:

kubectl -n istio-system get secret coraza-wasm-proxy

Step 3: Apply the WasmPlugin resource

The WasmPlugin resource declares which plug-in to load, where to insert it in the Envoy filter chain, and how to configure it.

  1. Create a file named wasm-plugin.yaml with the following content: The following table describes the key fields: In this example, the default directive set enables the Coraza rule engine and defines a single rule: deny any request whose x-user-type header equals baned.

    Field

    Description

    spec.url

    OCI image address including the tag. Supports oci://, file://, and http[s]:// schemes.

    spec.imagePullSecret

    Name of the Kubernetes Secret with registry credentials.

    spec.imagePullPolicy

    Image pull policy.

    spec.selector

    Label selector that determines which workloads load this plug-in. Here it targets the ingress gateway.

    spec.phase

    Where to insert the plug-in in the filter chain. AUTHN places it before authentication filters, so requests are inspected as early as possible.

    spec.pluginConfig

    Coraza-specific configuration. directives_map defines named rule sets using SecRule syntax. default_directives specifies which rule set to apply by default.

       apiVersion: extensions.istio.io/v1alpha1
       kind: WasmPlugin
       metadata:
         name: coraza-proxy-wasm
         namespace: istio-system
       spec:
         imagePullPolicy: IfNotPresent
         imagePullSecret: coraza-wasm-proxy
         selector:
           matchLabels:
             istio: ingressgateway
         url: oci://<your-registry-endpoint>.cr.aliyuncs.com/wasm/coraza-proxy-wasm:latest
         phase: AUTHN
         pluginConfig:
           directives_map:
             default:
               - "SecDebugLogLevel 9"
               - "SecRuleEngine On"
               - "SecRule REQUEST_HEADERS:x-user-type \"@streq baned\" \"id:101,phase:1,t:lowercase,deny,msg:'denied by header'\""
           default_directives: default
  2. Connect to the ASM instance with kubectl and apply the resource:

       kubectl apply -f wasm-plugin.yaml

Step 4: Verify the WAF plug-in

Test both allowed and blocked requests to confirm the plug-in is working.

  1. Send a normal request to the HTTPBin application through the ingress gateway: Replace <gateway-ip> with the IP address of your ingress gateway. For more information, see Obtain the IP address of the ingress gateway. Expected result -- the gateway returns 200 OK:

       curl -v http://<gateway-ip>/
       > GET / HTTP/1.1
       > Host: <gateway-ip>
       ...
       < HTTP/1.1 200 OK
       < server: istio-envoy
       ...
  2. Send a request with the blocked header: Expected result -- the gateway returns 403 Forbidden: The 403 response confirms that the Coraza WAF plug-in is active and enforcing the configured rule.

       curl -v -H 'x-user-type: baned' http://<gateway-ip>/
       > GET / HTTP/1.1
       > Host: <gateway-ip>
       > x-user-type: baned
       ...
       < HTTP/1.1 403 Forbidden
       < server: istio-envoy
       ...