1. Kubernetes 服务账号(ServiceAccount)基础概念
在 Kubernetes 集群中,服务账号(ServiceAccount)是为 Pod 中运行的进程提供身份认证的核心机制。与用户账号不同,服务账号是专门设计给集群内部工作负载使用的身份标识。
每个命名空间都会自动创建一个名为 default 的 ServiceAccount。当你在命名空间中创建 Pod 而没有显式指定服务账号时,Kubernetes 会自动将 default 服务账号分配给该 Pod。可以通过以下命令查看现有服务账号:
bash复制kubectl get serviceaccounts
服务账号的关键特性包括:
- 身份认证:为 Pod 提供访问 Kubernetes API 的身份凭证
- 权限控制:通过与 RBAC 机制结合,控制服务账号的访问权限
- 自动挂载:默认情况下,服务账号令牌会自动挂载到 Pod 的
/var/run/secrets/kubernetes.io/serviceaccount目录
2. 服务账号与角色绑定实践
2.1 创建自定义服务账号
首先我们创建一个专门用于构建任务的服务账号:
yaml复制apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
namespace: dev-team
应用这个配置后,可以通过以下命令验证:
bash复制kubectl get serviceaccount/build-robot -n dev-team -o yaml
2.2 角色绑定(RoleBinding)
创建服务账号后,需要为其分配适当的权限。Kubernetes 提供两种主要的绑定方式:
- RoleBinding:将角色绑定到当前命名空间中的服务账号
- ClusterRoleBinding:将集群角色绑定到服务账号(跨命名空间)
示例:为 build-robot 服务账号授予 dev-team 命名空间的只读权限
yaml复制apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev-team
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: dev-team
subjects:
- kind: ServiceAccount
name: build-robot
namespace: dev-team
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
2.3 集群角色绑定
如果需要跨命名空间访问资源,可以使用 ClusterRoleBinding:
yaml复制apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: ServiceAccount
name: build-robot
namespace: dev-team
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
3. 资源限制配置
3.1 为服务账号设置资源配额
Kubernetes 提供了 ResourceQuota 机制来限制命名空间中的资源使用:
yaml复制apiVersion: v1
kind: ResourceQuota
metadata:
name: build-quota
namespace: dev-team
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
3.2 LimitRange 配置
LimitRange 可以为命名空间中的容器设置默认的资源请求和限制:
yaml复制apiVersion: v1
kind: LimitRange
metadata:
name: build-limits
namespace: dev-team
spec:
limits:
- default:
cpu: 500m
memory: 1Gi
defaultRequest:
cpu: 200m
memory: 256Mi
type: Container
3.3 将资源限制与服务账号结合
虽然资源限制是应用在命名空间级别的,但我们可以通过标签选择器将特定配额与使用特定服务账号的 Pod 关联:
yaml复制apiVersion: v1
kind: ResourceQuota
metadata:
name: build-robot-quota
namespace: dev-team
spec:
hard:
pods: "5"
requests.cpu: "2"
scopeSelector:
matchExpressions:
- operator: In
scopeName: ServiceAccount
values: ["build-robot"]
4. 高级服务账号配置
4.1 服务账号令牌投射
Kubernetes 1.20+ 推荐使用令牌投射而不是自动挂载的 Secret:
yaml复制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
4.2 禁用自动挂载
对于不需要访问 Kubernetes API 的 Pod,可以禁用服务账号令牌的自动挂载:
yaml复制apiVersion: v1
kind: ServiceAccount
metadata:
name: no-api-access
automountServiceAccountToken: false
或者在 Pod 级别覆盖:
yaml复制apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
4.3 镜像拉取 Secret 配置
为服务账号配置镜像仓库凭证:
bash复制kubectl create secret docker-registry myregistrykey \
--docker-server=<registry name> \
--docker-username=DUMMY_USERNAME \
--docker-password=DUMMY_DOCKER_PASSWORD \
--docker-email=DUMMY_DOCKER_EMAIL
然后更新服务账号:
yaml复制apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
imagePullSecrets:
- name: myregistrykey
5. 安全最佳实践
- 最小权限原则:只为服务账号分配完成任务所需的最小权限
- 定期轮换凭证:使用短期有效的令牌而不是长期有效的 Secret
- 命名空间隔离:将不同用途的服务账号放在不同的命名空间中
- 审计日志:定期检查服务账号的 API 访问日志
- 禁用默认服务账号:对于不需要 API 访问的命名空间,考虑禁用默认服务账号的自动挂载
可以通过以下命令检查服务账号的权限:
bash复制kubectl auth can-i --list --as=system:serviceaccount:dev-team:build-robot
6. 常见问题排查
6.1 权限不足错误
当看到类似 "forbidden: User 'system:serviceaccount:dev-team:build-robot' cannot..." 的错误时:
- 检查 RoleBinding/ClusterRoleBinding 是否正确关联了服务账号
- 确认绑定的 Role/ClusterRole 包含所需的权限
- 检查命名空间是否正确
6.2 令牌无效错误
如果遇到 "Unauthorized" 错误:
- 检查令牌是否过期(对于投射令牌)
- 验证服务账号是否存在
- 确认 automountServiceAccountToken 是否被设置为 false
6.3 资源配额冲突
当 Pod 因资源限制无法创建时:
- 检查命名空间的 ResourceQuota
- 验证 LimitRange 设置
- 查看 Pod 的资源请求和限制配置
可以通过以下命令检查资源使用情况:
bash复制kubectl describe quota -n dev-team
kubectl describe limits -n dev-team
7. 实际应用案例
7.1 CI/CD 流水线中的服务账号
在 CI/CD 系统中,可以为不同的流水线阶段创建专门的服务账号:
yaml复制# 构建阶段服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-builder
namespace: ci-cd
# 部署阶段服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: cd-deployer
namespace: ci-cd
然后为它们分配不同的权限:
yaml复制# CI 构建者可以创建 Pod 但不能部署
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: ci-cd
name: ci-builder-role
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["create", "get", "watch", "list", "delete"]
# CD 部署者可以更新 Deployment
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: ci-cd
name: cd-deployer-role
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "update", "patch"]
7.2 多租户集群中的服务账号设计
在多租户环境中,可以按以下模式组织服务账号:
- 每个租户有自己的命名空间
- 每个应用或微服务有专属的服务账号
- 使用 NetworkPolicy 限制服务账号的访问范围
yaml复制# 租户A的前端服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: frontend
namespace: tenant-a
labels:
app: frontend
tenant: tenant-a
# 租户A的后端服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend
namespace: tenant-a
labels:
app: backend
tenant: tenant-a
然后使用 RBAC 和 NetworkPolicy 实现隔离:
yaml复制# 只允许前端服务账号访问后端服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-to-backend
namespace: tenant-a
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
8. 性能优化建议
- 避免过多服务账号:每个服务账号都会产生管理开销,按需创建
- 合并相似权限:为具有相同权限需求的工作负载使用同一个服务账号
- 使用 ClusterRole 共享权限:对于跨命名空间的通用权限,使用 ClusterRole 而不是重复创建 Role
- 定期清理:删除不再使用的服务账号和绑定
可以通过以下命令查找未使用的服务账号:
bash复制# 查找24小时内没有使用令牌的服务账号
kubectl get serviceaccounts --all-namespaces -o json | \
jq -r '.items[] | select(.metadata.annotations["kubernetes.io/created-by"] | not) | .metadata.namespace + "/" + .metadata.name'
