为 Pod 配置服务账户
Kubernetes 为在您的集群中运行的客户端提供了两种截然不同的方式,或者以其他方式与您集群的控制平面建立关系,以对API 服务器进行身份验证。
服务帐户为在 Pod 中运行的进程提供身份,并映射到 ServiceAccount 对象。当您对 API 服务器进行身份验证时,您将自己标识为特定用户。Kubernetes 识别用户的概念,但是 Kubernetes 本身没有用户 API。
本任务指南介绍了 ServiceAccounts,它们存在于 Kubernetes API 中。该指南向您展示了一些为 Pod 配置 ServiceAccounts 的方法。
开始之前
您需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果您还没有集群,可以使用minikube创建一个集群,或者可以使用以下 Kubernetes 游乐场之一
使用默认服务帐户访问 API 服务器
当 Pod 联系 API 服务器时,Pod 会以特定 ServiceAccount(例如,default
)的身份进行身份验证。每个命名空间中至少有一个 ServiceAccount。
每个 Kubernetes 命名空间都包含至少一个 ServiceAccount:该命名空间的默认 ServiceAccount,名为 default
。如果您在创建 Pod 时没有指定 ServiceAccount,Kubernetes 会自动在该命名空间中分配名为 default
的 ServiceAccount。
您可以获取您已创建的 Pod 的详细信息。例如
kubectl get pods/<podname> -o yaml
在输出中,您会看到一个字段 spec.serviceAccountName
。如果您在创建 Pod 时没有指定该值,Kubernetes 会自动设置该值。
在 Pod 中运行的应用程序可以使用自动挂载的服务帐户凭据访问 Kubernetes API。有关详细信息,请参阅访问集群。
当 Pod 以 ServiceAccount 身份进行身份验证时,其访问级别取决于正在使用的授权插件和策略。
API 凭据在 Pod 被删除时会自动撤销,即使存在最终器。特别是,API 凭据会在 Pod 上设置的 .metadata.deletionTimestamp
(删除时间戳通常是接受删除请求的时间加上 Pod 的终止宽限期)之后 60 秒被撤销。
选择退出 API 凭据自动挂载
如果您不希望kubelet自动挂载 ServiceAccount 的 API 凭据,您可以选择退出默认行为。您可以通过在 ServiceAccount 上设置 automountServiceAccountToken: false
来选择退出在 /var/run/secrets/kubernetes.io/serviceaccount/token
上自动挂载服务帐户的 API 凭据
例如
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
您也可以选择退出为特定 Pod 自动挂载 API 凭据
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
如果 ServiceAccount 和 Pod 的 .spec
都为 automountServiceAccountToken
指定了值,则 Pod 规范优先。
使用多个 ServiceAccount
每个命名空间都至少有一个 ServiceAccount:称为 default
的默认 ServiceAccount 资源。您可以使用以下命令列出您当前命名空间中的所有 ServiceAccount 资源
kubectl get serviceaccounts
输出类似于以下内容
NAME SECRETS AGE
default 1 1d
您可以像这样创建其他 ServiceAccount 对象
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
EOF
ServiceAccount 对象的名称必须是有效的DNS 子域名称。
如果您获得了服务帐户对象的完整转储,如下所示
kubectl get serviceaccounts/build-robot -o yaml
输出类似于以下内容
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2019-06-16T00:12:34Z
name: build-robot
namespace: default
resourceVersion: "272500"
uid: 721ab723-13bc-11e5-aec2-42010af0021e
您可以使用授权插件来设置服务帐户的权限。
要使用非默认服务帐户,请将 Pod 的 spec.serviceAccountName
字段设置为要使用的 ServiceAccount 的名称。
您只能在创建 Pod 时或在新 Pod 的模板中设置 serviceAccountName
字段。您不能更新已存在 Pod 的 .spec.serviceAccountName
字段。
注意
.spec.serviceAccount
字段是 .spec.serviceAccountName
的弃用别名。如果您想从工作负载资源中删除这些字段,请在Pod 模板上将这两个字段都显式设置为为空。清理
如果您尝试从上面的示例中创建 build-robot
ServiceAccount,则可以通过运行以下命令进行清理
kubectl delete serviceaccount/build-robot
手动为 ServiceAccount 创建 API 令牌
假设您有一个名为“build-robot”的现有服务帐户,如前所述。
您可以使用 kubectl
为该 ServiceAccount 获取一个有限时 API 令牌
kubectl create token build-robot
该命令的输出是一个令牌,您可以使用该令牌以该 ServiceAccount 的身份进行身份验证。您可以使用 kubectl create token
的 --duration
命令行参数请求特定令牌持续时间(实际发行的令牌持续时间可能更短,甚至可能更长)。
Kubernetes v1.31 [beta]
启用 ServiceAccountTokenNodeBinding
和 ServiceAccountTokenNodeBindingValidation
功能,并使用 kubectl
v1.31 或更高版本,可以创建直接绑定到节点的服务帐户令牌
kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456
令牌将一直有效,直到它过期或关联的节点或服务帐户被删除。
注意
Kubernetes v1.22 之前的版本会自动创建用于访问 Kubernetes API 的长期凭据。这种较旧的机制是基于创建令牌 Secret,然后可以将其挂载到正在运行的 Pod 中。在更新的版本中,包括 Kubernetes v1.31,API 凭据是通过使用TokenRequest API 直接获取的,并使用投影卷挂载到 Pod 中。使用此方法获得的令牌具有绑定生命周期,并在将它们挂载到的 Pod 被删除时会自动失效。
您仍然可以手动创建服务帐户令牌 Secret;例如,如果您需要一个永不过期的令牌。但是,建议改为使用TokenRequest 子资源来获取访问 API 的令牌。
手动为 ServiceAccount 创建一个长期 API 令牌
如果您要为 ServiceAccount 获取 API 令牌,请使用带有特殊批注 kubernetes.io/service-account.name
的新 Secret。
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: build-robot-secret
annotations:
kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF
如果您使用以下命令查看 Secret
kubectl get secret/build-robot-secret -o yaml
您会看到 Secret 现在包含“build-robot”ServiceAccount 的 API 令牌。
由于您设置的批注,控制平面会自动为该 ServiceAccounts 生成令牌,并将它们存储到关联的 Secret 中。控制平面还会清理已删除 ServiceAccounts 的令牌。
kubectl describe secrets/build-robot-secret
输出类似于以下内容
Name: build-robot-secret
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: build-robot
kubernetes.io/service-account.uid: da68f9c6-9d26-11e7-b84e-002dc52800da
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1338 bytes
namespace: 7 bytes
token: ...
注意
此处省略了 token
的内容。
注意不要在旁观者可能看到您的终端/计算机屏幕的地方显示 kubernetes.io/service-account-token
Secret 的内容。
当您删除具有关联 Secret 的 ServiceAccount 时,Kubernetes 控制平面会自动从该 Secret 中清理长期令牌。
注意
如果您使用以下命令查看 ServiceAccount
kubectl get serviceaccount build-robot -o yaml
您无法在 ServiceAccount API 对象.secrets
字段中看到 build-robot-secret
Secret,因为该字段仅填充自动生成的 Secret。
将 ImagePullSecrets 添加到服务帐户
首先,创建一个 imagePullSecret。接下来,验证它是否已创建。例如
创建一个 imagePullSecret,如在 Pod 上指定 ImagePullSecrets中所述。
kubectl create secret docker-registry myregistrykey --docker-server=<registry name> \ --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \ --docker-email=DUMMY_DOCKER_EMAIL
验证它是否已创建。
kubectl get secrets myregistrykey
输出类似于以下内容
NAME TYPE DATA AGE myregistrykey kubernetes.io/.dockerconfigjson 1 1d
将镜像拉取 Secret 添加到服务帐户
接下来,修改命名空间的默认服务帐户以使用此 Secret 作为 imagePullSecret。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'
您也可以通过手动编辑对象来实现相同的结果。
kubectl edit serviceaccount/default
sa.yaml
文件的输出类似于:
您选择的文本编辑器将打开一个类似于以下内容的配置:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
resourceVersion: "243024"
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
使用您的编辑器,删除带有键 resourceVersion
的行,添加 imagePullSecrets:
的行并保存。将 uid
值保持与您找到的值相同。
在您进行这些更改后,编辑后的 ServiceAccount 看起来像这样:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
imagePullSecrets:
- name: myregistrykey
验证新 Pod 是否设置了 imagePullSecrets。
现在,当在当前命名空间中创建新的 Pod 并使用默认 ServiceAccount 时,新 Pod 的 spec.imagePullSecrets
字段会自动设置。
kubectl run nginx --image=<registry name>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'
输出为:
myregistrykey
ServiceAccount 令牌卷投影
Kubernetes v1.20 [稳定]
注意
要启用并使用令牌请求投影,您必须为 kube-apiserver
指定以下每个命令行参数:
--service-account-issuer
- 定义服务帐户令牌签发者的标识符。您可以多次指定
--service-account-issuer
参数,这对于启用签发者的非破坏性更改很有用。当此标志被多次指定时,第一个用于生成令牌,所有这些都用于确定哪些签发者被接受。您必须运行 Kubernetes v1.22 或更高版本才能多次指定--service-account-issuer
。 --service-account-key-file
- 指定包含 PEM 编码 X.509 私钥或公钥(RSA 或 ECDSA)的文件的路径,用于验证 ServiceAccount 令牌。指定的文件可以包含多个密钥,并且可以将标志与不同的文件一起多次指定。如果多次指定,则由任何指定密钥签名的令牌都被 Kubernetes API 服务器视为有效。
--service-account-signing-key-file
- 指定包含服务帐户令牌签发者当前私钥的文件的路径。签发者使用此私钥签署已发出的 ID 令牌。
--api-audiences
(可以省略)- 定义 ServiceAccount 令牌的受众。服务帐户令牌身份验证器验证用于 API 的令牌是否绑定到这些受众中的至少一个。如果多次指定
api-audiences
,则针对任何指定受众的令牌都被 Kubernetes API 服务器视为有效。如果您指定--service-account-issuer
命令行参数,但未设置--api-audiences
,则控制平面默认为包含签发者 URL 的单元素受众列表。
kubelet 也可以将 ServiceAccount 令牌投影到 Pod 中。您可以指定令牌的所需属性,例如受众和有效期。这些属性不能在默认 ServiceAccount 令牌上配置。当 Pod 或 ServiceAccount 被删除时,令牌也将对 API 无效。
您可以使用名为 ServiceAccountToken
的 投影卷 类型来配置 Pod 的 spec
的此行为。
来自此投影卷的令牌是 JSON Web 令牌 (JWT)。此令牌的 JSON 负载遵循一个定义明确的模式 - 绑定到 Pod 的令牌的示例负载
{
"aud": [ # matches the requested audiences, or the API server's default audiences when none are explicitly requested
"https://kubernetes.default.svc"
],
"exp": 1731613413,
"iat": 1700077413,
"iss": "https://kubernetes.default.svc", # matches the first value passed to the --service-account-issuer flag
"jti": "ea28ed49-2e11-4280-9ec5-bc3d1d84661a", # ServiceAccountTokenJTI feature must be enabled for the claim to be present
"kubernetes.io": {
"namespace": "kube-system",
"node": { # ServiceAccountTokenPodNodeInfo feature must be enabled for the API server to add this node reference claim
"name": "127.0.0.1",
"uid": "58456cb0-dd00-45ed-b797-5578fdceaced"
},
"pod": {
"name": "coredns-69cbfb9798-jv9gn",
"uid": "778a530c-b3f4-47c0-9cd5-ab018fb64f33"
},
"serviceaccount": {
"name": "coredns",
"uid": "a087d5a0-e1dd-43ec-93ac-f13d89cd13af"
},
"warnafter": 1700081020
},
"nbf": 1700077413,
"sub": "system:serviceaccount:kube-system:coredns"
}
使用服务帐户令牌投影启动 Pod
要为 Pod 提供具有受众 vault
和有效期为两小时的令牌,您可以定义一个类似于以下内容的 Pod 清单
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault
创建 Pod
kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml
kubelet 将:代表 Pod 请求并存储令牌;在可配置的文件路径下向 Pod 提供令牌;并在令牌接近过期时刷新令牌。如果令牌比其总生存时间 (TTL) 的 80% 更旧,或者如果令牌比 24 小时更旧,则 kubelet 会主动请求令牌轮换。
应用程序负责在令牌轮换时重新加载令牌。对于应用程序来说,定期(例如:每 5 分钟一次)加载令牌,而无需跟踪实际过期时间,通常已经足够了。
服务帐户签发者发现
Kubernetes v1.21 [稳定]
如果您已在集群中为 ServiceAccount 启用了 令牌投影,那么您也可以使用发现功能。Kubernetes 为客户端提供了一种以身份提供者身份联合的方式,以便一个或多个外部系统可以充当信赖方。
注意
签发者 URL 必须符合 OIDC 发现规范。实际上,这意味着它必须使用 https
方案,并且应在 {service-account-issuer}/.well-known/openid-configuration
处提供一个 OpenID 提供者配置。
如果 URL 不符合,则不会注册或访问 ServiceAccount 签发者发现端点。
启用后,Kubernetes API 服务器通过 HTTP 发布 OpenID 提供者配置文档。配置文档在 /.well-known/openid-configuration
处发布。OpenID 提供者配置有时被称为发现文档。Kubernetes API 服务器还通过 HTTP 在 /openid/v1/jwks
处发布相关的 JSON Web 密钥集 (JWKS)。
注意
在/.well-known/openid-configuration
和 /openid/v1/jwks
处提供的响应旨在与 OIDC 兼容,但并不严格符合 OIDC。这些文档只包含验证 Kubernetes 服务帐户令牌所需的必要参数。使用 RBAC 的集群包含一个名为 system:service-account-issuer-discovery
的默认 ClusterRole。一个默认 ClusterRoleBinding 将此角色分配给 system:serviceaccounts
组,所有 ServiceAccount 都隐式属于该组。这允许在集群上运行的 Pod 通过其挂载的服务帐户令牌访问服务帐户发现文档。此外,管理员可以选择根据其安全要求以及他们打算与之联合的外部系统将角色绑定到 system:authenticated
或 system:unauthenticated
。
JWKS 响应包含信赖方可用于验证 Kubernetes 服务帐户令牌的公钥。信赖方首先查询 OpenID 提供者配置,并使用响应中的 jwks_uri
字段查找 JWKS。
在许多情况下,Kubernetes API 服务器无法在公共互联网上访问,但用户或服务提供商可以提供公开端点来提供 API 服务器的缓存响应。在这种情况下,可以通过将 --service-account-jwks-uri
标志传递给 API 服务器来覆盖 OpenID 提供者配置中的 jwks_uri
,使其指向公共端点,而不是 API 服务器的地址。与签发者 URL 一样,JWKS URI 要求使用 https
方案。
下一步
另请参阅
- 阅读 集群管理员指南以了解服务帐户
- 阅读有关 Kubernetes 中的授权
- 阅读有关 机密
- 或学习 使用机密安全地分发凭据
- 但也要记住,使用机密以 ServiceAccount 身份进行身份验证已过时。建议的替代方案是 ServiceAccount 令牌卷投影。
- 阅读有关 投影卷。
- 有关 OIDC 发现的背景信息,请阅读 服务帐户签名密钥检索 Kubernetes 增强提案
- 阅读 OIDC 发现规范