鉴权

Kubernetes 鉴权机制和支持的鉴权模式的详细信息。

Kubernetes 鉴权在身份认证之后进行。 通常,发出请求的客户端必须经过身份验证(登录)才能允许其请求; 但是,Kubernetes 在某些情况下也允许匿名请求。

有关鉴权在 API 访问控制中的位置这类进一步的语境信息, 请阅读控制对 Kubernetes API 的访问

鉴权裁定

Kubernetes 对 API 请求的鉴权在 API 服务器内进行。 API 服务器根据所有策略评估所有请求属性,可能还会咨询外部服务,然后允许或拒绝该请求。

API 请求的所有部分都必须通过某种鉴权机制才能继续, 换句话说:默认情况下拒绝访问。

当系统配置了多个鉴权模块时,Kubernetes 将按顺序使用每个模块。 如果任何鉴权模块批准拒绝请求,则立即返回该决定,并且不会与其他鉴权模块协商。 如果所有模块对请求没有意见,则拒绝该请求。 总体拒绝裁决意味着 API 服务器拒绝请求并以 HTTP 403(禁止)状态进行响应。

鉴权中使用的请求属性

Kubernetes 仅审查以下 API 请求属性:

  • 用户 —— 身份验证期间提供的 user 字符串。
  • —— 经过身份验证的用户所属的组名列表。
  • 额外信息 —— 由身份验证层提供的任意字符串键到字符串值的映射。
  • API —— 指示请求是否针对 API 资源。
  • 请求路径 —— 各种非资源端点的路径,如 /api/healthz
  • API 请求动词 —— API 动词 getlistcreateupdatepatchwatchproxyredirectdeletedeletecollection 用于资源请求。 要确定资源 API 端点的请求动词,请参阅请求动词和鉴权
  • HTTP 请求动词 —— HTTP 动词 getpostputdelete 用于非资源请求。
  • 资源 —— 正在访问的资源的 ID 或名称(仅限资源请求)- 对于使用 getupdatepatchdelete 动词的资源请求,你必须提供资源名称。
  • 子资源 —— 正在访问的子资源(仅限资源请求)。
  • 名字空间 —— 正在访问的对象的名称空间(仅适用于名字空间资源请求)。
  • API 组 —— 正在访问的 API 组 (仅限资源请求)。空字符串表示核心 API 组

请求动词和鉴权

非资源请求

对于 /api/v1/.../apis/<group>/<version>/... 之外的端点的请求被视为非资源请求(Non-Resource Requests), 并使用该请求的 HTTP 方法的小写形式作为其请求动词。

例如,对 /api/healthz 这类端点的 GET 请求将使用 get 作为其动词。

资源请求

为了确定资源 API 端点的请求动词,Kubernetes 会映射所使用的 HTTP 动词, 并考虑该请求是否作用于单个资源或资源集合:

HTTP 动词请求动词
POSTcreate
GETHEADget(针对单个资源)、list(针对集合,包括完整的对象内容)、watch(用于查看单个资源或资源集合)
PUTupdate
PATCHpatch
DELETEdelete(针对单个资源)、deletecollection(针对集合)

Kubernetes 有时使用专门的动词以对额外的权限进行鉴权。例如:

  • 身份认证的特殊情况
    • 对核心 API 组中 usersgroupsserviceaccounts 以及 authentication.k8s.io API 组中的 userextras 所使用的 impersonate 动词。
  • RBAC
    • rbac.authorization.k8s.io API 组中 rolesclusterroles 资源的 bindescalate 动词

鉴权上下文

Kubernetes 需要 REST API 请求所共有的属性, 这意味着 Kubernetes 鉴权可与现有的组织范围或云提供商范围的访问控制系统配合使用, 这些系统可以处理除 Kubernetes API 之外的其他 API。

鉴权模式

