为工作负载设置访问策略

默认情况下,服务网格内的工作负载可以互相访问。当您需要对集群中的工作负载进行访问控制和权限管理时,可以使用授权策略设置工作负载的访问条件(例如限制请求路径、方法和客户端IP等),确保只有符合要求的请求才能访问对应工作负载,提高网格安全和资源保护。

前提条件

已添加集群到ASM实例

功能介绍

授权策略支持CUSTOM(自定义)、DENY(拒绝)和ALLOW(允许)策略类型。规则的判断存在优先级关系,当CUSTOM、DENY和ALLOW策略同时用于同一个工作负载时,将首先验证CUSTOM策略,然后验证DENY策略,最后验证ALLOW策略,并且存在以下关系:

  • 如果任何一个CUSTOM策略匹配了请求并验证结果为拒绝,则拒绝此请求。

  • 如果任何一个DENY策略匹配了请求并验证结果为拒绝,则拒绝此请求。

  • 如果此工作负载上没有配置ALLOW策略,允许此请求(默认允许)。

  • 如果该工作负载配置了ALLOW策略,并且ALLOW策略匹配此请求,允许此请求。

  • 如果都不满足以上要求,则拒绝此请求。

本文提供以下四个示例,帮助您快速了解和使用授权策略。

示例一:限制访问工作负载的请求路径

本示例中,foo命名空间下的应用可以访问本命名空间下的httpbin应用的/headers路径,访问其他路径都将失败;其它命名空间下的应用无法访问httpbin应用。

步骤一:为default和foo命名空间注入Sidecar代理

  1. 创建default和foo命名空间。具体操作,请参见新建命名空间

  2. 为default和foo命名空间注入Sidecar代理。具体操作,请参见启用自动注入

步骤二:部署测试应用

  1. 在default和foo命名空间部署sleep应用。

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

      展开查看sleep.yaml

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: sleep
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
          service: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: sleep
            containers:
            - name: sleep
              image: curlimages/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
    2. 执行以下命令,在default命名空间部署sleep应用。

      kubectl apply -f sleep.yaml -n default
    3. 执行以下命令,在foo命名空间部署sleep应用。

      kubectl apply -f sleep.yaml -n foo
  2. 在foo命名空间部署httpbin应用。

    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/kennethreitz/httpbin
              imagePullPolicy: IfNotPresent
              name: httpbin
              ports:
              - containerPort: 80
    2. 执行以下命令,在foo命名空间部署httpbin应用。

      kubectl apply -f httpbin.yaml -n foo

步骤三:创建授权策略

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

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

  3. 创建页面,配置相关信息,然后单击创建

    配置项

    说明

    名称

    自定义授权策略名称。

    策略类型

    设置为允许

    命名空间

    工作负载生效页签,设置命名空间foo

    生效范围

    选择Service

    工作负载

    选择httpbin

    请求匹配规则

    1. 添加请求来源区域,打开命名空间(Namespaces)开关,设置值为foo,使foo命名空间下的应用都能访问httpbin应用。

    2. 添加请求目标区域,打开HTTP路径(Paths)开关,设置值为/headers,使所有命名空间下的应用仅支持访问foo命名空间下的httpbin应用的/headers路径。

步骤四:验证限制访问请求路径是否成功

  1. 使用default命名空间下的sleep应用访问foo命名空间下的httpbin应用。

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 容器组

    3. 容器组页面顶部,设置命名空间default,在操作列,单击sleep容器对应的终端 > sleep

    4. 在sleep容器终端中执行以下命令,访问httpbin应用的/headers路径。

      curl httpbin.foo.svc.cluster.local:8000/headers

      返回403,提示访问被拒绝。

    5. 在sleep容器终端中执行以下命令,访问httpbin应用的/ip路径。

      curl httpbin.foo.svc.cluster.local:8000/ip

      返回403,提示访问被拒绝。

  2. 使用foo命名空间下的sleep应用访问foo命名空间下的httpbin应用。

    1. 在集群管理页左侧导航栏,选择工作负载 > 容器组

    2. 容器组页面顶部设置命名空间foo,在操作列,单击sleep容器对应的终端 > sleep

    3. 在sleep容器终端中执行以下命令,访问httpbin应用的/headers路径。

      curl httpbin.foo.svc.cluster.local:8000/headers

      预期输出:

      {
        "headers": {
          "Accept": "*/*",
          "Host": "httpbin.foo.svc.cluster.local:8000",
          "User-Agent": "curl/7.82.0-DEV",
          "X-Envoy-Attempt-Count": "1",
          "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=f7ab4985563b5b1986314d5a36c6e46819213e2f38301f534f00afb7cd4b9164;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/sleep"
        }
      }
    4. 在sleep容器终端中执行以下命令,访问httpbin应用的/ip路径。

      curl httpbin.foo.svc.cluster.local:8000/ip

      返回403,提示访问被拒绝。

    可以看到default命名空间中的应用无法访问foo命名空间下的httpbin应用的任何路径,foo命名空间中的应用可以访问httpbin的/headers路径。

