Kubernetes ServiceAccount 详解
1. ServiceAccount 基本概念
ServiceAccount(服务账户)是 Kubernetes 中用于为工作负载(如 Pod)提供身份认证的机制,它代表了应用程序或服务的身份,而不是个人用户的身份。
1.1 ServiceAccount 的主要作用
- 为 Pod 中运行的进程提供身份标识
- 控制对 Kubernetes API 的访问权限
- 管理与外部系统集成时的身份认证
- 实现 Pod 间的安全通信
1.2 与 UserAccount 的区别
特性 | ServiceAccount | UserAccount |
---|---|---|
用途 | 集群内部工作负载身份 | 集群外部用户身份 |
创建位置 | 集群内部 | 集群外部(由外部IDP管理) |
命名空间 | 属于特定命名空间 | 集群全局 |
前缀 | 自动添加 system:serviceaccount: | 无特定前缀 |
典型使用者 | Pod中的应用程序 | 人类用户或外部服务 |
2. ServiceAccount 的 YAML 结构
基本 ServiceAccount 定义示例:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-serviceaccount
namespace: default
annotations:
example.com/description: "Service account for XYZ service"
automountServiceAccountToken: true
secrets:
- name: my-serviceaccount-token-xyz12
imagePullSecrets:
- name: my-registry-key
2.1 关键字段说明
-
metadata:
name
: ServiceAccount 名称namespace
: 所属命名空间annotations
: 可添加自定义注解
-
automountServiceAccountToken:
- 布尔值,控制是否自动挂载 API 访问令牌
- 默认值在 kube-apiserver 的
--service-account-default-token
参数中设置
-
secrets:
- 关联的 Secret 对象列表
- 通常包含访问令牌
-
imagePullSecrets:
- 用于拉取私有镜像的 Secret 引用
3. ServiceAccount 与相关资源的联系
3.1 与 Pod 的关系
- 每个 Pod 都与一个 ServiceAccount 关联
- 如果没有显式指定,Pod 使用所在命名空间的默认 ServiceAccount (
default
) - Pod 规格中指定 ServiceAccount:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: my-serviceaccount
containers:
- name: main
image: my-image
3.2 与 Secret 的关系
- 每个 ServiceAccount 通常有一个关联的 Secret
- Secret 包含以下关键信息:
ca.crt
: 集群的 CA 证书namespace
: Pod 所在的命名空间token
: 用于认证的 Bearer token
- 自动生成的 Secret 命名格式:
<serviceaccount-name>-token-<random-suffix>
3.3 与 RBAC 的关系
- 通过 RoleBinding/ClusterRoleBinding 将权限授予 ServiceAccount
- 示例 RoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: my-serviceaccount
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
3.4 与 API Server 的关系
- API Server 验证 ServiceAccount token
- 认证流程:
- Pod 使用挂载的 token 向 API Server 发起请求
- API Server 验证 token 的有效性
- API Server 检查关联的 RBAC 规则
3.5 与 Admission Controllers 的关系
ServiceAccount
准入控制器负责:- 为新建的 Pod 设置默认 ServiceAccount
- 确保引用的 ServiceAccount 存在
- 自动挂载 ServiceAccount token
TokenRequest
准入控制器处理 token 的创建和更新
4. ServiceAccount 的生命周期
4.1 创建
kubectl create serviceaccount my-sa
# 或通过 YAML 文件
kubectl apply -f sa.yaml
4.2 令牌管理
- 自动创建: Kubernetes 1.24+ 使用 TokenRequest API 动态生成令牌
- 手动创建: 可以创建 Secret 并关联到 ServiceAccount
4.3 更新
kubectl patch serviceaccount my-sa -p '{"imagePullSecrets": [{"name": "new-secret"}]}'
4.4 删除
kubectl delete serviceaccount my-sa
5. ServiceAccount 的使用场景
5.1 Pod 访问 Kubernetes API
apiVersion: v1
kind: Pod
metadata:
name: api-client-pod
spec:
serviceAccountName: api-client
containers:
- name: main
image: api-client-image
volumeMounts:
- name: token-volume
mountPath: "/var/run/secrets/kubernetes.io/serviceaccount"
readOnly: true
volumes:
- name: token-volume
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
audience: api
5.2 跨命名空间访问
# 在命名空间A中创建ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: cross-ns-sa
namespace: namespace-a
# 在命名空间B中创建RoleBinding引用该SA
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: allow-cross-ns-access
namespace: namespace-b
subjects:
- kind: ServiceAccount
name: cross-ns-sa
namespace: namespace-a
roleRef:
kind: Role
name: namespace-b-reader
apiGroup: rbac.authorization.k8s.io
5.3 私有镜像仓库认证
apiVersion: v1
kind: ServiceAccount
metadata:
name: private-registry-user
imagePullSecrets:
- name: registry-credentials
6. 高级主题
6.1 TokenRequest API (Kubernetes 1.20+)
- 更安全的动态令牌机制
- 令牌具有有限的生命周期
- 可以绑定到特定 Pod 或特定用途
apiVersion: v1
kind: Pod
metadata:
name: token-request-pod
spec:
containers:
- name: main
image: my-image
volumeMounts:
- name: token-volume
mountPath: "/var/run/secrets/tokens"
volumes:
- name: token-volume
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 600
audience: "vault"
6.2 BoundServiceAccountTokenVolume
- Kubernetes 1.21+ 默认启用
- 提供更安全的令牌卷挂载方式
- 令牌自动轮换且与 Pod 生命周期绑定
6.3 ServiceAccount Issuer Discovery
- 允许外部系统验证 ServiceAccount token
- 配置 API Server 参数:
--service-account-issuer=https://kubernetes.default.svc --service-account-jwks-uri=https://kubernetes.default.svc/openid/v1/jwks --service-account-signing-key-file=/path/to/key
7. 安全最佳实践
-
最小权限原则:
- 只授予必要的 RBAC 权限
- 定期审计 ServiceAccount 的权限
-
令牌管理:
- 使用 TokenRequest API 而非静态令牌
- 设置适当的 expirationSeconds
- 限制令牌的 audience
-
Pod 配置:
- 避免使用默认 ServiceAccount
- 设置
automountServiceAccountToken: false
当不需要 API 访问时
-
网络策略:
- 结合 NetworkPolicy 限制 Pod 的网络访问
- 限制对 API Server 的访问
-
监控与审计:
- 监控异常 API 访问
- 定期轮换凭证
8. 常见问题排查
8.1 权限不足错误
# 检查 ServiceAccount 的权限
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<namespace>:<sa-name>
# 检查关联的 Role/RoleBinding
kubectl get rolebindings,clusterrolebindings --all-namespaces | grep <sa-name>
8.2 令牌挂载问题
# 检查 Pod 是否挂载了 token
kubectl exec <pod-name> -- ls /var/run/secrets/kubernetes.io/serviceaccount
# 检查 ServiceAccount 配置
kubectl get serviceaccount <sa-name> -o yaml
8.3 镜像拉取失败
# 检查 imagePullSecrets 是否正确关联
kubectl get serviceaccount <sa-name> -o jsonpath='{.imagePullSecrets}'
# 检查 Secret 是否存在且有效
kubectl get secret <secret-name> -o yaml
9. 实际示例
9.1 创建受限的 ServiceAccount
- 创建 ServiceAccount:
kubectl create serviceaccount restricted-sa
- 创建 Role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-viewer
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- 创建 RoleBinding:
kubectl create rolebinding restricted-sa-binding \
--role=pod-viewer \
--serviceaccount=default:restricted-sa \
--namespace=default
- 测试 Pod:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
serviceAccountName: restricted-sa
containers:
- name: test
image: alpine
command: ["sh", "-c", "sleep 3600"]
9.2 使用 ServiceAccount 访问 API
from kubernetes import client, config
# 自动加载 Pod 内的 ServiceAccount 凭证
config.load_incluster_config()
v1 = client.CoreV1Api()
print("Listing pods:")
ret = v1.list_namespaced_pod(namespace="default")
for i in ret.items:
print(f"{i.metadata.name}")
10. 总结
ServiceAccount 是 Kubernetes 安全模型的核心组件,它:
- 为工作负载提供身份标识
- 通过 RBAC 实现精细的访问控制
- 支持安全的服务间通信
- 管理外部资源访问凭证
合理使用 ServiceAccount 可以:
- 实现最小权限原则
- 隔离不同工作负载
- 提供可审计的服务身份
- 增强集群整体安全性
理解 ServiceAccount 与 Pod、Secret、RBAC 等组件的关系,对于设计安全的 Kubernetes 架构至关重要。随着 Kubernetes 的发展,ServiceAccount 机制也在不断改进,如 TokenRequest API 的引入,使得身份管理更加安全和灵活。