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 some 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 Enable automatic sidecar proxy injection.
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.
Buildah is installed. For more information, see buildah.
Step 1: Deploy the HTTPBin application and configure an Isito gateway and a virtual service
Deploy the HTTPBin application.
Create an httpbin.yaml file that contains the following content:
Use kubectl to connect to the ACK cluster based on the information in the kubeconfig file, and then run the following command to deploy the HTTPBin application in the cluster:
kubectl apply -f httpbin.yaml
Create an Istio gateway.
Create an ingressgateway.yaml file that contains the following content:
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: ingressgateway namespace: istio-system spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP
Use kubectl to connect to the ASM instance based on the information in the kubeconfig file. Then, run the following command to configure an Istio gateway for the ingress gateway and expose port 80:
kubectl apply -f ingressgateway.yaml
Create a virtual service.
Create an ingressgateway-vs.yaml file that contains the following content:
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: ingressgateway namespace: istio-system spec: gateways: - ingressgateway hosts: - '*' http: - match: - uri: prefix: / name: httpbin route: - destination: host: httpbin.default.svc.cluster.local
Use kubectl to connect to the ASM instance based on the information in the kubeconfig file. Then, run the following command to configure a route to the HTTPBin application on the ingress gateway:
kubectl apply -f ingressgateway-vs.yaml
Step 2: 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.
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
Create an image and push it 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:
buildah login --username=Logon user name enterprise-registry.cn-hangzhou.cr.aliyuncs.com
Run the following commands to create an image named
coroza-proxy-wasm
and copy the plugin.wasm file obtained in Step 1 to the image:buildah --name coroza-proxy-wasm from scratch buildah copy coroza-proxy-wasm plugin.wasm ./
Run the following command to push the image to the image repository:
buildah commit coroza-proxy-wasm docker://enterprise-registry.cn-hangzhou.cr.aliyuncs.com/wasm/coroza-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 coroza-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 3: 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 coroza-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 workload where the Coraza Wasm plug-in is located. In this example, the Coraza Wasm plug-in applies to an ASM gateway. Therefore, the Secret is created in the istio-system namespace. In actual use, change the namespace name after the
-n
parameter in the preceding command to the name of the namespace where the workload resides.Run the following command to check whether the Secret is created:
kubectl -n isito-system get secret coroza-wasm-proxy
Step 4: 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: coroza-proxy-wasm namespace: istio-system spec: imagePullPolicy: IfNotPresent imagePullSecret: coroza-wasm-proxy selector: matchLabels: istio: ingressgateway url: oci://enterprise-registry.cn-hangzhou.cr.aliyuncs.com/wasm/coroza-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
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 5: 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 ......
You can see 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
You can see that
403 Forbidden
is returned for the request, which is rejected by the gateway as expected.