服务账号

了解 Kubernetes 中的 ServiceAccount 对象。

此页面介绍了 Kubernetes 中的 ServiceAccount 对象,提供有关服务账户如何工作、用例、限制、替代方案以及额外指导资源链接的信息。

什么是服务账户?

服务账户是一种非人类账户,在 Kubernetes 中,它在 Kubernetes 集群中提供一个独特的身份。应用程序 Pod、系统组件以及集群内部和外部的实体可以使用特定 ServiceAccount 的凭据来标识为该 ServiceAccount。此身份在各种情况下都很有用,包括向 API 服务器进行身份验证或实施基于身份的安全策略。

服务账户作为 ServiceAccount 对象存在于 API 服务器中。服务账户具有以下属性:

  • 命名空间化: 每个服务账户都绑定到一个 Kubernetes 命名空间。每个命名空间在创建时都会获得一个 default ServiceAccount

  • 轻量: 服务账户存在于集群中,并在 Kubernetes API 中定义。你可以快速创建服务账户以启用特定任务。

  • 可移植: 复杂容器化工作负载的配置包可能包含系统组件的服务账户定义。服务账户的轻量级特性和命名空间化的身份使配置具有可移植性。

服务账户与用户账户不同,用户账户是集群中经过身份验证的人类用户。默认情况下,用户账户不存在于 Kubernetes API 服务器中;相反,API 服务器将用户身份视为不透明数据。你可以使用多种方法作为用户账户进行身份验证。一些 Kubernetes 发行版可能会添加自定义扩展 API 以在 API 服务器中表示用户账户。

服务账户与用户账户的比较
描述ServiceAccount用户或组
位置Kubernetes API (ServiceAccount 对象)外部
访问控制Kubernetes RBAC 或其他授权机制Kubernetes RBAC 或其他身份和访问管理机制
预期用途工作负载、自动化人员

默认服务账户

当你创建一个集群时,Kubernetes 会自动为集群中的每个命名空间创建一个名为 default 的 ServiceAccount 对象。在每个命名空间中的 default 服务账户默认没有权限,除了在启用基于角色的访问控制 (RBAC) 时 Kubernetes 授予所有已认证主体的默认 API 发现权限。如果你删除了命名空间中的 default ServiceAccount 对象,控制平面 会用一个新的对象替换它。

如果你在命名空间中部署一个 Pod,并且没有手动为该 Pod 分配 ServiceAccount,Kubernetes 会将该命名空间的 default ServiceAccount 分配给该 Pod。

Kubernetes 服务账户的用例

作为一般准则,你可以在以下场景中使用服务账户来提供身份:

  • 你的 Pod 需要与 Kubernetes API 服务器通信,例如在以下情况下:
    • 提供对存储在 Secrets 中的敏感信息的只读访问。
    • 授予跨命名空间访问权限,例如允许 example 命名空间中的 Pod 读取、列出和监视 kube-node-lease 命名空间中的 Lease 对象。
  • 你的 Pod 需要与外部服务通信。例如,一个工作负载 Pod 需要一个商业云 API 的身份,并且商业提供商允许配置适当的信任关系。
  • 使用 imagePullSecret 向私有镜像仓库进行身份验证.
  • 外部服务需要与 Kubernetes API 服务器通信。例如,作为 CI/CD 管道的一部分向集群进行身份验证。
  • 你在集群中使用第三方安全软件,该软件依赖不同 Pod 的 ServiceAccount 身份将这些 Pod 分组到不同的上下文中。

如何使用服务账户

要使用 Kubernetes 服务账户,你需要执行以下操作:

  1. 使用 Kubernetes 客户端(如 kubectl)或定义对象的清单创建 ServiceAccount 对象。

  2. 使用授权机制(如 RBAC)向 ServiceAccount 对象授予权限。

  3. 在 Pod 创建期间将 ServiceAccount 对象分配给 Pod。

    如果你正在使用来自外部服务的身份,请检索 ServiceAccount 令牌并从该服务中使用它。

