为Pod配置服务账户
服务账户为Pod中运行的进程提供了一个标识。
Note:本文是服务账户的用户使用介绍,描述服务账号在集群中如何起作用。你的集群管理员可能已经对你的集群做了定制,因此导致本文中所讲述的内容并不适用。
当你(自然人)访问集群时(例如,使用kubectl),API服务器将你的身份验证为特定的用户帐户(当前这通常是admin,除非你的集群管理员已经定制了你的集群配置)。Pod内的容器中的进程也可以与api服务器接触。当它们进行身份验证时,它们被验证为特定的服务帐户(例如,default)。
在开始之前
你必须拥有一个Kubernetes的集群,同时你的Kubernetes集群必须带有kubectl命令行工具。建议在至少有两个节点的集群上运行本教程,且这些节点不作为控制平面主机。如果你还没有集群,你可以通过Minikube构建一个你自己的集群,或者你可以使用下面任意一个Kubernetes工具构建:
要检查版本,请输入kubectlversion。
使用默认的服务账户访问API服务器
当你创建Pod时,如果没有指定服务账户,Pod会被指定给命名空间中的default服务账户。如果你查看Pod的原始JSON或YAML(例如:kubectlgetpods/podname-oyaml),你可以看到spec.serviceAccountName字段已经被自动设置了。
你可以使用自动挂载给Pod的服务账户凭据访问API。服务账户的API许可取决于你所使用的鉴权插件和策略。
在1.6以上版本中,你可以通过在服务账户上设置automountServiceAccountToken:false来实现不给服务账号自动挂载API凭据:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
在1.6以上版本中,你也可以选择不给特定Pod自动挂载API凭据:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
如果Pod和服务账户都指定了automountServiceAccountToken值,则Pod的spec优先于服务帐户。
使用多个服务账户
每个命名空间都有一个名为default的服务账户资源。你可以用下面的命令查询这个服务账户以及命名空间中的其他ServiceAccount资源:
kubectl get serviceAccounts
输出类似于:
NAME SECRETS AGE
default 1 1d
你可以像这样来创建额外的ServiceAccount对象:
kubectl create -f - <
ServiceAccount对象的名字必须是一个有效的DNS子域名.
如果你查询服务帐户对象的完整信息,如下所示:
kubectl get serviceaccounts/build-robot -o yaml
输出类似于:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2015-06-16T00:12:59Z
name: build-robot
namespace: default
resourceVersion: "272500"
uid: 721ab723-13bc-11e5-aec2-42010af0021e
secrets:
- name: build-robot-token-bvbk5
那么你就能看到系统已经自动创建了一个令牌并且被服务账户所引用。
你可以使用授权插件来设置服务账户的访问许可。
要使用非默认的服务账户,将Pod的spec.serviceAccountName字段设置为你想用的服务账户名称。
Pod被创建时服务账户必须存在,否则会被拒绝。
你不能更新已经创建好的Pod的服务账户。
你可以清除服务账户,如下所示:
kubectl delete serviceaccount/build-robot
手动创建服务账户API令牌
假设我们有一个上面提到的名为“build-robot”的服务账户,然后我们手动创建一个新的Secret。
kubectl create -f - <
现在,你可以确认新构建的Secret中填充了“build-robot”服务帐户的API令牌。令牌控制器将清理不存在的服务帐户的所有令牌。
kubectl describe secrets/build-robot-secret
输出类似于:
Name: build-robot-secret
Namespace: default
Labels:
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: ...
Note:这里省略了token的内容。
为服务账户添加ImagePullSecrets 创建ImagePullSecret将镜像拉取Secret添加到服务账号
接着修改命名空间的default服务帐户,以将该Secret用作imagePullSecret。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'
你也可以使用kubectledit,或者如下所示手动编辑YAML清单:
kubectl get serviceaccounts default -o yaml > ./sa.yaml
sa.yaml文件的内容类似于:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2015-08-07T22:02:39Z
name: default
namespace: default
resourceVersion: "243024"
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge
使用你常用的编辑器(例如vi),打开sa.yaml文件,删除带有键名resourceVersion的行,添加带有imagePullSecrets:的行,最后保存文件。
所得到的sa.yaml文件类似于:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2015-08-07T22:02:39Z
name: default
namespace: default
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge
imagePullSecrets:
- name: myregistrykey
最后,用新的更新的sa.yaml文件替换服务账号。
kubectl replace serviceaccount default -f ./sa.yaml
验证镜像拉取Secret已经被添加到Pod规约
现在,在当前命名空间中创建使用默认服务账号的新Pod时,新Pod会自动设置其.spec.imagePullSecrets字段:
kubectl run nginx --image=nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'
输出为:
myregistrykey
服务帐户令牌卷投射
FEATURESTATE:Kubernetesv1.20[stable]
为了启用令牌请求投射,你必须为kube-apiserver设置以下命令行参数:
kubelet还可以将服务帐户令牌投射到Pod中。你可以指定令牌的期望属性,例如受众和有效期限。这些属性在default服务帐户令牌上无法配置。当删除Pod或ServiceAccount时,服务帐户令牌也将对API无效。
使用名为ServiceAccountToken的ProjectedVolume类型在PodSpec上配置此功能。要向Pod提供具有“vault”用户以及两个小时有效期的令牌,可以在PodSpec中配置以下内容:
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内可用,并在令牌快要到期的时候刷新它。kubelet会在令牌存在期达到其TTL的80%的时候或者令牌生命期超过24小时的时候主动轮换它。
应用程序负责在令牌被轮换时重新加载其内容。对于大多数使用场景而言,周期性地(例如,每隔5分钟)重新加载就足够了。
发现服务账号分发者
FEATURESTATE:Kubernetesv1.21[stable]
当启用服务账号令牌投射时启用发现服务账号分发者(ServiceAccountIssuerDiscovery)这一功能特性,如上面的服务帐户令牌卷投射所述。
分发者的URL必须遵从OIDC发现规范。这意味着URL必须使用https模式,并且必须在{service-account-issuer}/.well-known/openid-configuration路径给出OpenID提供者(Provider)配置。
如果URL没有遵从这一规范,ServiceAccountIssuerDiscovery末端就不会被注册,即使该特性已经被启用。
发现服务账号分发者这一功能使得用户能够用联邦的方式结合使用Kubernetes集群(“IdentityProvider”,标识提供者)与外部系统(“RelyingParties”,依赖方)所分发的服务账号令牌。
当此功能被启用时,KubernetesAPI服务器会在/.well-known/openid-configuration提供一个OpenID提供者配置文档,并在/openid/v1/jwks处提供与之关联的JSONWebKeySet(JWKS)。这里的OpenID提供者配置有时候也被称作“发现文档(DiscoveryDocument)”。
集群包括一个的默认RBACClusterRole,名为system:service-account-issuer-discovery。默认的RBACClusterRoleBinding将此角色分配给system:serviceaccounts组,所有服务帐户隐式属于该组。这使得集群上运行的Pod能够通过它们所挂载的服务帐户令牌访问服务帐户发现文档。此外,管理员可以根据其安全性需要以及期望集成的外部系统选择是否将该角色绑定到system:authenticated或system:unauthenticated。
对/.well-known/openid-configuration和/openid/v1/jwks路径请求的响应被设计为与OIDC兼容,但不是完全与其一致。返回的文档仅包含对Kubernetes服务账号令牌进行验证所必须的参数。
JWKS响应包含依赖方可以用来验证Kubernetes服务账号令牌的公钥数据。依赖方先会查询OpenID提供者配置,之后使用返回响应中的jwks_uri来查找JWKS。
在很多场合,KubernetesAPI服务器都不会暴露在公网上,不过对于缓存并向外提供API服务器响应数据的公开末端而言,用户或者服务提供商可以选择将其暴露在公网上。在这种环境中,可能会重载OpenID提供者配置中的jwks_uri,使之指向公网上可用的末端地址,而不是API服务器的地址。这时需要向API服务器传递--service-account-jwks-uri参数。与分发者URL类似,此JWKSURI也需要使用https模式。