使用ASM安全策略接入外部OPA执行引擎

ASM对Istio原生安全资源的场景进行封装,提供ASM安全策略功能,便于一站式配置常见的安全场景。ASM集成了开放策略代理(OPA)插件,通过OPA定义访问控制策略,可以使您的应用实现细粒度的访问控制。本文介绍如何使用ASM安全策略接入外部OPA执行引擎。

前提条件

功能介绍

ASM目前默认的OPA部署方式为Sidecar模式。当开启OPA之后,重启应用Pod,ASM就会在应用Pod中注入一个OPA容器。此后,业务容器所有的请求都会经过OPA Sidecar校验。Sidecar模式是完全的Pod内部访问,因此可以实现较低的延迟,适用于一些对延迟比较敏感的业务。

但是Sidecar模式存在一些弊端,例如资源占用、应用接入需要重启Pod、接入方式不够灵活等。集中式OPA在这些方面可以和Sidecar模式的OPA形成互补。集中式OPA可以实现更低的资源占用、应用无需重启即可接入、自由决定到达应用的哪些请求执行OPA策略等。下文将介绍如何部署一个集中式的OPA授权服务并将其接入应用。

OPA部署方式.png

步骤一:部署OPA

  1. 使用以下内容,创建asm-opa.yaml文件。

    YAML文件部署了一个OPA Service、OPA Deployment和Secret。

    Kind

    说明

    Deployment

    • 镜像registry-vpc.cn-hangzhou.aliyuncs.com/acs/opa:0.46.1-istio-3-static请替换为您实际的集群地域。

    • 该OPA引擎默认打开了日志--set=decision_logs.console=true,方便进行调试。

    Secret

    Secret定义了OPA策略,含义如下:

    • 如果请求路径是health,放行请求。

    • 如果请求的方法是HEAD,放行请求。

    • 如果用户名称是alice,放行请求。

      说明

      用户名称来自请求的AuthorizationHeader,形式为Authorization: Basic ${用户名:密码字符串的base64编码}

    展开查看asm-opa.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: asm-opa
      labels:
        app: opa
    spec:
      ports:
        - name: grpc
          port: 9191
          targetPort: 9191
          protocol: TCP
        - name: http
          port: 8181
          targetPort: 8181
          protocol: TCP
      selector:
        app: opa
    ---
    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: opa
      labels:
        app: opa
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: opa
      template:
        metadata:
          labels:
            app: opa
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          containers:
            - name: opa
              image: registry-vpc.cn-hangzhou.aliyuncs.com/acs/opa:0.46.1-istio-3-static
              securityContext:
                runAsUser: 1111
              volumeMounts:
                - readOnly: true
                  mountPath: /policy
                  name: opa-policy
              args:
                - "run"
                - "--server"
                - "--addr=0.0.0.0:8181"
                - "--diagnostic-addr=0.0.0.0:8282"
                - "--set=plugins.envoy_ext_authz_grpc.addr=:9191"
                - "--set=plugins.envoy_ext_authz_grpc.path=asm/authz/allow"
                - "--set=decision_logs.console=true"
                - "--ignore=.*"
                - "/policy/policy.rego"
              ports:
                - containerPort: 9191
                  protocol: TCP
              resources:
                limits:
                  cpu: "0"
                  memory: "0"
          volumes:
            - name: opa-policy
              secret:
                secretName: opa-policy
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: opa-policy
    type: Opaque
    stringData:
      policy.rego: |
        package asm.authz
    
        import future.keywords
    
        import input.attributes.request.http as http_request
        import input.parsed_path
    
        default allow := false
    
        allow if {
          parsed_path[0] == "health"
        }
    
        allow if {
          http_request.method == "HEAD"
        }
    
        allow if {
          user_name == "alice"
        }
    
        user_name := parsed if {
          [_, encoded] := split(http_request.headers.authorization, " ")
          [parsed, _] := split(base64url.decode(encoded), ":")
        }
    
  2. 使用ACK集群的KubeConfig,执行以下命令,部署OPA。

    kubectl apply -f asm-opa.yaml

