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.
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.
Download the Coraza Wasm plug-in and create an image.
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
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
Use the following content to create a Dockerfile file in the current directory:
FROM scratch
ADD ./plugin.wasm ./plugin.wasm
Run the following command to create an image:
docker build -t coraza-proxy-wasm:latest .
Push the image to the 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 card of the desired Container Registry Enterprise Edition instance.
In the left-side navigation pane, choose . 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.
In the left-side navigation pane, choose . 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.
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
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
Check whether the image is pushed.
Log on to the Container Registry console. In the left-side navigation pane, click Instances.
On the Instances page, click the card of the desired Container Registry Enterprise Edition instance.
In the left-side navigation pane, choose . 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.
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.
Run the following command to check whether the Secret is created:
kubectl -n istio-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.
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 .
|
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
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.
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
The output indicates that 403 Forbidden
is returned for the request, which is rejected by the gateway as expected.