有关说明,请参阅为 Pod 配置服务账户

授予 ServiceAccount 权限

你可以使用内置的 Kubernetes 基于角色的访问控制 (RBAC) 机制,为每个服务账户授予所需的最小权限。你创建一个授予访问权限的“角色”,然后将该角色“绑定”到你的 ServiceAccount。RBAC 允许你定义一组最小权限,以便服务账户权限遵循最小特权原则。使用该服务账户的 Pod 不会获得超出正常运行所需的更多权限。

有关说明,请参阅ServiceAccount 权限

使用 ServiceAccount 进行跨命名空间访问

你可以使用 RBAC 允许一个命名空间中的服务账户对集群中不同命名空间中的资源执行操作。例如,假设你在 `dev` 命名空间中有一个服务账户和一个 Pod,并且你希望你的 Pod 能够查看 `maintenance` 命名空间中运行的 Job。你可以创建一个授予列出 Job 对象权限的 Role 对象。然后,你将在 `maintenance` 命名空间中创建一个 RoleBinding 对象,将该 Role 绑定到 ServiceAccount 对象。现在,`dev` 命名空间中的 Pod 可以使用该服务账户列出 `maintenance` 命名空间中的 Job 对象。

为 Pod 分配 ServiceAccount

要为 Pod 分配 ServiceAccount,你可以在 Pod 规约中设置 spec.serviceAccountName 字段。然后 Kubernetes 会自动将该 ServiceAccount 的凭据提供给 Pod。在 v1.22 及更高版本中,Kubernetes 使用 TokenRequest API 获取一个短生命周期的、自动轮换的令牌,并将其作为投影卷挂载。

默认情况下,Kubernetes 会为 Pod 提供已分配 ServiceAccount 的凭据,无论是 default ServiceAccount 还是你指定的自定义 ServiceAccount。

要阻止 Kubernetes 自动注入指定 ServiceAccount 或 default ServiceAccount 的凭据,请将 Pod 规约中的 automountServiceAccountToken 字段设置为 false

在 v1.22 之前的版本中,Kubernetes 将一个长期有效的静态令牌作为 Secret 提供给 Pod。

手动检索 ServiceAccount 凭据

如果你需要 ServiceAccount 凭据以挂载到非标准位置,或者用于非 API 服务器的受众,请使用以下方法之一:

  • TokenRequest API(推荐):在你的“应用程序代码”中请求一个短生命周期的服务账户令牌。令牌会自动过期,并可在过期时轮换。如果你有一个不了解 Kubernetes 的传统应用程序,你可以在同一个 Pod 中使用一个 sidecar 容器来获取这些令牌并使其可用于应用程序工作负载。
  • 令牌卷投影(也推荐):在 Kubernetes v1.20 及更高版本中,使用 Pod 规约指示 kubelet 将服务账户令牌作为“投影卷”添加到 Pod 中。投影令牌会自动过期,并且 kubelet 会在令牌过期之前轮换它。
  • 服务账户令牌 Secret(不推荐):你可以将服务账户令牌作为 Kubernetes Secret 挂载到 Pod 中。这些令牌不会过期,也不会轮换。在 v1.24 之前的版本中,每个服务账户都会自动创建一个永久令牌。由于与静态、长期凭据相关的风险,此方法不再推荐,尤其是在大规模使用时。LegacyServiceAccountTokenNoAutoGeneration 特性门(在 Kubernetes v1.24 到 v1.26 中默认启用)阻止 Kubernetes 自动为 ServiceAccounts 创建这些令牌。该特性门在 v1.27 中被移除,因为它已升级为 GA 状态;你仍然可以手动创建无限期的服务账户令牌,但应考虑其安全影响。

限制对 Secret 的访问(已弃用)

特性状态: Kubernetes v1.32 [已弃用]

