授权政策概览

与可在同一位置运行的单体式应用不同,全球分布式微服务应用会跨网络边界执行调用。这意味着应用的入口点越多,遭遇恶意攻击的机会就越多。由于 Kubernetes pod 使用临时 IP,因此基于 IP 的传统防火墙规则不足以保护工作负载之间的访问。微服务架构需要采用新的安全机制。Cloud Service Mesh 依托于 Kubernetes 服务账号和 Istio 安全政策等多种安全功能,并且提供了更多功能来帮助您保护应用。

本页面为应用运营人员提供了 AuthorizationPolicy 自定义资源 (CR) 概览。授权政策让您可以对应用 (L7) 和传输 (L3/4) 层的工作负载启用访问权限控制。您可以通过配置授权政策来指定权限,即允许服务或用户执行哪些操作?

授权政策

默认情况下,系统允许网格中服务之间(以及最终用户与服务之间)的请求。您可以使用 AuthorizationPolicy CR 为您的工作负载定义细化政策。应用授权政策后,Cloud Service Mesh 会将这些政策分发给 Sidecar 代理。当请求进入工作负载时,Sidecar 代理会检查授权政策,以确定应允许还是拒绝请求。

政策的应用范围

您可以将政策应用于整个服务网格,也可以应用一个命名空间或单个工作负载。

  • 如需应用网格级别的政策,请在 metadata:namespace 字段中指定根命名空间 istio-system

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "mesh-wide"
      namespace: istio-system
    spec:
    ...
    
  • 如需将政策应用于命名空间,请在 metadata:namespace 字段中指定命名空间:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "currencyservice"
      namespace: currencyservice
    spec:
    ...
    
  • 如需将政策限制于特定工作负载,请添加 selector 字段。

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "frontend"
      namespace: demo
    spec:
      selector:
        matchLabels:
          app: frontend
       ...
    

基本结构

授权政策包括政策的应用范围、一个 action 和一个 rules 列表:

  • 如上一节中所述,政策的应用范围可以是整个网格、一个命名空间或特定工作负载。如果您添加了 selector 字段,则此字段会指定政策的目标。

  • action 字段指定是 ALLOW 还是 DENY 请求。如果您未指定操作,则操作默认设置为 ALLOW。为清晰起见,我们建议您始终指定操作。(授权政策还支持 AUDITCUSTOM 操作)。

  • rules 指定何时触发操作。

    • rules 中的 from 字段指定请求的来源

    • rules 中的 to 字段指定请求的操作

    • when 字段指定为了应用规则所需满足的其他条件

在以下示例中:

  • 政策应用于对 demo 命名空间中 frontend 服务发出的请求。

  • 如果请求标头中包含“hello:world”,则允许请求;否则,拒绝请求。

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "hello-world"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: frontend
  action: ALLOW
  rules:
  - when:
    - key: request.headers[hello]
      values: ["world"]

对于请求操作的访问权限控制

您可以通过在 rules 下添加 to 部分来控制对特定请求操作(如 HTTP 方法或 TCP 端口)的访问权限。在以下示例中,仅允许 GETPOST HTTP 方法用于 demo 命名空间中的 currencyservice

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: currencyservice
 namespace: demo
spec:
 selector:
   matchLabels:
     app: currencyservice
 action: ALLOW
 rules:
 - to:
   - operation:
       methods: ["GET", "POST"]

对于经过身份验证的身份的访问权限控制

在前面的示例中,政策允许来自未经身份验证的工作负载的请求。如果您已启用 STRICT 双向 TLS (mTLS),则可以根据 source 部分中请求来自的工作负载或命名空间的身份限制访问权限。

  • 使用 principalsnotPrincipal 字段可控制工作负载级层的访问权限。

  • 使用 namespacesnotNamespaces 字段可控制命名空间级层的访问权限。

以上所有字段都要求您已启用 STRICT mTLS。如果您无法设置 STRICT mTLS,请参阅拒绝明文请求以获取替代解决方案。

确定的工作负载

在以下示例中,仅允许从 frontend 服务发出对于 currencyservice 的请求。如果从其他工作负载发出对于 currencyservice 的请求,则会被系统拒绝。

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "currencyservice"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: currencyservice
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["example-project-1234.svc.id.goog/ns/demo/sa/frontend-sa"]

如需指定服务账号,Cloud Service Mesh 证书授权机构 (Mesh CA) 和 Certificate Authority Service (CA Service) 的 principals 必须采用以下格式:

principals: ["PROJECT_ID.svc.id.goog/ns/NAMESPACE/sa/SERVICE_ACCOUNT_NAME"]

PROJECT_ID.svc.id.goog 是 Mesh CA 的信任网域。如果您使用的是 Istio CA(以前称为 Citadel),则默认信任网域为 cluster.local

确定的命名空间

以下示例展示了一项政策,如果来源不是 foo 命名空间,该政策会拒绝请求:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       notNamespaces: ["foo"]

值匹配

