Kubernetes v1.34:用于镜像拉取的服务帐户令牌集成进阶至 Beta

Kubernetes 社区通过减少对长期凭证的依赖,持续推进安全最佳实践。继 Kubernetes v1.33 中的 Alpha 版本成功发布后,Kubelet 凭证提供程序的服务账号令牌集成功能现已在 Kubernetes v1.34 中进入 Beta 阶段,这使我们离在 Kubernetes 集群中消除长期存在的镜像拉取 Secret 更近了一步。

此增强功能允许凭证提供程序使用特定于工作负载的服务账号令牌来获取镜像仓库凭证,为传统的镜像拉取 Secret 提供了一种安全、临时的替代方案。

Beta 版本有哪些新功能?

Beta 版本的推出带来了几个重要的变化,使该功能更加健壮和生产就绪。

必需的 cacheType 字段

与 Alpha 版本的重大变更:在使用服务账号令牌时,凭证提供程序配置中必须包含 cacheType 字段。该字段是 Beta 版本中的新增字段,必须指定以确保正确的缓存行为。

# CAUTION: this is not a complete configuration example, just a reference for the 'tokenAttributes.cacheType' field.
tokenAttributes:
  serviceAccountTokenAudience: "my-registry-audience"
  cacheType: "ServiceAccount"  # Required field in beta
  requireServiceAccount: true

选择两种缓存策略

  • Token:按服务账号令牌缓存凭证(当凭证生命周期与令牌绑定时使用)。当凭证提供程序将服务账号令牌转换为与令牌具有相同生命周期的镜像仓库凭证时,或者当镜像仓库直接支持 Kubernetes 服务账号令牌时,此策略非常有用。注意:kubelet 无法直接将服务账号令牌发送到镜像仓库;需要凭证提供程序插件将令牌转换为镜像仓库期望的用户名/密码格式。
  • ServiceAccount:按服务账号身份缓存凭证(当凭证对所有使用相同服务账号的 Pod 都有效时使用)。

隔离的镜像拉取凭证

Beta 版本在使用服务账号令牌进行镜像拉取时,为容器镜像提供了更强的安全隔离。它确保 Pod 只能访问使用其被授权使用的 ServiceAccount 拉取的镜像。这可以防止对敏感容器镜像的未经授权访问,并实现精细的访问控制,使不同的工作负载可以根据其 ServiceAccount 拥有不同的镜像仓库权限。

当凭证提供程序使用服务账号令牌时,系统会为每个拉取的镜像跟踪 ServiceAccount 的身份(命名空间、名称和 UID)。当一个 Pod 尝试使用缓存的镜像时,系统会验证该 Pod 的 ServiceAccount 与最初用于拉取该镜像的 ServiceAccount 完全匹配。

管理员可以通过删除并重新创建 ServiceAccount 来撤销对先前拉取镜像的访问,这将更改其 UID 并使缓存镜像的访问失效。

有关此功能的更多详细信息,请参阅镜像拉取凭证验证文档。

工作原理

配置

凭证提供程序通过配置 tokenAttributes 字段来选择使用 ServiceAccount 令牌:

#
# CAUTION: this is an example configuration.
#          Do not use this for your own cluster!
#
apiVersion: kubelet.config.k8s.io/v1
kind: CredentialProviderConfig
providers:
- name: my-credential-provider
  matchImages:
  - "*.myregistry.io/*"
  defaultCacheDuration: "10m"
  apiVersion: credentialprovider.kubelet.k8s.io/v1
  tokenAttributes:
    serviceAccountTokenAudience: "my-registry-audience"
    cacheType: "ServiceAccount"  # New in beta
    requireServiceAccount: true
    requiredServiceAccountAnnotationKeys:
    - "myregistry.io/identity-id"
    optionalServiceAccountAnnotationKeys:
    - "myregistry.io/optional-annotation"

镜像拉取流程

