Kubernetes服务账户与Pod身份认证
ServiceAccount(服务账户,简称 SA)是 Kubernetes 中给 Pod 内进程使用的身份,与给人类用户使用的 User 账号区分开。Pod 里的应用通过它向 API Server 证明「我是谁」,再由 RBAC 决定「我能做什么」。
三者的关系可以这样理解:
serviceAccountName 字段把身份注入 Pod,并决定是否挂载 token。每个命名空间都有一个名为 default 的 ServiceAccount,Pod 未显式指定 serviceAccountName 时默认使用它。
这是使用 ServiceAccount 最容易踩坑的地方:
1.23 及以前 创建 SA 会自动生成一个长期有效的 Secret,token 永久不过期
1.24 起 不再自动创建 Secret(LegacyServiceAccountTokenNoAutoGeneration 默认启用)
需要 token 时必须显式用 kubectl create token 或 TokenRequest API 申请
获取 token 的三种方式:
# 1. 临时 token(推荐),默认有效期 1 小时
kubectl create token build-bot -n dev
# 2. 指定有效期与受众
kubectl create token build-bot -n dev --duration=24h --audience=https://vault.example.com
# 3. 绑定到具体对象,Pod 删除后 token 自动失效(安全性最高)
kubectl create token build-bot -n dev --duration=1h \
--bound-object-kind=Pod --bound-object-name=my-pod
# 4. 需要长期固定 token 时,手工创建 Secret(v1.24+ 仍支持)
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Secret
metadata:
name: build-bot-token
namespace: dev
annotations:
kubernetes.io/service-account.name: build-bot
type: kubernetes.io/service-account-token
EOF
kubectl create serviceaccount <名称> [-n <命名空间>]
kubectl create token <服务账户名> [-n <命名空间>] [--duration=<时长>]
kubectl get serviceaccount [-A]
kubectl describe serviceaccount <名称> [-n <命名空间>]
kubectl delete serviceaccount <名称> [-n <命名空间>]
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
namespace: dev
# 关闭 token 自动挂载,需要 token 的容器必须显式声明卷
automountServiceAccountToken: false
# 拉取私有仓库镜像时自动注入 imagePullSecrets
imagePullSecrets:
- name: my-registry-secret
apiVersion: v1
kind: Pod
metadata:
name: caller
namespace: dev
spec:
serviceAccountName: build-bot # 1.24 起该字段创建后不可修改
automountServiceAccountToken: false # 可覆盖 SA 上的设置
containers:
- name: app
image: my-app:1.0
volumeMounts:
- name: token
mountPath: /var/run/secrets/tokens
readOnly: true
volumes:
# 投影卷:由 kubelet 自动轮换的短期 token,推荐做法
- name: token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
audience: vault
# 同时可挂载 ConfigMap / Secret / DownwardAPI
- configMap:
name: app-config
自动挂载的 token 会被放到固定路径,容器内可直接读取:
/var/run/secrets/kubernetes.io/serviceaccount/token # JWT
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt # 集群 CA
/var/run/secrets/kubernetes.io/serviceaccount/namespace # 当前命名空间
# 创建与查看
kubectl create serviceaccount build-bot -n dev
kubectl get sa -A
kubectl get sa build-bot -n dev -o yaml
kubectl describe sa build-bot -n dev
# 申请 token 并在容器内调用 API
TOKEN=$(kubectl create token build-bot -n dev)
kubectl exec -it caller -n dev -- sh -c \
"curl -s -H 'Authorization: Bearer $TOKEN' \
https://kubernetes.default.svc/api/v1/namespaces/dev/pods"
# 绑定权限(SA 本身不含任何权限,必须再绑定角色)
kubectl create rolebinding build-bot-edit \
--clusterrole=edit --serviceaccount=dev:build-bot -n dev
# 校验身份能做什么
kubectl auth can-i list pods --as=system:serviceaccount:dev:build-bot -n dev
kubectl auth whoami --as=system:serviceaccount:dev:build-bot
# 给默认 SA 配置镜像拉取凭据
kubectl create secret docker-registry my-registry-secret -n dev \
--docker-server=registry.example.com \
--docker-username=user --docker-password=pass
kubectl patch serviceaccount default -n dev \
-p '{"imagePullSecrets": [{"name": "my-registry-secret"}]}'
# 查看已签发的 token Secret
kubectl get secret -n dev --field-selector type=kubernetes.io/service-account-token
kubectl get secret <sa>-token-xxxx 取 token 的脚本会直接失效,需改用 kubectl create token。kubectl create token 签发的 token 默认只有 1 小时有效期,不能写死在长期运行的配置文件里。需要长期 token 时应使用 --bound-object-kind=Pod 绑定到工作负载,由 kubelet 自动轮换。serviceAccountName 创建后不可修改。Pod 是不可变对象,改身份必须重建 Pod(Deployment 会滚动更新)。dev 命名空间下的 Pod 只能引用 dev 下的 SA,写错命名空间会报 serviceaccount "xxx" not found。Forbidden,这是排查「Pod 无法访问 API」时的第一步。automountServiceAccountToken: false,避免 token 泄露后被用来横向移动。kubernetes.io/service-account-token 类型 Secret 不会自动删除,遗留的 token 仍可能被旧 Pod 使用。imagePullSecrets 在 SA 上配置会对该 SA 的所有 Pod 生效;若 Pod 自己声明了 imagePullSecrets,则 SA 上的配置不会被合并,需要重新列出。kubectl auth reconcile 收敛。kubectl — Kubernetes集群管理工具rbac — 基于角色的访问控制kubeadm — Kubernetes集群安装工具kube-bench — CIS 安全基线检查