All Products
Search
Document Center

Alibaba Cloud Service Mesh:Use the Coraza Wasm plug-in to implement WAF capabilities on an ASM gateway

Last Updated:Aug 21, 2024

Service Mesh (ASM) provides rich routing and request manipulation capabilities by using the VirtualService API, and provides rich security capabilities by using the AuthorizationPolicy API. However, these APIs may still fail to meet your requirements in specific scenarios. You can customize WebAssembly (Wasm) filters and add them to ASM gateways or sidecar proxies to implement custom behavior in complex scenarios. This topic describes how to use the WasmPlugin API to enable Coraza Web Application Firewall (WAF) for an ASM gateway.

Prerequisites

Step 1: Create an OCI image of the Wasm plug-in and push it to the Container Registry Enterprise Edition instance

A Wasm plug-in can be loaded in the following three ways. The following example uses the second method. In the example, an OCI image of the Wasm plug-in is created and pushed to the Container Registry Enterprise Edition instance.

  • The Wasm plug-in is stored in a ConfigMap and mounted to a container. An ASM sidecar proxy or ASM gateway loads the Wasm plug-in from the local file system.

  • An OCI image of the Wasm plug-in is created and uploaded to the image repository. An ASM sidecar proxy or ASM gateway pulls the image from the image repository.

  • The Wasm plug-in is uploaded to cloud storage or other services that support download over HTTP. An ASM sidecar proxy or ASM gateway downloads the Wasm plug-in over the network.

  1. Download the Coraza Wasm plug-in and create an image.

    1. Run the following commands to download the Coraza Wasm plug-in to your computer 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. Run the following command to rename the Coraza Wasm plug-in.

      After you decompress the file in the previous step, you obtain the coraza-proxy-wasm.wasm file. ASM requires that a Wasm plug-in must be named plugin.wasm, and therefore you must rename it.

      mv coraza-proxy-wasm.wasm plugin.wasm
    3. Use the following content to create a Dockerfile file in the current directory:

      FROM scratch
      ADD ./plugin.wasm ./plugin.wasm
    4. Run the following command to create an image:

      docker build -t coraza-proxy-wasm:latest . 
  2. Push the image to the Container Registry Enterprise Edition instance.

    1. Create a namespace.

      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 the desired Container Registry Enterprise Edition instance.

      3. In the left-side navigation pane, choose Repository > Namespace. On the page that appears, click Create Namespace. In the dialog box that appears, configure the relevant information, and then click OK.

        For this example, set Namespace to wasm.

    2. In the left-side navigation pane, choose Repository > Access Control. Then, click the Internet tab, turn on Enable Access over Internet, and add Internet whitelists based on your business requirements.

      If you do not need whitelist-based control, delete the default whitelist.

      Note

      The public endpoint is used as an example. During actual use, you can configure virtual private cloud (VPC) access for greater security and better network performance. For more information, see Configure a VPC ACL.

    3. Run the following command and enter the password to log on to the Container Registry Enterprise Edition instance:

      docker login --username=Logon username enterprise-registry.cn-hangzhou.cr.aliyuncs.com
    4. Run the following command to push the image to the image repository:

      docker tag ${ImageId} enterprise-registry.cn-hangzhou.cr.aliyuncs.com/wasm/coraza-proxy-wasm:latest
      docker push enterprise-registry.cn-hangzhou.cr.aliyuncs.com/wasm/coraza-proxy-wasm:latest
    5. Check whether the image is pushed.

      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 the desired Container Registry Enterprise Edition instance.

      3. In the left-side navigation pane, choose Repository > Repositories. On the page that appears, click coraza-proxy-wasm. In the left-side navigation pane, click Tags.

        If the image with the latest tag is displayed, the image is pushed successfully.

Step 2: Configure permissions to pull images

After you create a private repository, you must use the password configured for the Container Registry Enterprise Edition instance to create a Secret. An ASM sidecar proxy or ASM gateway uses the authorization information in the Secret for authentication when it pulls images.

  1. Run the following command to create a Secret:

    kubectl create secret docker-registry -n istio-system coraza-wasm-proxy --docker-server=enterprise-registry.cn-hangzhou.cr.aliyuncs.com --docker-username=Username -- docker-password=Password

    The Secret must be in the same namespace as the Wasm plug-in. In this example, the namespace of the Wasm plug-in is istio-system. Therefore, the Secret should be in the istio-system namespace. In actual use, modify the namespace name following the -n parameter in the preceding command based on your business requirements.

  2. Run the following command to check whether the Secret is created:

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

Step 3: Apply the WasmPlugin API to the ASM instance

The WasmPlugin API is used to declare the plug-ins that apply to the destination gateway or sidecar proxy and the related configurations.

  1. Create a wasm-plugin.yaml file that contains the following content:

    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://enterprise-registry.cn-hangzhou.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

    Parameter

    Description

    spec.url

    Specifies the address and tags of the OCI image.

    spec.imagePullSecret

    Specifies the Secret that is used to authenticate the image repository.

    spec.selector

    Specifies the workload on which this plug-in configuration is applied.

    spec.phase

    Specifies where to insert the plug-in.

    sepc.pluginConfig

    Specifies the plug-in configurations.

    • directives_map: defines a directive named default. By default, the rule specifies that a request is rejected if the request carries the x-user-type header with a value of baned.

    • default_directives: specifies that the default directive is default.

  2. Use kubectl to connect to the ASM instance based on the information in the kubeconfig file. Then, run the following command to apply the Coraza Wasm plug-in to the ASM instance:

    kubectl apply -f wasm-plugin.yaml

Step 4: Check whether the Coraza Wasm plug-in takes effect

  1. Run the following command to access the HTTPBin application.

    Replace http://120.27.XXX.XX/ with the IP address of the ingress gateway. For more information about how to obtain the IP address of the gateway, see Obtain the IP address of the ingress gateway.

    curl -v http://120.27.XXX.XX/

    Expected output:

    *   Trying 120.27.XXX.XX:80...
    * Connected to 120.27.XXX.XX (120.27.XXX.XX) port 80 (#0)
    > GET / HTTP/1.1
    > Host: 120.27.XXX.XX
    > User-Agent: curl/7.86.0
    > Accept: */*
    >
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < server: istio-envoy
    < date: Fri, 27 Oct 2023 03:21:19 GMT
    < content-type: text/html; charset=utf-8
    < content-length: 9593
    < access-control-allow-origin: *
    < access-control-allow-credentials: true
    < x-envoy-upstream-service-time: 2
    ......

    The output indicates that 200 OK is returned for the request as expected.

  2. Run the following command to send a request with the x-user-type: baned header to access the HTTPBin application again.

    Replace http://120.27.XXX.XX/ with the actual IP address of the gateway.

    curl -v -H 'x-user-type: baned' http://120.27.XXX.XX/

    Expected output:

    *   Trying 120.27.XXX.XX:80...
    * Connected to 120.27.XXX.XX (120.27.XXX.XX) port 80 (#0)
    > GET / HTTP/1.1
    > Host: 120.27.XXX.XX
    > User-Agent: curl/7.86.0
    > Accept: */*
    > x-user-type: baned
    >
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 403 Forbidden
    < date: Fri, 27 Oct 2023 03:22:19 GMT
    < server: istio-envoy
    < content-length: 0
    <
    * Connection #0 to host 120.27.XXX.XX left intact

    The output indicates that 403 Forbidden is returned for the request, which is rejected by the gateway as expected.