示例二:限制访问工作负载的请求路径和方法

本示例中,所有命名空间下的应用仅支持通过GET请求访问foo命名空间下的httpbin应用的/status路径,访问其他路径或使用其他请求方法都将失败。

步骤一:为default和foo命名空间注入Sidecar代理

  1. 创建default和foo命名空间。具体操作,请参见新建命名空间

  2. 为default和foo命名空间注入Sidecar代理。具体操作,请参见启用自动注入

步骤二:部署测试应用

  1. 在default和foo命名空间部署sleep应用。

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

      展开查看sleep.yaml

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: sleep
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
          service: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: sleep
            containers:
            - name: sleep
              image: curlimages/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
    2. 执行以下命令,在default命名空间部署sleep应用。

      kubectl apply -f sleep.yaml -n default
    3. 执行以下命令,在foo命名空间部署sleep应用。

      kubectl apply -f sleep.yaml -n foo
  2. 在foo命名空间部署httpbin应用。

    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/kennethreitz/httpbin
              imagePullPolicy: IfNotPresent
              name: httpbin
              ports:
              - containerPort: 80
    2. 执行以下命令,在foo命名空间部署httpbin应用。

      kubectl apply -f httpbin.yaml -n foo

步骤三:创建授权策略

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

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

  3. 创建页面,配置相关信息,然后单击创建

  4. 配置项

    说明

    名称

    自定义授权策略名称。

    策略类型

    选择允许

    命名空间

    工作负载生效页签,设置命名空间foo

    生效范围

    选择Service

    工作负载

    选择httpbin

    请求匹配规则

    添加请求目标区域,进行如下配置:

    1. 打开HTTP方法(Methods)开关,设置值为GET

    2. 打开HTTP路径(Paths)开关,设置值为/status/*,使所有命名空间下的应用仅支持使用GET方法访问foo命名空间下的httpbin应用的/status路径。

步骤四:验证限制访问工作负载的请求路径和方法是否成功

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 容器组

  3. 容器组页面顶部,设置命名空间default,在操作列,单击sleep容器对应的终端 > sleep

  4. 在sleep容器终端中执行以下命令,使用POST的方式访问httpbin应用的/status路径。

    curl -I -X POST "httpbin.foo.svc.cluster.local:8000/status/200" -H "accept: text/plain"

    返回403,访问httpbin应用失败。

  5. 执行以下命令,使用GET的方式访问httpbin应用的/IP路径。

    curl -I -X GET "httpbin.foo.svc.cluster.local:8000/IP/200" -H "accept: text/plain"

    返回403,访问httpbin应用失败。

  6. 执行以下命令,使用GET的方式访问httpbin应用的/status路径。

    curl -I -X GET "httpbin.foo.svc.cluster.local:8000/status/200" -H "accept: text/plain"

    预期输出:

    HTTP/1.1 200 OK
    server: envoy
    date: Fri, 29 Apr 2022 03:01: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: 5

    可以看到default命名空间下的应用只有使用GET方式访问httpbin应用的/status路径才能成功,说明限制访问工作负载的请求路径和方法成功。

示例三:限制访问工作负载的客户端IP

限制foo命名空间中的httpbin应用只能被许可的客户端IP访问。

步骤一:为foo命名空间注入Sidecar代理

  1. 创建foo命名空间。具体操作,请参见管理全局命名空间

  2. 为foo命名空间注入Sidecar代理。具体操作,请参见启用自动注入

步骤二:创建ASM网关

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

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择ASM网关 > 入口网关

  3. 入口网关页面,单击创建,配置相关信息,然后单击创建

    配置项

    说明

    名称

    自定义网关的名称。

    部署集群

    选择网关部署的集群。

    负载均衡

    选择CLB(可以根据需要使用NLB,此处以CLB为例),公网访问。

    新建负载均衡

    选择负载均衡,可选:

    • 使用已有负载均衡:从已有负载均衡列表中选择。

    • 新建负载均衡:单击新建负载均衡,从下拉列表中选择所需的负载均衡规格。

    端口映射

    按需选择协议,输入服务端口

    外部流量策略

    单击高级选项,设置外部流量策略Local

步骤三:创建虚拟服务和网关规则

  1. 使用以下内容,在foo命名空间中创建虚拟服务。具体操作,请参见管理虚拟服务

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      gateways:
        - httpbin-gateway
      hosts:
        - '*'
      http:
        - match:
            - uri:
                prefix: /headers
          route:
            - destination:
                host: httpbin
                port:
                  number: 8000
  2. 使用以下内容,在foo命名空间创建网关规则。具体操作,请参见管理网关规则

    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway
      servers:
        - hosts:
            - '*'
          port:
            name: http
            number: 80
            protocol: HTTP

步骤四:创建授权策略

  1. 获取ASM网关IP。具体操作,请参见创建入口网关服务

  2. 获取客户端IP。

    在浏览器地址栏中输入http://{ASM网关IP}/headers,获取X-Envoy-External-Address右侧的IP。客户端IP

  3. 创建授权策略。

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

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

    3. 创建页面,配置相关信息,然后单击创建

      配置项

      说明

      名称

      自定义授权策略名称。

      策略类型

      选择拒绝

      命名空间

      工作负载生效页签,设置命名空间foo

      生效范围

      选择Service

      工作负载

      选择httpbin

      请求匹配规则

      添加请求来源区域,打开原始源IP(RemoteIPBlocks)开关,设置值为步骤2获取的客户端IP,使客户端IP将无法访问httpbin应用。

步骤五:验证限制访问工作负载的客户端IP是否成功

在浏览器地址栏中输入http://{ASM网关IP}/headers,返回RBAC:access denied,访问httpbin应用失败,说明限制访问工作负载的客户端IP成功。验证客户端IP

示例四:限制跨命名空间的服务访问

步骤一:为demo-frontend和demo-server命名空间注入Sidecar代理

  1. 创建demo-frontend和demo-server命名空间。具体操作,请参见新建命名空间

  2. 为demo-frontend和demo-server命名空间注入Sidecar代理。具体操作,请参见启用自动注入

步骤二:部署测试服务

在demo-frontend命名空间下创建发起请求的sleep服务,在demo-server命名空间下创建被访问的httpbin服务。

  1. 在demo-frontend命名空间下创建sleep服务。

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

      展开查看sleep.yaml

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: sleep
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
          service: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: sleep
            containers:
            - name: sleep
              image: curlimages/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,创建sleep服务。

      kubectl apply -f sleep.yaml -n demo-frontend
  2. 在demo-server命名空间下创建httpbin服务。

    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/kennethreitz/httpbin
              imagePullPolicy: IfNotPresent
              name: httpbin
              ports:
              - containerPort: 80
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,创建httpbin服务。

      kubectl apply -f httpbin.yaml -n demo-server
  3. 验证测试服务是否成功注入Sidecar。

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 容器组

    3. 容器组页面上方,命名空间选择demo-frontend,单击sleep服务的容器组名称。

      容器页签下可以看到istio-proxy容器,说明sleep服务注入Sidecar成功。

    4. 容器组页面上方,命名空间选择demo-server,单击httpbin服务的容器组名称。

      容器页签下可以看到istio-proxy容器,说明httpbin服务注入Sidecar成功。

步骤三:使用授权策略实现对跨命名空间服务访问的控制

通过修改授权策略的动作,您可以禁止或允许demo-frontend命名空间下的服务访问demo-server下的服务,实现对跨命名空间服务访问的控制。

  1. 创建授权策略,禁止来自demo-frontend命名空间的访问请求。

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

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

    3. 配置授权策略相关信息,然后单击创建

      配置项

      说明

      名称

      输入授权策略的名称。

      策略类型

      选择拒绝

      命名空间

      工作负载生效页签,设置命名空间demo-server

      生效范围

      选择命名空间生效

      请求匹配规则

      添加请求来源区域,打开命名空间(Namespaces)开关,设置值为demo-frontend

  2. 访问httpbin服务。

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 容器组

    3. 容器组页面上方,命名空间选择demo-frontend,然后在操作列,单击sleep容器对应的终端 > sleep

    4. 在容器组终端中执行以下命令,访问httpbin服务。

      curl -I httpbin.demo-server.svc.cluster.local:8000

      预期输出:

      HTTP/1.1 403 Forbidden
      content-length: 19
      content-type: text/plain
      date: Wed, 11 Oct 2023 08:15:25 GMT
      server: envoy
      x-envoy-upstream-service-time: 4

      返回以上结果,说明demo-frontend命名空间下的服务访问demo-server下的服务失败。

  3. 修改授权策略动作为ALLOW,允许来自demo-frontend命名空间的访问请求。

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

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

    3. 授权策略页面,单击目标策略右侧操作列下的查看YAML

    4. 编辑对话框,修改action参数值为ALLOW,然后单击确定

  4. 在sleep容器组终端中执行以下命令,访问httpbin服务。

    curl -I httpbin.demo-server.svc.cluster.local:8000

    预期输出:

    HTTP/1.1 200 OK
    server: envoy
    date: Wed, 11 Oct 2023 08:21:40 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: 13

    返回以上结果,说明demo-frontend命名空间下的服务成功访问demo-server下的服务。

    可以看到,创建动作Deny的授权策略后,demo-frontend命名空间下的服务访问demo-server下的服务失败。修改授权策略的动作ALLOW,demo-frontend命名空间下的服务访问demo-server下的服务成功,说明通过授权策略控制跨命名空间服务访问成功。