AlwaysAllow
此模式允许所有请求,但存在安全风险, 仅当你的 API 请求不需要鉴权时(例如,用于测试),才使用此鉴权模式。
AlwaysDeny
此模式阻止所有请求。此鉴权模式仅适用于测试。
ABAC基于属性的访问控制
Kubernetes ABAC 模式定义了一种访问控制范例,通过使用将属性组合在一起的策略向用户授予访问权限, 策略可以使用任何类型的属性(用户属性、资源属性、对象、环境属性等)。
RBAC基于角色的访问控制
Kubernetes RBAC 是一种根据企业内各个用户的角色来管理其对计算机或网络资源的访问权限的方法。 在此上下文中,访问权限是单个用户执行特定任务(例如查看、创建或修改文件)的能力。 在这种模式下,Kubernetes 使用 rbac.authorization.k8s.io API 组来驱动鉴权决策, 允许你通过 Kubernetes API 动态配置权限策略。
Node
一种特殊用途的鉴权模式,根据 kubelet 计划运行的 Pod 向其授予权限。 要了解有关 Node 鉴权模式的更多信息,请参阅 Node 鉴权
Webhook
Kubernetes 的 Webhook 鉴权模式用于鉴权,进行同步 HTTP 调用, 阻塞请求直到远程 HTTP 服务响应查询。你可以编写自己的软件来处理这种向外调用,也可以使用生态系统中的解决方案。

鉴权模式配置

你可以仅使用命令行参数, 或使用配置文件来配置 Kubernetes API 服务器的鉴权链,后者目前是 Beta 特性。

你必须选择两种配置方法之一;不允许同时设置 --authorization-config 路径并使用 --authorization-mode--authorization-webhook-* 命令行参数配置鉴权 Webhook。 如果你尝试这样做,API 服务器会在启动期间报告错误消息,然后立即退出。

命令行鉴权模式配置

特性状态: Kubernetes v1.8 [stable]

你可以使用以下模式:

  • --authorization-mode=ABAC(基于属性的访问控制模式)
  • --authorization-mode=RBAC(基于角色的访问控制模式)
  • --authorization-mode=Node(节点鉴权组件)
  • --authorization-mode=Webhook(Webhook 鉴权模式)
  • --authorization-mode=AlwaysAllow(始终允许请求;存在安全风险)
  • --authorization-mode=AlwaysDeny(始终拒绝请求)

你可以选择多种鉴权模式;例如:--authorization-mode=Node,Webhook

Kubernetes 根据你在 API 服务器的命令行上指定鉴权模块的顺序来检查鉴权模块, 因此较早的模块具有更高的优先级来允许或拒绝请求。

你不能将 --authorization-mode 命令行参数与用于使用本地文件配置鉴权--authorization-config 命令行参数结合使用。

有关 API 服务器命令行参数的更多信息,请阅读 kube-apiserver 参考

使用鉴权配置文件配置 API 服务器

特性状态: Kubernetes v1.30 [beta] (enabled by default: true)

作为一项 Beta 级别特性,Kubernetes 允许你配置可包含多个 Webhook 的鉴权链。 该链中的鉴权项可以具有明确定义的参数,这些参数可以按特定顺序检查请求, 从而为你提供细粒度的控制,例如在失败时明确拒绝。

配置文件方法甚至允许你指定 CEL规则, 在将请求发送到 Webhook 之前对其进行预过滤,从而帮助你防止不必要的调用。 修改配置文件时,API 服务器还会自动重新加载鉴权链。

你可以使用 --authorization-config 命令行参数指定鉴权配置的路径。

如果你想使用命令行参数而不是配置文件,这也是一种有效且受支持的方法。 某些鉴权功能(例如:多个 Webhook、Webhook 失败策略和预过滤规则)仅在使用鉴权配置文件时可用。

示例配置

