文档

使用Coraza Wasm插件在ASM网关上实现WAF能力

更新时间:

ASM通过VirtualService API提供丰富的路由能力和请求操纵能力,通过AuthorizationPolicy API提供丰富的安全能力,但是在一些特定场景下,这些API可能仍然不能满足需求。您可以通过编写自定义的Wasm Filter并添加到ASM网关或Sidecar来实现复杂场景的自定义行为。本文介绍如何通过WasmPlugin API为ASM网关启用Coraza WAF。

前提条件

步骤一:部署httpbin应用,并配置网关规则和虚拟服务

  1. 部署应用。

    1. 使用以下内容,创建httpbin.yaml。

      展开查看httpbin.yaml

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: httpbin
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: httpbin
        labels:
          app: httpbin
          service: httpbin
      spec:
        ports:
        - name: http
          port: 8000
          targetPort: 80
        selector:
          app: httpbin
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: httpbin
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: httpbin
            version: v1
        template:
          metadata:
            labels:
              app: httpbin
              version: v1
          spec:
            serviceAccountName: httpbin
            containers:
            - image: docker.io/kong/httpbin
              imagePullPolicy: IfNotPresent
              name: httpbin
              ports:
              - containerPort: 80
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,将httpbin应用部署至集群。

      kubectl apply -f httpbin.yaml
  2. 创建网关规则。

    1. 使用以下内容,创建ingressgateway.yaml。

      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
    2. 在ASM实例对应的KubeConfig环境下,执行以下命令,为网关配置网关规则,暴露80端口。

      kubectl apply -f ingressgateway.yaml
  3. 创建虚拟服务。

    1. 使用以下内容,创建ingressgateway-vs.yaml。

      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
    2. 在ASM实例对应的KubeConfig环境下,执行以下命令,为网关配置到httpbin应用的路由。

      kubectl apply -f ingressgateway-vs.yaml

步骤二:制作Wasm Plugin OCI镜像并推送至阿里云容器镜像服务

Wasm Plugin有以下三种加载方式。本文以第二种方式为例,制作Wasm Plugin的OCI镜像,并将其推送到阿里云容器镜像服务。

  • 将Wasm扩展存储至configmap,并Mount至容器,ASM网格代理或ASM网关从本地文件系统加载。

  • 将Wasm扩展制作成OCI镜像上传至镜像仓库,ASM网格代理或ASM网关从镜像仓库拉取。

  • 将Wasm扩展上传至云存储或其他支持HTTP协议下载的服务,ASM网格代理或网关通过网络下载。

  1. 下载Coraza Wasm插件。

    1. 执行以下命令,下载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
    2. 执行以下命令,为Coraza Wasm插件重命名。

      上一步解压完成后,会得到coraza-proxy-wasm.wasm文件。ASM要求Wasm插件必须命名为plugin.wasm,因此需要重命名。

      mv coraza-proxy-wasm.wasm plugin.wasm
  2. 制作镜像并推送到ACR企业版实例。

    1. 创建命名空间。

      1. 登录容器镜像服务控制台,在左侧导航栏,单击实例列表

      2. 实例列表页面,单击目标企业版实例。

      3. 在左侧导航栏,单击仓库管理 > 命名空间,然后单击创建命名空间,配置相关信息,然后单击确定

        本示例配置命名空间名称为wasm

    2. 在左侧导航栏,单击仓库管理 > 访问控制,单击公网页签,打开访问入口开关,按需添加公网白名单。

      如果不需要白名单控制,请删除默认的白名单。

      说明

      本文采用公网地址作为演示。在实际应用中,您可以配置专有网络访问以实现更高的私密性和更好的网络性能。更多信息,请参见配置专有网络的访问控制

    3. 执行以下命令,登录ACR企业版实例,输入密码。

      buildah login --username=登录用户名 enterprise-registry.cn-hangzhou.cr.aliyuncs.com
    4. 执行以下命令,创建名为coraza-proxy-wasm的镜像,将步骤1获取的plugin.wasm文件拷贝至镜像内。

      buildah --name coraza-proxy-wasm from scratch
      buildah copy coraza-proxy-wasm plugin.wasm ./
    5. 执行以下命令,将镜像推送到镜像仓库。

      buildah commit coraza-proxy-wasm docker://enterprise-registry.cn-hangzhou.cr.aliyuncs.com/wasm/coraza-proxy-wasm:latest
    6. 验证镜像是否推送成功。

      1. 登录容器镜像服务控制台,在左侧导航栏,单击实例列表

      2. 实例列表页面,单击目标企业版实例。

      3. 在左侧导航栏,单击仓库管理 > 镜像仓库,单击coraza-proxy-wasm,然后在左侧导航栏,单击镜像版本

        若显示刚推送的标签为latest的镜像,表明镜像推送成功。

步骤三:配置镜像拉取权限

创建私有仓库后,您需要使用容器镜像服务配置的口令创建Secret。ASM网格代理或ASM网关将使用Secret中的授权信息在拉取镜像时进行认证。

  1. 执行以下命令,创建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所在的工作负载同一命名空间。本文在ASM网关上应用Wasm Plugin,因此采用了istio-system命名空间。在实际使用中,请您根据工作负载所在的命名空间调整以上命令中-n参数后的命名空间名称。

  2. 执行以下命令,检查Secret是否创建成功。

    kubectl -n isito-system get secret coraza-wasm-proxy 

步骤四:应用WasmPlugin API到ASM

WasmPlugin API用于声明在目标网关或网格代理上使用的插件及相关配置。

  1. 使用以下内容,创建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:定义名为defaultdirective,其中规则指定当请求携带x-user-type Header,且值为baned时,拒绝该请求。

    • default_directives:指定默认的directivedefault

  2. 在ASM实例对应的KubeConfig环境下,执行以下命令,将WasmPlugin应用到ASM实例。

    kubectl apply -f wasm-plugin.yaml

步骤五:验证WasmPlugin API是否生效

  1. 执行以下命令,访问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,符合预期。

  2. 执行以下命令,为请求添加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,被网关拒绝,符合预期。

  • 本页导读 (1)
文档反馈