步骤二:使用ASM安全策略接入OPA

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择网格安全中心 > ASM安全策略

  3. ASM安全策略页面,单击创建,在创建ASM安全策略对话框,单击自定义授权服务卡片,然后单击确定

  4. 配置自定义授权相关信息。

    1. 创建自定义授权服务页面,配置步骤一部署的OPA授权服务信息,然后单击下一步

      创建自定义授权服务.png
    2. 工作负载和匹配规则配置向导,单击添加工作负载组,然后在新建工作负载组对话框,输入工作负载组名称,单击添加工作负载

    3. 添加工作负载对话框,选中工作负载生效命名空间选择default工作负载类型选择Service,在选择负载区域选中httpbin,单击Dingtalk_20230302182310.png图标,然后单击确定添加工作负载.png

    4. 新建工作负载组对话框的匹配规则列表区域匹配模式选择选中请求必须经过鉴权匹配规则选择自定义匹配规则,打开HTTP路径(Path)开关并配置为/status/*,然后单击确定

      新建工作负载组.png
    5. 工作负载和匹配规则配置向导,单击提交

      创建成功后,界面显示如下。ASM安全策略创建成功.png

步骤三:对httpbin应用进行访问测试

  1. 执行以下命令,访问/路径。

    curl ${ASM网关IP}/ -I -X GET

    预期输出:

    HTTP/1.1 200 OK
    server: istio-envoy
    date: Tue, 25 Jul 2023 08:30:58 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

    预期输出表明该路径不需要鉴权,直接通过。

  2. 执行以下命令,未携带合法参数,访问/status/201路径。

    curl ${ASM网关IP}/status/201 -I -X GET

    预期输出:

    HTTP/1.1 403 Forbidden
    date: Tue, 25 Jul 2023 08:31:18 GMT
    server: istio-envoy
    content-length: 0
    x-envoy-upstream-service-time: 1

    预期输出表明未携带合法参数,请求被拒绝。

  3. 执行以下命令,携带合法参数,访问/status/201路径。

    curl ${ASM网关IP}/status/201 -I -X GET --user alice:testpassword

    预期输出:

    HTTP/1.1 201 Created
    server: istio-envoy
    date: Tue, 25 Jul 2023 08:31:38 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 3

    预期输出表明携带合法参数,请求通过。

步骤四:更新OPA策略

调用OPA引擎的HTTP接口,更新OPA策略。

  1. 执行以下命令,要求只有bob用户才可以正常访问HTTP,之前的alice用户不能访问。

    kubectl exec deployment/httpbin -c istio-proxy -- curl asm-opa:8181/v1/policies/policy/policy.rego -XPUT --data-binary 'package asm.authz
    
    import future.keywords
    import input.attributes.request.http as http_request
    import input.parsed_path
    
    default allow := false
    
    allow if {
      parsed_path[0] == "health"
    }
    
    allow if {
      http_request.method == "HEAD"
    }
    
    allow if {
      user_name == "bob"
    }
    
    user_name := parsed if {
      [_, encoded] := split(http_request.headers.authorization, " ")
      [parsed, _] := split(base64url.decode(encoded), ":")
    }'
  2. 执行以下命令,使用bob用户访问httpbin。

    curl ${ASM网关IP}/status/201 -I -X GET --user bob:testpassword

    预期输出:

    HTTP/1.1 201 Created
    server: istio-envoy
    date: Tue, 25 Jul 2023 08:32:16 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 3

    预期输出表明bob用户访问成功。

  3. 执行以下命令,使用alice用户访问httpbin。

    curl ${ASM网关IP}/status/201 -I -X GET --user alice:testpassword  

    预期输出:

    HTTP/1.1 403 Forbidden
    date: Tue, 25 Jul 2023 08:32:49 GMT
    server: istio-envoy
    content-length: 0
    x-envoy-upstream-service-time: 1

    预期输出表明alice用户访问被禁止。