---
#
# 请勿按原样使用配置,这只是一个示例。
#
apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthorizationConfiguration
authorizers:
  - type: Webhook
    # 用于描述鉴权人的名称
    # 这明确用于监控机制的指标
    # 注意
    #   - 该字段的验证与今天的 K8s 标签的验证方式类似。
    # 必填,无默认值
    name: webhook
    webhook:
      # 缓存来自 Webhook 鉴权组件的“鉴权”响应的持续时间
      # 与设置 `--authorization-webhook-cache-authorized-ttl` 标志相同
      # 默认值:5m0s
      authorizedTTL: 30s
      # 缓存来自 Webhook 鉴权组件的“未授权”响应的持续时间。
      # 与设置 `--authorization-webhook-cache-unauthorized-ttl` 标志相同
      # 默认值:30s
      unauthorizedTTL: 30s
      # Webhook 请求超时
      # 允许的最大时间为 30 秒。
      # 必填,没有默认值。
      timeout: 3s
      # 要发送到 Webhook 并期望从 webhook 获得的 authorization.k8s.io SubjectAccessReview 的 API 版本。
      # 与设置 `--authorization-webhook-version` 标志相同
      # 必填,无默认值
      # 有效值:v1beta1、v1
      subjectAccessReviewVersion: v1
      # MatchConditionSubjectAccessReviewVersion 指定评估 CEL 表达式的 SubjectAccessReview 版本
      # 有效值:v1
      # 必填,无默认值
      matchConditionSubjectAccessReviewVersion: v1
      # 当 Webhook 请求无法完成或返回格式错误的响应或评估 matchConditions 时出现错误时,控制鉴权决定。
      # 有效值:
      #   - NoOpinion:继续联系后续鉴权组件,看其中是否有人允许该请求
      #   - Deny:拒绝请求而不咨询后续鉴权组件
      # 必填,没有默认值。
      failurePolicy: Deny
      connectionInfo:
        # 控制 Webhook 如何与服务器通信。
        # 有效值:
        # - KubeConfigFile:使用 kubeConfigFile 中指定的文件来定位服务器。
        # - InClusterConfig:使用集群内配置来调用由 kube-apiserver 托管的 SubjectAccessReview API,kube-apiserver 不允许使用此模式。
        type: KubeConfigFile
        # 连接信息的 KubeConfig 文件的路径
        # 如果 connectionInfo.Type 是 KubeConfig,则为必填项
        kubeConfigFile: /kube-system-authz-webhook.yaml
        # matchConditions 是将请求发送到此 Webhook 必须满足的条件列表。
        # matchConditions 为空列表表示匹配所有请求。
        # 最多允许 64 个匹配条件。
        #
        # 精确匹配逻辑如下(按顺序):
        # 1. 如果至少一个 matchCondition 计算结果为 FALSE,则跳过 Webhook。
        # 2. 如果所有 matchConditions 计算结果为 TRUE,则调用 Webhook。
        # 3. 如果至少一个 matchCondition 计算结果为错误(但没有一个为 FALSE):
        # - 如果 FailurePolicy=Deny,则 Webhook 拒绝请求
        # - 如果 FailurePolicy=NoOpinion,则忽略错误并跳过 Webhook
      matchConditions:
        # 表达式表示将由 CEL 评估的表达式。必须评估为布尔值。
        # CEL 表达式可以访问 v1 版本中的 SubjectAccessReview 的内容。
        # 如果请求变量中 subjectAccessReviewVersion 指定的版本是 v1beta1,
        # 在评估 CEL 表达式之前,内容将转换为 v1 版本。
      #
      # CEL 文档:https://kubernetes.io/docs/reference/using-api/cel/
      #
      # 仅向 Webhook 发送资源请求
      - expression: has(request.resourceAttributes)
      # 仅拦截对 kube-system 的请求
      - expression: request.resourceAttributes.namespace == 'kube-system'
      # 不要拦截来自 kube-system 服务账户的请求
      - expression: "!('system:serviceaccounts:kube-system' in request.groups)"
  - type: Node
    name: node
  - type: RBAC
    name: rbac
  - type: Webhook
    name: in-cluster-authorizer
    webhook:
      authorizedTTL: 5m
      unauthorizedTTL: 30s
      timeout: 3s
      subjectAccessReviewVersion: v1
      failurePolicy: NoOpinion
      connectionInfo:
        type: InClusterConfig

使用配置文件配置鉴权链时,请确保所有控制平面节点具有相同的文件内容。升级/降级集群时,请记下 API 服务器配置。 例如,如果从 Kubernetes 1.30 升级到 Kubernetes 1.31,则需要确保配置文件的格式是 Kubernetes 1.31 可以理解的,然后再升级集群。 如果降级到 1.30,则需要适当设置配置。

鉴权配置和重新加载

当 API 服务器观察到文件的更改时,Kubernetes 会重新加载鉴权配置文件, 如果没有观察到更改事件,则也会按照 60 秒的计划重新加载。

通过创建或编辑工作负载来提升权限

能够直接或通过启用间接工作负载管理的对象在命名空间中创建/编辑 Pod 的用户可能能够在该命名空间中提升其权限。 权限提升的潜在途径包括 Kubernetes API 扩展及其相关的 控制器

权限提升路径

如果你允许攻击者或不值得信任的用户在该命名空间中运行任意 Pod, 则他们可以通过不同的方式在命名空间内获得额外的权限:

  • 在该命名空间中挂载任意 Secret
    • 可用于访问其他工作负载的机密信息
    • 可用于获取更具特权的 ServiceAccount 的服务帐户令牌
  • 在该命名空间中使用任意 ServiceAccount
    • 可以作为另一个工作负载执行 Kubernetes API 操作(模拟)
    • 可以执行 ServiceAccount 拥有的任何特权操作
  • 在该命名空间中挂载或使用其他工作负载的 ConfigMap
    • 可用于获取其他工作负载的信息,例如数据库主机名。
  • 在该命名空间中挂载其他工作负载的卷
    • 可用于获取其他工作负载的信息并进行更改。

检查 API 访问

kubectl 提供 auth can-i 子命令,用于快速查询 API 鉴权。 该命令使用 SelfSubjectAccessReview API 来确定当前用户是否可以执行给定操作, 无论使用何种鉴权模式该命令都可以工作。

kubectl auth can-i create deployments --namespace dev

输出类似于:

yes
kubectl auth can-i create deployments --namespace prod

输出类似于:

no

管理员可以将此与用户扮演(User Impersonation) 结合使用,以确定其他用户可以执行的操作。

kubectl auth can-i list secrets --namespace dev --as dave

输出类似于:

no

类似地,检查名字空间 dev 里的 dev-sa 服务账户是否可以列举名字空间 target 里的 Pod:

kubectl auth can-i list pods \
	--namespace target \
	--as system:serviceaccount:dev:dev-sa

输出类似于:

yes

SelfSubjectAccessReview 是 authorization.k8s.io API 组的一部分,它将 API 服务器鉴权公开给外部服务。该组中的其他资源包括:

  • SubjectAccessReview : 对任意用户的访问进行评估,而不仅仅是当前用户。 当鉴权决策被委派给 API 服务器时很有用。例如,kubelet 和扩展 API 服务器使用它来确定用户对自己的 API 的访问权限。

  • LocalSubjectAccessReview : 与 SubjectAccessReview 类似,但仅限于特定的名字空间。

  • SelfSubjectRulesReview : 返回用户可在名字空间内执行的操作集的审阅。 用户可以快速汇总自己的访问权限,或者用于 UI 中的隐藏/显示动作。

可以通过创建普通的 Kubernetes 资源来查询这些 API,其中返回对象的响应 status 字段是查询的结果,例如:

kubectl create -f - -o yaml << EOF
apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
spec:
  resourceAttributes:
    group: apps
    name: deployments
    verb: create
    namespace: dev
EOF

生成的 SelfSubjectAccessReview 类似于:

apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
metadata:
  creationTimestamp: null
spec:
  resourceAttributes:
    group: apps
    name: deployments
    namespace: dev
    verb: create
status:
  allowed: true
  denied: false

接下来

最后修改 October 16, 2024 at 1:30 PM PST: Update structured authz examples (1f1779e777)