16.7.2 ServiceAccount与认证机制
ServiceAccount 是 Kubernetes 中为 Pod 提供身份标识的内置对象,用于在集群内与 API Server 交互完成认证与授权。每个命名空间默认包含一个 default ServiceAccount,未显式指定时 Pod 会使用它。ServiceAccount 与 RBAC 一起决定“是谁”以及“能做什么”,其核心载体为 Token 与 CA 证书,挂载到 Pod 文件系统中供应用调用。
原理草图(认证与授权链路):
1. 基础操作与示例#
1.1 创建专用 ServiceAccount#
# 创建命名空间
kubectl create ns dev
# 创建 ServiceAccount
kubectl -n dev create sa app-sa
# 查看 SA 与自动生成的 Token
kubectl -n dev get sa app-sa -o yaml
1.2 最小权限 RBAC 绑定(示例仅允许读取 Pod)#
# 文件: rbac-read-pods.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: dev
subjects:
- kind: ServiceAccount
name: app-sa
namespace: dev
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-read-pods.yaml
1.3 在 Pod 中指定 ServiceAccount 并测试权限#
# 文件: pod-with-sa.yaml
apiVersion: v1
kind: Pod
metadata:
name: sa-test
namespace: dev
spec:
serviceAccountName: app-sa
containers:
- name: curl
image: curlimages/curl:8.6.0
command: ["sleep","3600"]
kubectl apply -f pod-with-sa.yaml
# 进入 Pod,读取 Token 并访问 API Server
kubectl -n dev exec -it sa-test -- sh -c '
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
APISERVER=https://kubernetes.default.svc
curl -s --cacert $CACERT -H "Authorization: Bearer $TOKEN" $APISERVER/api/v1/namespaces/dev/pods | head
'
预期效果:返回 dev 命名空间内 Pod 列表(JSON),证明 RBAC 生效。
1.4 禁用自动挂载 Token(降低暴露面)#
# 文件: pod-no-token.yaml
apiVersion: v1
kind: Pod
metadata:
name: no-token
namespace: dev
spec:
automountServiceAccountToken: false
containers:
- name: busybox
image: busybox:1.36
command: ["sleep","3600"]
kubectl apply -f pod-no-token.yaml
kubectl -n dev exec -it no-token -- ls /var/run/secrets/kubernetes.io/serviceaccount
# 预期输出:目录不存在或为空
2. Bound ServiceAccount Token(短期令牌)示例#
新版集群推荐使用短期投影 Token,降低长期 Token 泄露风险:
# 文件: pod-projected-token.yaml
apiVersion: v1
kind: Pod
metadata:
name: projected-token
namespace: dev
spec:
serviceAccountName: app-sa
containers:
- name: curl
image: curlimages/curl:8.6.0
command: ["sleep","3600"]
volumeMounts:
- name: sa-token
mountPath: /var/run/secrets/tokens
volumes:
- name: sa-token
projected:
sources:
- serviceAccountToken:
path: api-token
expirationSeconds: 3600
audience: api
kubectl apply -f pod-projected-token.yaml
kubectl -n dev exec -it projected-token -- \
sh -c 'ls /var/run/secrets/tokens && wc -c /var/run/secrets/tokens/api-token'
预期效果:Token 文件存在且为短期令牌(1小时过期)。
3. 常见问题与排错(含命令解释)#
1) 认证失败(401)
# 检查 Pod 的 SA
kubectl -n dev get pod sa-test -o jsonpath='{.spec.serviceAccountName}'
# 检查 SA 是否存在
kubectl -n dev get sa app-sa
# 检查 Token 是否挂载
kubectl -n dev exec -it sa-test -- ls /var/run/secrets/kubernetes.io/serviceaccount
原因:ServiceAccount 删除/未挂载 Token/Token 过期。
2) 权限不足(403)
# 查看 Role/RoleBinding
kubectl -n dev get role,rolebinding
# 模拟权限判定(解释:验证 SA 是否允许 list pods)
kubectl auth can-i list pods --as system:serviceaccount:dev:app-sa -n dev
原因:Role/RoleBinding 绑定错误或权限不足。
3) Token 挂载异常
# 检查 Pod 是否禁用自动挂载
kubectl -n dev get pod sa-test -o jsonpath='{.spec.automountServiceAccountToken}'
# 检查集群是否启用了相关 Admission 插件
kubectl -n kube-system get cm kube-apiserver -o yaml | grep -i admission
原因:automountServiceAccountToken 被禁用或 Admission 配置影响。
4. 认证机制与外部 OIDC 简述(关键点)#
- 集群内工作负载最常用 ServiceAccount Token。
- 集群外用户可通过 OIDC/x509/Webhook 等认证方式。
- 必须明确区分“集群内 SA 认证链”与“外部用户认证链”。
5. 练习#
1) 在 dev 命名空间创建 log-sa,只允许读取 pods/log。
2) 编写 Pod 使用 log-sa,验证 GET /api/v1/namespaces/dev/pods 是否被拒绝,GET /pods/<name>/log 是否被允许。
3) 将 Pod 的 automountServiceAccountToken 设为 false,验证 Token 不再挂载。
4) 使用 kubectl auth can-i 验证最小权限是否正确生效。
以上实践可在保障应用访问能力的同时,显著提升集群安全性与合规性。