从高层次来看,kubelet 与你的凭证提供程序和容器运行时的协作方式如下:

  • 当镜像在本地不存在时

    • kubelet 使用配置的 cacheTypeTokenServiceAccount)检查其凭证缓存。
    • 如果需要,kubelet 会为 Pod 的 ServiceAccount 请求一个 ServiceAccount 令牌,并将其连同任何必需的注解一起传递给凭证提供程序。
    • 提供程序将该令牌交换为镜像仓库凭证,并将其返回给 kubelet
    • kubelet 根据 cacheType 策略缓存凭证,并使用这些凭证拉取镜像。
    • kubelet 记录与所拉取镜像关联的 ServiceAccount 坐标(命名空间、名称、UID),以供后续授权检查使用。
  • 当镜像已在本地存在时

    • kubelet 验证 Pod 的 ServiceAccount 坐标是否与为缓存镜像记录的坐标匹配。
    • 如果它们完全匹配,则无需从镜像仓库拉取即可使用缓存的镜像。
    • 如果它们不同,kubelet 将使用新 ServiceAccount 的凭证执行一次新的拉取。
  • 启用镜像拉取凭证验证后

    • 授权将使用记录的 ServiceAccount 坐标来强制执行,确保 Pod 只能使用由其被授权使用的 ServiceAccount 拉取的镜像。
    • 管理员可以通过删除并重新创建 ServiceAccount 来撤销访问权限;UID 会发生变化,先前记录的授权将不再匹配。

受众限制

Beta 版本建立在服务账号节点受众限制(自 v1.33 起为 Beta)的基础上,以确保 kubelet 只能请求授权受众的令牌。管理员使用 RBAC 配置允许的受众,以使 kubelet 能够请求用于镜像拉取的服务账号令牌。

#
# CAUTION: this is an example configuration.
#          Do not use this for your own cluster!
#
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubelet-credential-provider-audiences
rules:
- verbs: ["request-serviceaccounts-token-audience"]
  apiGroups: [""]
  resources: ["my-registry-audience"]
  resourceNames: ["registry-access-sa"]  # Optional: specific SA

开始使用 Beta 版本

先决条件

  1. Kubernetes v1.34 或更高版本
  2. 启用特性门控KubeletServiceAccountTokenForCredentialProviders=true(Beta,默认启用)
  3. 凭证提供程序支持:更新你的凭证提供程序以处理 ServiceAccount 令牌。

从 Alpha 版本迁移

如果你已经在使用 Alpha 版本,迁移到 Beta 版本只需做少量更改:

  1. 添加 cacheType 字段:更新你的凭证提供程序配置,以包含必需的 cacheType 字段。
  2. 检查缓存策略:根据你的提供程序的行为,在 TokenServiceAccount 缓存类型之间进行选择。
  3. 测试受众限制:确保你的 RBAC 配置或其他集群授权规则能正确限制令牌受众。

示例设置

这是一个使用服务账号令牌设置凭证提供程序的完整示例(此示例假设你的集群使用 RBAC 授权):

#
# CAUTION: this is an example configuration.
#          Do not use this for your own cluster!
#

# Service Account with registry annotations
apiVersion: v1
kind: ServiceAccount
metadata:
  name: registry-access-sa
  namespace: default
  annotations:
    myregistry.io/identity-id: "user123"
---
# RBAC for audience restriction
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: registry-audience-access
rules:
- verbs: ["request-serviceaccounts-token-audience"]
  apiGroups: [""]
  resources: ["my-registry-audience"]
  resourceNames: ["registry-access-sa"]  # Optional: specific ServiceAccount
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubelet-registry-audience
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: registry-audience-access
subjects:
- kind: Group
  name: system:nodes
  apiGroup: rbac.authorization.k8s.io
---
# Pod using the ServiceAccount
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  serviceAccountName: registry-access-sa
  containers:
  - name: my-app
    image: myregistry.example/my-app:latest

接下来是什么?

对于 Kubernetes v1.35,我们——Kubernetes SIG Auth——预计该功能将保持在 Beta 阶段,并将继续征求反馈。

你可以在 Kubernetes 文档的用于镜像拉取的服务账号令牌页面上了解有关此功能的更多信息。

你也可以在 KEP-4412 上关注后续 Kubernetes 版本中的进展。

行动号召

在这篇博文中,我介绍了 Kubernetes v1.34 中 Kubelet 凭证提供程序的服务账号令牌集成功能进入 Beta 阶段的情况。我讨论了关键改进,包括必需的 cacheType 字段以及与 Ensure Secret Pull Images 的增强集成。

在 Alpha 阶段,我们收到了社区的积极反馈,并希望在我们为 GA 稳定此功能的过程中听到更多声音。特别是,我们希望凭证提供程序实现者在与新的 Beta API 和缓存机制集成时提供反馈。请通过 Kubernetes Slack 上的 #sig-auth-authenticators-dev 频道与我们联系。

如何参与

如果你有兴趣参与此功能的开发、分享反馈或参与任何其他正在进行的 SIG Auth 项目,请通过 Kubernetes Slack 上的 #sig-auth 频道与我们联系。

也欢迎你参加每两周一次的 SIG Auth 会议,会议在每隔一个星期三举行。