授权政策中的大多数字段都支持以下全部匹配架构:

  • 完全匹配:字符串完全匹配。
  • 使用 "*" 通配符的通配符匹配:
    • 前缀匹配:以 "*" 结尾的字符串。例如,"test.example.*""test.example.com""test.example.com.cn" 匹配。
    • 后缀匹配:以 "*" 开头的字符串。例如,"*.example.com""eng.example.com""test.eng.example.com" 匹配。
  • 存在状态匹配:如需指定某个字段必须存在且非空,请使用 fieldname: ["*"] 格式。这不同于未指定字段,未指定字段意味着匹配任何内容,包括空字段在内。

但也有一些例外情况。例如,以下字段仅支持完全匹配:

  • when 部分下的 key 字段
  • source 部分下的 ipBlocks
  • to 部分下的 ports 字段

以下示例政策允许通过具有 /test/* 前缀或 */info 后缀的路径进行访问:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tester
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        paths: ["/test/*", "*/info"]

排除匹配

要匹配否定条件,比如 when 字段中的 notValuessource 字段中的 notIpBlocksto 字段中的 notPorts,Cloud Service Mesh 支持排除匹配。以下示例需要有效的请求 principals,该请求源自 JWT 身份验证(如果请求路径不是 /healthz)。因此,该政策会从 JWT 身份验证中排除对 /healthz 路径的请求:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: disable-jwt-for-healthz
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        notPaths: ["/healthz"]
    from:
    - source:
        requestPrincipals: ["*"]

拒绝明文请求

在 Cloud Service Mesh 1.5 及更高版本中,自动 mTLS 默认处于启用状态。通过自动 mTLS,客户端 Sidecar 代理会自动检测服务器是否具有 Sidecar。客户端 Sidecar 会将 mTLS 发送到具有 Sidecar 的工作负载,并将纯文本发送到没有 Sidecar 的工作负载。为获得最佳安全性,我们建议您启用 STRICT mTLS

如果您无法为工作负载或命名空间启用 STRICT 模式的 mTLS,您可以:

  • 创建授权政策,以明确允许具有非空 namespaces 或非空 principals 的流量,或者
  • 拒绝具有空 namespacesprincipals 的流量。

由于 namespacesprincipals 只能通过 mTLS 请求进行提取,因此这些政策实际上会拒绝任何明文流量。

如果请求中的主体为空(明文请求就属于这种情况),则以下政策会拒绝请求。如果主体不为空,则该政策会允许请求。["*"] 表示非空匹配项,如果使用 notPrincipals,则表示匹配空主体。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-mtls
  namespace: NAMESPACE
spec:
  action: DENY
  rules:
  - from:
    - source:
        notPrincipals: ["*"]

授权政策优先级

您可以配置单独的 ALLOWDENY 授权政策,但您需要了解政策优先级和默认行为,以确保这些政策符合您的要求。下图说明了政策优先级。

授权政策优先级

以下部分中的示例政策说明了一些默认行为以及一些可能有用的场景。

全部不允许

以下示例展示了与任何内容都不匹配的 ALLOW 政策。默认情况下,如果没有其他 ALLOW 政策,则请求会始终被拒绝

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-nothing
spec:
  action: ALLOW

一个不错的安全做法是先从“全部不允许”政策开始,然后逐步添加更多 ALLOW 政策,从而开放更多对工作负载的访问权限。

拒绝所有访问

以下示例展示了匹配所有内容的一个 DENY 政策。由于 DENY 政策会先于 ALLOW 政策进行评估,因此即使有与请求匹配的 ALLOW 政策,所有请求也会遭到拒绝。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
spec:
  action: DENY
  rules:
  - {}

如果您要暂时停用对工作负载的所有访问权限,则“全部拒绝”政策非常有用。

允许所有访问

以下示例展示了一个与所有内容都匹配且允许对工作负载的完整访问权限的 ALLOW 政策。“全部允许”政策会使其他 ALLOW 政策毫无用处,因为该政策始终允许请求。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all
spec:
  action: ALLOW
  rules:
  - {}

如果要暂时公开对工作负载的完整访问权限,则“全部允许”政策非常有用。如果存在任何 DENY 政策,则请求可能仍会被拒绝,因为 DENY 政策在 ALLOW 政策之前评估。

最佳做法

  1. 为每个服务创建一个 Kubernetes 服务账号,并在 Deployment 中指定服务账号。例如:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: frontend-sa
      namespace: demo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: frontend
      namespace:demo
    spec:
      selector:
        matchLabels:
          app: frontend
      template:
        metadata:
          labels:
            app: frontend
        spec:
          serviceAccountName: frontend-sa
        ...
    
  2. “全部不允许”政策开始,逐步添加更多 ALLOW 政策,从而开放更多对工作负载的访问权限。

  3. 如果您为服务使用 JWT,请执行以下操作:

    1. 创建 DENY 政策以阻止未经身份验证的请求,例如:

      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: requireJWT
        namespace: admin
      spec:
        action: DENY
        rules:
        -  from:
          - source:
              notRequestPrincipals: ["*"]
      
    2. 应用“全部不允许”政策。

    3. 为每个工作负载定义 ALLOW 政策。如需查看示例,请参阅 JWT 令牌

后续步骤

详细了解 Cloud Service Mesh 安全功能:

详细了解 Istio 文档中的授权政策: