默认情况下,服务网格内的工作负载可以互相访问。您可以使用授权策略设置工作负载的访问条件,仅符合要求的请求才能访问对应工作负载。本文以限制访问工作负载的请求路径、方法和客户端IP为例,介绍如何为工作负载设置访问策略。

背景信息

授权策略支持CUSTOM、DENY和ALLOW策略类型。规则的判断存在优先级关系,当CUSTOM、DENY和ALLOW策略同时用于同一个工作负载时,将首先验证CUSTOM策略,然后验证DENY策略,最后验证ALLOW策略,并且存在以下关系:
  • 如果任何一个CUSTOM策略匹配了请求并验证结果为拒绝,则拒绝此请求。
  • 如果任何一个DENY策略匹配了请求并验证结果为拒绝,则拒绝此请求。
  • 如果此工作负载上没有配置ALLOW策略,允许此请求(默认允许)。
  • 如果该工作负载配置了ALLOW策略,并且ALLOW策略匹配此请求,允许此请求。
  • 如果都不满足以上要求,则拒绝此请求。

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

本示例中,所有命名空间下的应用仅支持访问foo命名空间下的httpbin应用的/headers路径,访问其他路径都将失败,foo命名空间下的应用访问httpbin应用不受任何限制。

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

  1. 创建default和foo命名空间。具体操作,请参见管理全局命名空间
  2. 为default命名空间注入Sidecar代理。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏,选择网格实例 > 全局命名空间
    5. 全局命名空间页面单击default命名空间右侧操作列下的启用Sidecar自动注入
    6. 确认对话框单击确定
  3. 重复步骤2,为foo命名空间注入Sidecar代理。

步骤二:部署测试应用

  1. 在default和foo命名空间部署sleep应用。
    1. 使用以下内容,创建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
      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. 在网格详情页面左侧导航栏,选择网格安全中心 > 授权策略,然后在右侧页面,单击创建
  5. 创建页面设置授权策略参数,然后单击创建
    配置项说明
    名称自定义授权策略名称。
    策略类型设置策略类型允许
    命名空间工作负载生效页签,设置命名空间foo
    生效范围选择生效范围Service
    工作负载设置工作负载httpbin
    命名空间(Namespaces)添加请求来源区域,打开命名空间(Namespaces)开关,设置值为foo

    以上设置,使得foo命名空间下的应用都能访问httpbin应用。

    HTTP路径(Paths)添加请求目标区域,打开HTTP路径(Paths)开关,设置值为/headers

    以上设置,使得所有命名空间下的应用仅支持访问foo命名空间下的httpbin应用的/headers路径。

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

  1. 使用default命名空间下的sleep应用访问foo命名空间下的httpbin应用。
    1. 登录容器服务管理控制台
    2. 在控制台左侧导航栏,单击集群
    3. 集群列表页面,单击目标集群名称或者目标集群右侧操作列下的详情
    4. 在集群管理页左侧导航栏,选择工作负载 > 容器组
    5. 容器组页面顶部设置命名空间为default,单击sleep右侧操作列下的终端,选择容器:sleep
    6. 在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"
        }
      }
    7. 在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

      预期输出:

      {
        "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"
        }
      }
    可以看到default命名空间中的应用仅能访问foo命名空间下的httpbin应用的/headers路径,访问其他路径失败,foo命名空间中的应用访问httpbin应用不受任何限制,说明限制访问工作负载的请求路径成功。

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

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

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

  1. 创建default和foo命名空间。具体操作,请参见管理全局命名空间
  2. 为default命名空间注入Sidecar代理。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏,选择网格实例 > 全局命名空间
    5. 全局命名空间页面单击default命名空间右侧操作列下的启用Sidecar自动注入
    6. 确认对话框单击确定
  3. 重复步骤2,为foo命名空间注入Sidecar代理。

步骤二:部署测试应用

  1. 在default和foo命名空间部署sleep应用。
    1. 使用以下内容,创建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
      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. 在网格详情页面左侧导航栏,选择网格安全中心 > 授权策略,然后在右侧页面,单击创建
  5. 创建页面设置授权策略参数,然后单击创建
    配置项说明
    名称自定义授权策略名称。
    策略类型设置策略类型允许
    命名空间工作负载生效页签,设置命名空间foo
    生效范围选择生效范围Service
    工作负载设置工作负载httpbin
    HTTP方法(Methods)添加请求目标区域,打开HTTP方法(Methods)开关,设置值为GET
    HTTP路径(Paths)添加请求目标区域,打开HTTP路径(Paths)开关,设置值为/status/*

    以上设置,使得所有命名空间下的应用仅支持使用GET方法访问foo命名空间下的httpbin应用的/status路径。

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

  1. 登录容器服务管理控制台
  2. 在控制台左侧导航栏,单击集群
  3. 集群列表页面,单击目标集群名称或者目标集群右侧操作列下的详情
  4. 在集群管理页左侧导航栏,选择工作负载 > 容器组
  5. 容器组页面顶部设置命名空间为default,单击sleep右侧操作列下的终端,选择容器:sleep
  6. 在sleep容器终端中执行以下命令,使用POST的方式访问httpbin应用的/status路径。
    curl -I -X POST "httpbin.foo.svc.cluster.local:8000/status/200" -H "accept: text/plain"

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

  7. 执行以下命令,使用GET的方式访问httpbin应用的/IP路径。
    curl -I -X GET "httpbin.foo.svc.cluster.local:8000/IP/200" -H "accept: text/plain"

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

  8. 执行以下命令,使用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代理。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏,选择网格实例 > 全局命名空间
    5. 全局命名空间页面单击default命名空间右侧操作列下的启用Sidecar自动注入
    6. 确认对话框单击确定

步骤二:创建ASM网关

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理
  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择ASM网关 > 入口网关
  3. 入口网关页面,单击创建
  4. 设置网关的基本信息,以下介绍重点参数,其他参数采用默认配置。
    参数说明
    名称自定义网关的名称。
    部署集群选择网关部署的集群。
    网关类型选择南北向-入口
    负载均衡类型选择公网访问
    新建负载均衡选择负载均衡,可选:
    • 使用已有负载均衡:从已有负载均衡列表中选择。
    • 新建负载均衡:单击新建负载均衡,从下拉列表中选择所需的负载均衡规格。
    端口映射单击添加端口,在新增端口行中,选择协议,输入服务端口。
  5. 单击高级选项,设置外部流量策略Local,单击创建

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

  1. 创建虚拟服务。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏,选择流量管理中心 > 虚拟服务,然后在右侧页面,单击使用YAML创建
    5. 设置命名空间foo,场景模板采用默认设置,将以下内容输入到YAML文本框中,然后单击创建
      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. 创建网关规则。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏,选择ASM网关 > 网关规则,然后在右侧页面,单击使用YAML创建
    5. 设置命名空间foo,场景模板采用默认设置,将以下内容输入到YAML文本框中,然后单击创建
      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. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在网格详情页面左侧导航栏,选择网格安全中心 > 授权策略,然后在右侧页面,单击创建
    5. 创建页面设置授权策略参数,然后单击创建
      配置项说明
      名称自定义授权策略名称。
      策略类型设置策略类型拒绝
      命名空间工作负载生效页签,设置命名空间foo
      生效范围选择生效范围Service
      工作负载设置工作负载httpbin
      原始源IP(RemoteIPBlocks)添加请求来源区域,打开原始源IP(RemoteIPBlocks)开关,设置值为步骤2获取的客户端IP。

      以上设置,使得客户端IP将无法访问httpbin应用。

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

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