ASM通過VirtualService API提供豐富的路由能力和請求操縱能力,通過AuthorizationPolicy API提供豐富的安全能力,但是在一些特定場景下,這些API可能仍然不能滿足需求。您可以通過編寫自定義的Wasm Filter并添加到ASM網關或Sidecar來實現復雜場景的自定義行為。本文介紹如何通過WasmPlugin API為ASM網關啟用Coraza WAF。
前提條件
已添加集群到ASM實例,且ASM實例版本為1.18及以上。
已啟用Sidecar注入。具體操作,請參見配置Sidecar注入策略。
已部署httpbin應用,且可以正常訪問。具體操作,請參見部署httpbin應用。
已創建阿里云容器鏡像服務企業版(企業版實例支持OCI鏡像)。具體操作,請參見創建企業版實例。
已安裝Docker,請參見:Get Docker
步驟一:制作Wasm Plugin OCI鏡像并推送至阿里云容器鏡像服務
Wasm Plugin有以下三種加載方式。本文以第二種方式為例,制作Wasm Plugin的OCI鏡像,并將其推送到阿里云容器鏡像服務。
將Wasm擴展存儲至configmap,并Mount至容器,ASM網格代理或ASM網關從本地文件系統加載。
將Wasm擴展制作成OCI鏡像上傳至鏡像倉庫,ASM網格代理或ASM網關從鏡像倉庫拉取。
將Wasm擴展上傳至云存儲或其他支持HTTP協議下載的服務,ASM網格代理或網關通過網絡下載。
下載Coraza Wasm插件并構建鏡像。
執行以下命令,下載Coraza Wasm插件至本地,并解壓縮。
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
執行以下命令,為Coraza Wasm插件重命名。
上一步解壓完成后,會得到coraza-proxy-wasm.wasm文件。ASM要求Wasm插件必須命名為plugin.wasm,因此需要重命名。
mv coraza-proxy-wasm.wasm plugin.wasm
在當前目錄下創建Dockerfile文件,內容如下:
FROM scratch ADD ./plugin.wasm ./plugin.wasm
執行如下命令構建鏡像:
docker build -t coraza-proxy-wasm:latest .
推送鏡像到ACR企業版實例。
創建命名空間。
登錄容器鏡像服務控制臺,在左側導航欄,單擊實例列表。
在實例列表頁面,單擊目標企業版實例。
在左側導航欄,單擊
,然后單擊創建命名空間,配置相關信息,然后單擊確定。本示例配置命名空間名稱為wasm。
在左側導航欄,單擊
,單擊公網頁簽,打開訪問入口開關,按需添加公網白名單。如果不需要白名單控制,請刪除默認的白名單。
說明本文采用公網地址作為演示。在實際應用中,您可以配置專有網絡訪問以實現更高的私密性和更好的網絡性能。更多信息,請參見配置專有網絡的訪問控制。
執行以下命令,登錄ACR企業版實例,輸入密碼。
docker login --username=登錄用戶名 enterprise-registry.cn-hangzhou.cr.aliyuncs.com
執行以下命令,將鏡像推送到鏡像倉庫。
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
驗證鏡像是否推送成功。
登錄容器鏡像服務控制臺,在左側導航欄,單擊實例列表。
在實例列表頁面,單擊目標企業版實例。
在左側導航欄,單擊
,單擊coraza-proxy-wasm,然后在左側導航欄,單擊鏡像版本。若顯示剛推送的標簽為
latest
的鏡像,表明鏡像推送成功。
步驟二:配置鏡像拉取權限
創建私有倉庫后,您需要使用容器鏡像服務配置的口令創建Secret。ASM網格代理或ASM網關將使用Secret中的授權信息在拉取鏡像時進行認證。
執行以下命令,創建Secret。
kubectl create secret docker-registry -n istio-system coraza-wasm-proxy --docker-server=enterprise-registry.cn-hangzhou.cr.aliyuncs.com --docker-username=用戶名 --docker-password=密碼
Secret需要保持與Wasm Plugin處于同一命名空間。本文的Wasm Plugin命名空間為istio-system,因此對應的Secret在istio-system命名空間。在實際使用中,請您根據實際情況調整以上命令中
-n
參數后的命名空間名稱。執行以下命令,檢查Secret是否創建成功。
kubectl -n isito-system get secret coraza-wasm-proxy
步驟三:應用WasmPlugin API到ASM
WasmPlugin API用于聲明在目標網關或網格代理上使用的插件及相關配置。
使用以下內容,創建wasm-plugin.yaml。
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
字段
說明
spec.url
指定OCI鏡像的地址和Tag。
spec.imagePullSecret
指定用于進行鏡像倉庫鑒權的Secret。
spec.selector
指定生效的工作負載。
spec.phase
指定插件生效的階段。
sepc.pluginConfig
指定插件配置。
directives_map
:定義名為default
的directive
,其中規則指定當請求攜帶x-user-type
Header,且值為baned
時,拒絕該請求。default_directives
:指定默認的directive
為default
。
在ASM實例對應的KubeConfig環境下,執行以下命令,將WasmPlugin應用到ASM實例。
kubectl apply -f wasm-plugin.yaml
步驟四:驗證WasmPlugin API是否生效
執行以下命令,訪問httpbin應用。
請將
http://120.27.XXX.XX/
替換為實際的網關地址。關于如何獲取網關地址,請參見獲取入口網關地址。curl -v http://120.27.XXX.XX/
預期輸出:
* 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 ......
可以看到請求返回
200 OK
,符合預期。執行以下命令,為請求添加
header:x-user-type: baned
,再次訪問httpbin應用。請將
http://120.27.XXX.XX/
替換為實際的網關地址。curl -v -H 'x-user-type: baned' http://120.27.XXX.XX/
預期輸出:
* 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
可以看到請求返回
403 Forbidden
,被網關拒絕,符合預期。