为 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 凭据自动挂载

如果您不希望 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 字段。

清理

如果您尝试从上面的示例中创建 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 命令行参数请求特定的令牌持续时间(实际颁发的令牌的持续时间可能更短,甚至可能更长)。

ServiceAccountTokenNodeBindingServiceAccountTokenNodeBindingValidation 功能启用且 KUBECTL_NODE_BOUND_TOKENS 环境变量设置为 true 时,可以创建直接绑定到 Node 的服务帐户令牌

KUBECTL_NODE_BOUND_TOKENS=true kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456

该令牌在过期或关联的 Node 或服务帐户被删除之前一直有效。

手动为 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:          ...

当您删除具有关联 Secret 的 ServiceAccount 时,Kubernetes 控制平面会自动从该 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 [稳定]

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 为客户端提供了一种作为身份提供者联合的方式,以便一个或多个外部系统可以充当信赖方

启用后,Kubernetes API 服务器通过 HTTP 发布 OpenID 提供者配置文档。配置文档发布在 /.well-known/openid-configuration 上。OpenID 提供者配置有时被称为发现文档。Kubernetes API 服务器还通过 HTTP 在 /openid/v1/jwks 上发布相关的 JSON Web 密钥集 (JWKS)。

使用 RBAC 的集群包含一个名为 system:service-account-issuer-discovery 的默认 ClusterRole。一个默认的 ClusterRoleBinding 将此角色分配给 system:serviceaccounts 组,所有 ServiceAccount 隐式地属于该组。这允许在集群上运行的 Pod 通过其挂载的服务帐户令牌访问服务帐户发现文档。此外,管理员可以选择根据其安全要求以及他们打算与之联合的外部系统将角色绑定到 system:authenticatedsystem:unauthenticated

JWKS 响应包含信赖方可用于验证 Kubernetes 服务帐户令牌的公钥。信赖方首先查询 OpenID 提供者配置,并使用响应中的 jwks_uri 字段查找 JWKS。

在许多情况下,Kubernetes API 服务器在公共互联网上不可用,但用户或服务提供商可以提供从 API 服务器提供缓存响应的公共端点。在这些情况下,可以通过将 --service-account-jwks-uri 标志传递给 API 服务器来覆盖 OpenID 提供者配置中的 jwks_uri,使其指向公共端点,而不是 API 服务器的地址。与发行者 URL 一样,JWKS URI 要求使用 https 方案。

下一步

另请参阅

上次修改时间:2024 年 6 月 27 日下午 2:43 PST:更新 configure-service-account.md (505b0c5a0b)