Service Mesh (ASM) provides rich routing and request manipulation capabilities through the VirtualService API and extensive security capabilities through the AuthorizationPolicy API. However, in some scenarios, these APIs may not meet all your requirements. You can write custom WebAssembly (Wasm) filters and add them to an ASM gateway or sidecar proxy to implement custom behaviors for complex scenarios. This topic describes how to enable a Coraza Web Application Firewall (WAF) on an ASM gateway using the WasmPlugin API.
Prerequisites
-
A cluster has been added to an ASM instance of version 1.18 or later. For more information, see Add a cluster to an ASM instance.
-
Sidecar injection is enabled. For more information, see Configure sidecar injection policies.
-
The httpbin application is deployed and accessible. For more information, see Deploy the httpbin application.
-
An Alibaba Cloud Container Registry Enterprise Edition instance has been created. Enterprise Edition instances support OCI images. For more information, see Create an Enterprise Edition instance.
-
Docker is installed. For more information, see Get Docker.
Step 1: Build and push the Wasm OCI image
You can load a Wasm plugin in three ways. This topic demonstrates the second method: building a Wasm plugin into an OCI image and pushing it to Alibaba Cloud Container Registry.
-
Store the Wasm extension in a ConfigMap and mount it to the container. The ASM sidecar proxy or ASM gateway loads it from the local file system.
-
Package the Wasm extension as an OCI image and upload it to an image repository. The ASM sidecar proxy or ASM gateway pulls the image from the repository.
-
Upload the Wasm extension to cloud storage or another service that supports HTTP downloads. The ASM sidecar proxy or gateway downloads it over the network.
-
Download the Coraza Wasm plugin and build the image.
-
Run the following commands to download and unzip the Coraza Wasm plugin:
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 -
Run the following command to rename the Coraza Wasm plugin file.
After unzipping, you get a file named
coraza-proxy-wasm.wasm. Rename it toplugin.wasm, as required by ASM.mv coraza-proxy-wasm.wasm plugin.wasm -
In the current directory, create a file named
Dockerfilethat contains the following content:FROM scratch ADD ./plugin.wasm ./plugin.wasm -
Run the following command to build the image:
docker build -t coraza-proxy-wasm:latest .
-
-
Push the image to your Alibaba Cloud Container Registry Enterprise Edition instance.
-
Create a namespace.
-
Log on to the Container Registry console. In the left-side navigation pane, click Instances.
-
On the Instances page, click the target Enterprise Edition instance.
-
In the left-side navigation pane, choose and click Create Namespace. Configure the settings and click OK.
In this example, set the Namespace name to wasm.
-
-
In the left-side navigation pane, choose . Click the Public Network tab, turn on the Access Entry switch, and add IP addresses to the public whitelist as needed.
If you do not require a whitelist, delete the default entry.
NoteThis topic uses a public network address for demonstration purposes. In a production environment, you can configure VPC access for enhanced privacy and network performance. For more information, see Configure access control over a VPC.
-
Run the following command to log in to your Alibaba Cloud Container Registry Enterprise Edition instance. You will be prompted for your password.
docker login --username=<your-username> enterprise-registry.cn-hangzhou.cr.aliyuncs.com -
Run the following commands 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 -
Verify that the image was pushed successfully.
-
Log on to the Container Registry console. In the left-side navigation pane, click Instances.
-
On the Instances page, click the target Enterprise Edition instance.
-
In the left-side navigation pane, choose . Click coraza-proxy-wasm and then, in the left-side navigation pane, click Image Versions.
If an image with the
latesttag is displayed, the image was pushed successfully.
-
-
Step 2: Configure image pull permissions
After creating the private repository, you must create a Kubernetes Secret that contains the credentials for your container registry. The ASM gateway or sidecar proxy uses this Secret to authenticate and pull the OCI image.
-
Run the following command to create the Secret:
kubectl create secret docker-registry -n istio-system coraza-wasm-proxy --docker-server=enterprise-registry.cn-hangzhou.cr.aliyuncs.com --docker-username=<your-username> --docker-password=<your-password>The Secret must be in the same namespace as the WasmPlugin. In this topic, the WasmPlugin is deployed to the
istio-systemnamespace, so the Secret is also created there. Adjust the namespace specified by the-nflag based on your actual configuration. -
Run the following command to verify that the Secret was created successfully:
kubectl -n istio-system get secret coraza-wasm-proxy
Step 3: Apply the WasmPlugin
The WasmPlugin API declares the plugin and related configurations for the target gateway or sidecar proxy.
-
Create a file named
wasm-plugin.yamlwith 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: defaultParameter
Description
spec.urlSpecifies the URL and tag of the OCI image.
spec.imagePullSecretSpecifies the Secret to use for authenticating with the image repository.
spec.selectorSpecifies the target workload where the plugin is applied.
spec.phaseSpecifies the phase in the filter chain where the plugin is inserted.
spec.pluginConfigSpecifies the configuration for the plugin.
-
directives_map: Defines a directive set nameddefault. The rule specifies that requests that contain thex-user-typeheader with a value ofbanedare denied. -
default_directives: Specifiesdefaultas the directive set.
-
-
In the KubeConfig environment for your ASM instance, run the following command to apply the WasmPlugin:
kubectl apply -f wasm-plugin.yaml
Step 4: Verify the WasmPlugin
-
Run the following command to access the httpbin application.
Replace
http://120.27.XXX.XX/with your actual gateway address. For information about how to obtain the gateway address, see Obtain the IP address of an 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 command returns a
200 OKstatus code, which indicates the request was successful. -
Run the following command again to access the httpbin application, this time with the
x-user-type: banedheader.Replace
http://120.27.XXX.XX/with your actual gateway address.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 intactThe command returns a
403 Forbiddenstatus code, which indicates that the gateway denied the request.