Kubernetes 提供了一个名为 kubernetes.io/enforce-mountable-secrets 的注解,你可以将其添加到 ServiceAccounts。当应用此注解时,ServiceAccount 的 Secret 只能挂载到指定类型的资源上,从而增强了集群的安全态势。

你可以使用清单向 ServiceAccount 添加注解:

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    kubernetes.io/enforce-mountable-secrets: "true"
  name: my-serviceaccount
  namespace: my-namespace

当此注解设置为 "true" 时,Kubernetes 控制平面会确保此 ServiceAccount 的 Secret 受到某些挂载限制。

  1. 作为卷挂载到 Pod 中的每个 Secret 的名称必须出现在 Pod 的 ServiceAccount 的 secrets 字段中。
  2. 在 Pod 中使用 envFrom 引用的每个 Secret 的名称也必须出现在 Pod 的 ServiceAccount 的 secrets 字段中。
  3. 在 Pod 中使用 imagePullSecrets 引用的每个 Secret 的名称也必须出现在 Pod 的 ServiceAccount 的 secrets 字段中。

通过理解和执行这些限制,集群管理员可以保持更严格的安全配置,并确保只有适当的资源才能访问 Secret。

验证服务账户凭据

ServiceAccount 使用签名的 JSON Web Token (JWT) 向 Kubernetes API 服务器以及存在信任关系的其他系统进行身份验证。根据令牌的颁发方式(使用 TokenRequest 颁发的时间受限令牌,或使用 Secret 的传统机制颁发),ServiceAccount 令牌可能还具有过期时间、受众以及令牌“开始”有效的时间。当作为 ServiceAccount 运行的客户端尝试与 Kubernetes API 服务器通信时,客户端会在 HTTP 请求中包含 Authorization: Bearer 头部。API 服务器按以下方式检查该持有者令牌的有效性:

  1. 检查令牌签名。
  2. 检查令牌是否已过期。
  3. 检查令牌声明中的对象引用当前是否有效。
  4. 检查令牌当前是否有效。
  5. 检查受众声明。

TokenRequest API 为 ServiceAccount 生成“绑定令牌”。此绑定与作为该 ServiceAccount 的客户端(例如 Pod)的生命周期相关联。有关绑定 Pod 服务账户令牌的 JWT 架构和负载示例,请参见令牌卷投影

对于使用 TokenRequest API 颁发的令牌,API 服务器还会检查正在使用 ServiceAccount 的特定对象引用是否存在,并通过该对象的唯一 ID 进行匹配。对于作为 Secret 挂载在 Pod 中的传统令牌,API 服务器会根据 Secret 检查令牌。

有关身份验证过程的更多信息,请参阅身份验证

在你的代码中验证服务账户凭据

如果你自己的服务需要验证 Kubernetes 服务账户凭据,你可以使用以下方法:

Kubernetes 项目建议你使用 TokenReview API,因为此方法会在删除绑定到 API 对象(如 Secrets、ServiceAccounts、Pods 或 Nodes)的令牌时立即使其失效。例如,如果你删除了包含投影 ServiceAccount 令牌的 Pod,集群会立即使该令牌失效,并且 TokenReview 会立即失败。如果你改为使用 OIDC 验证,你的客户端会继续将令牌视为有效,直到令牌达到其过期时间戳。

你的应用程序应始终定义其接受的受众,并应检查令牌的受众是否与应用程序预期的受众匹配。这有助于最大限度地缩小令牌的范围,使其只能在你的应用程序中使用,而不能在其他地方使用。

替代方案

下一步

本页面上的项目引用了提供 Kubernetes 所需功能的第三方产品或项目。Kubernetes 项目作者不对这些第三方产品或项目负责。有关详细信息,请参阅 CNCF 网站指南

在提议添加额外第三方链接的更改之前,你应该阅读内容指南

最后修改于 2024 年 11 月 19 日太平洋标准时间晚上 10:53:解决评论 (3b8c927a3b)