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
A Container Service for Kubernetes (ACK) cluster is added to an ASM instance of v1.18 or later. For more information, see Add a cluster to an ASM instance.
Automatic sidecar proxy injection is enabled. For more information, see Manage global namespaces.
The HTTPBin application is deployed and can be accessed. For more information, see Deploy the HTTPBin application.
A Container Registry Enterprise Edition instance is created. Container Registry Enterprise Edition instances support Open Container Initiative (OCI) images. For more information, see Create a Container Registry Enterprise Edition instance.
Docker is installed. For more information, see Get Docker.
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.
NoteThe 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 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.
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 adirective
nameddefault
. By default, the rule specifies that a request is rejected if the request carries thex-user-type
header with a value ofbaned
.default_directives
: specifies that the defaultdirective
isdefault
.
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 #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.