第四篇:《身份认证与访问控制:RBAC、ServiceAccount 与零信任身份》

第四篇:《身份认证与访问控制:RBAC、ServiceAccount 与零信任身份》 Kubernetes 的安全模型建立在两个核心问题上“你是谁 ”认证和“你能做什么 ”授权。在 Kubernetes 中RBAC基于角色的访问控制是授权的核心机制而 ServiceAccount 则为 Pod 提供了集群内的身份标识。然而仅仅依靠 RBAC 和 ServiceAccount 还不足以构建完整的零信任安全体系——跨集群、跨云的服务身份认证需要更标准化的方案。SPIFFE安全生产身份框架和 SPIRESPIFFE 运行时环境 为此提供了业界标准的工作负载身份方案。本文从 Kubernetes RBAC 的深度剖析入手讲解 ServiceAccount 的安全最佳实践并引入 SPIFFE/SPIRE 标准最后通过一个 Istio SPIRE 的集成实战展示零信任工作负载身份如何在服务网格中落地。一、Kubernetes RBAC授权模型的核心RBAC基于角色的访问控制 是 Kubernetes 授权的核心机制。它通过定义“谁”在“哪个命名空间”对“什么资源”有“什么操作权限”实现细粒度的访问控制。1.1 RBAC 的四个核心资源1.2 RBAC 配置示例以下示例创建了一个只读 Pod 的 Role并将其绑定到 ServiceAccount my-sa# 1. 定义 Role只读 PodapiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:namespace:productionname:pod-readerrules:-apiGroups:[]resources:[pods]verbs:[get,list,watch]---# 2. 定义 RoleBindingapiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:namespace:productionname:read-podssubjects:-kind:ServiceAccountname:my-sanamespace:productionroleRef:kind:Rolename:pod-readerapiGroup:rbac.authorization.k8s.io1.3 RBAC 的常见陷阱陷阱一过度宽松的 ClusterRoleBindingcluster-admin ClusterRole 拥有集群的最高权限。将普通用户或 ServiceAccount 绑定到 cluster-admin相当于授予了 root 权限。# ❌ 危险操作kubectl create clusterrolebinding grant-admin\--clusterrolecluster-admin\--serviceaccountdefault:default陷阱二使用 * 通配符在 RBAC 规则中使用 * 意味着授予该资源类型的所有操作权限容易导致权限过度扩散。# ❌ 风险较高授予了对所有资源的完全控制权rules:-apiGroups:[*]resources:[*]verbs:[*]陷阱三忽略 非资源型 URLKubernetes API 除了资源型端点如 /api/v1/pods还有非资源型端点如 /healthz、/version。非资源型 URL 也需要配置访问权限rules:-nonResourceURLs:[/healthz,/version]verbs:[get]1.4 RBAC 最佳实践最小权限原则只授予完成工作所必需的最小权限集。使用 kubectl auth can-i 命令验证权限# 验证当前用户能否在 production 命名空间创建 Podkubectl auth can-i create pods-nproduction# 验证指定 ServiceAccount 的权限kubectl auth can-i list pods-nproduction--assystem:serviceaccount:production:my-sa使用 ClusterRole 复用权限ClusterRole 是集群范围的可以被多个命名空间的 RoleBinding 引用。这避免了在每个命名空间重复定义相同的 Role。定期审计 RBAC 配置使用工具定期审查 RBAC 配置识别过度授权的绑定# 列出所有 ClusterRoleBindingkubectl get clusterrolebindings-owide# 查看特定 ServiceAccount 的权限kubectl describe rolebinding-nproduction二、ServiceAccountPod 的集群身份ServiceAccount 是 Kubernetes 中为 Pod 提供的身份标识。每个 Pod 在创建时都会关联一个 ServiceAccount并通过挂载的 Token 与 API Server 进行认证。2.1 ServiceAccount 的自动挂载机制默认情况下Kubernetes 会自动将 ServiceAccount 的 Token 挂载到 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/token 路径。任何能够进入 Pod 的攻击者都可以使用该 Token 以 ServiceAccount 的身份访问 API Server。风险场景攻击者通过应用漏洞进入 Pod。读取 /var/run/secrets/kubernetes.io/serviceaccount/token。使用该 Token 调用 Kubernetes API执行权限范围内的任意操作。2025 年的安全遥测数据显示22% 的云环境观察到与服务账号令牌窃取相关的可疑活动。ServiceAccount Token 窃取已成为云原生环境中最常见的攻击手法之一。2.2 ServiceAccount 安全加固加固一禁用默认 ServiceAccount 的自动挂载对于不需要访问 API Server 的 Pod应禁用 ServiceAccount Token 的自动挂载apiVersion:v1kind:ServiceAccountmetadata:name:no-token-saautomountServiceAccountToken:false或在 Pod 级别覆盖spec:automountServiceAccountToken:falsecontainers:-name:appimage:myapp加固二为每个应用创建独立的 ServiceAccount避免所有 Pod 共享 default ServiceAccount。为每个应用或工作负载创建独立的 ServiceAccount并授予最小权限kubectl create sa my-app-sa-nproduction加固三使用短期、可轮换的 Token从 Kubernetes 1.24 开始ServiceAccount Token 是有生命周期的默认 1 小时后过期且支持自动轮换。确保集群版本 ≥ 1.24并启用 Token 自动轮换apiVersion:v1kind:Podmetadata:name:my-podspec:serviceAccountName:my-sacontainers:-name:appimage:myappenv:-name:KUBERNETES_SERVICE_ACCOUNT_TOKEN_EXPIRATIONvalue:3600# 1 小时过期三、零信任工作负载身份SPIFFE 与 SPIRERBAC 解决了“谁可以做什么”的问题但 RBAC 依赖的“身份”本身需要一个可信的颁发机制。在传统环境中身份通常基于 IP 地址或主机名但在动态的云原生环境中Pod 的 IP 随时变化主机名也不再可靠。SPIFFESecure Production Identity Framework for Everyone 为此提供了一套标准它为每个工作负载Pod、容器、服务颁发一个全球唯一的、可验证的身份标识SPIFFE ID格式为 spiffe:///。SPIRESPIFFE Runtime Environment 是 SPIFFE 标准的参考实现它自动为工作负载签发和轮换身份证书并提供了与 Kubernetes、AWS、GCP 等平台的集成能力。3.1 SPIFFE ID 格式textspiffe://cluster.local/ns/production/sa/my-servicecluster.local信任域Trust Domain类似 DNS 根域ns/production命名空间sa/my-serviceServiceAccount 名称3.2 SPIRE 的核心架构SPIRE 由两个核心组件构成工作流程SPIRE Agent 启动后向 SPIRE Server 注册并验证节点身份。工作负载Pod通过本地 Unix Socket 向 Agent 请求身份。Agent 验证工作负载的身份基于 Kubernetes ServiceAccount、Pod 标签等。Agent 从 Server 获取工作负载的 SPIFFE 身份证书并通过 Envoy SDSSecret Discovery Service或 Unix Socket 提供给工作负载。四、实战SPIRE Istio 零信任集成将 SPIRE 与 Istio 集成可以实现基于 SPIFFE 身份的服务间 mTLS 认证取代 Istio 默认的 Citadel 证书签发机制。4.1 部署 SPIRE使用 Helm 在 Kubernetes 集群中部署 SPIRE# 添加 SPIRE Helm 仓库helm repoaddspire https://spiffe.io/helm-charts helm repo update# 安装 SPIRE Server 和 Agenthelminstallspire spire/spire\--namespacespire\--create-namespace\--setglobal.spire.namespacespire\--setglobal.spire.trustDomaincluster.local4.2 配置 SPIRE Agent 从 Kubernetes 获取身份SPIRE Agent 可以通过 Kubernetes 的 ServiceAccount 和 Pod 元数据来验证工作负载的身份。以下是一个工作负载注册条目示例将 spiffe://cluster.local/ns/production/sa/my-service 身份授予带有标签 app: my-service 的 PodapiVersion:spire.spiffe.io/v1alpha1kind:ClusterSPIFFEIDmetadata:name:my-service-idspec:spiffeIDTemplate:spiffe://cluster.local/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}selector:matchLabels:app:my-service4.3 配置 Istio 使用 SPIRE 作为 CA修改 Istio 配置将 CA 指向 SPIRE ServerapiVersion:install.istio.io/v1alpha1kind:IstioOperatorspec:meshConfig:caCertificates:-pem:|-----BEGIN CERTIFICATE----- ... SPIRE 根证书 ... -----END CERTIFICATE-----values:global:caAddress:spire-server.spire.svc.cluster.local:8081jwtPolicy:third-party-jwt4.4 验证集成部署一个测试 Pod查看其挂载的 SPIFFE 身份证书# 进入 Podkubectlexec-ittest-pod -- /bin/sh# 查看证书ls-la/run/secrets/workload-spiffe-credentials/cat/run/secrets/workload-spiffe-credentials/svid.pem当两个服务都通过 SPIRE 获取了 SPIFFE 身份后它们之间的 mTLS 通信会自动使用 SPIFFE 证书进行双向认证。五、小结RBAC 是 Kubernetes 授权的核心遵循最小权限原则避免过度授权。ServiceAccount 是 Pod 的集群身份默认 Token 自动挂载存在安全风险应禁用不必要的自动挂载并使用短期 Token。SPIFFE/SPIRE 提供了跨集群、跨云的工作负载身份标准是实现零信任安全架构的关键组件。SPIRE Istio 集成可实现基于 SPIFFE 身份的服务间 mTLS 认证构建完整的零信任服务网格。