阶段一 · 容器与集群安全

RBAC 与准入控制

一句话总结

RBAC 控制"谁能对什么资源做什么操作", 准入控制在资源创建/修改时拦截并校验请求.
两者结合实现: 人不能做超权操作(RBAC), 资源不能违反安全规范(Admission Controller).

RBAC 回顾与深入

K8s 08 篇概览了 RBAC 四件套. 本篇从安全视角深入: 如何设计最小权限, 常见过度授权问题, ServiceAccount 的安全隐患.

四件套回顾

对象 作用域 含义
Role Namespace 定义"能对哪些资源做什么"
ClusterRole 集群 跨 Namespace 的权限定义
RoleBinding Namespace 把 Role 绑定给用户/组/ServiceAccount
ClusterRoleBinding 集群 把 ClusterRole 绑定给全集群

RBAC = 酒店的房卡系统.
Role = 一张房卡能开哪些门(104 房间 + 泳池).
RoleBinding = 把这张房卡发给谁(张三).
ClusterRole = 万能房卡模板(能开所有楼层).
ClusterRoleBinding = 把万能卡发给酒店经理. 普通住客只需要自己楼层的房卡, 给所有人发万能卡就是安全灾难.

最小权限设计原则

# 错误: 给开发者 cluster-admin(上帝权限)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dev-admin
subjects:
- kind: User
name: developer@company.com
roleRef:
kind: ClusterRole
name: cluster-admin # 能做任何事!

# 正确: 只给开发者在自己 Namespace 内的需要权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: team-a
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "create", "update"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"] # 只能读 Secret, 不能 list(防止看到所有密钥)

最危险的权限组合

  1. secretslist 权限 = 可以读取 Namespace 内所有密钥
  2. pods/exec 权限 = 可以进入任何 Pod 执行命令(等于拥有 Pod 的全部权限)
  3. * 通配符 = 对所有资源的所有操作

审计 RBAC 时重点检查这三类.

ServiceAccount 安全

默认 SA 的风险

每个 Namespace 有一个 default ServiceAccount, 所有未指定 SA 的 Pod 自动使用它. 问题:

  • 如果给 default SA 绑定了 Role → 该 Namespace 的所有 Pod 都获得这个权限
  • SA Token 自动挂载到 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/token
  • 攻击者进入任意 Pod → 可以用这个 Token 调用 K8s API

最佳实践

# 1. 每个服务创建专属 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: order-service
namespace: production
automountServiceAccountToken: false # 默认不挂载 token

---
# 2. Pod 显式指定 SA, 且只在需要时挂载 token
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
serviceAccountName: order-service
automountServiceAccountToken: false # 不需要调 K8s API 就不挂载

---
# 3. 只给真正需要调用 K8s API 的服务绑定权限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: order-service-binding
namespace: production
subjects:
- kind: ServiceAccount
name: order-service
roleRef:
kind: Role
name: order-service-role

三条铁律

  1. 每个服务用专属 ServiceAccount, 不共用 default
  2. 不需要调用 K8s API 的 Pod 设置 automountServiceAccountToken: false
  3. 永远不要给 default ServiceAccount 绑定任何权限

准入控制(Admission Controller)

RBAC 控制"谁能创建 Pod", 准入控制决定"Pod 的配置是否符合规范". 即使有权限创建 Pod, 如果 Pod 配置了 privileged=true, 准入控制器可以拒绝.

准入流程

[kubectl apply] → [认证] → [授权(RBAC)] → [Mutating Admission
(修改请求)] → [Validating Admission
(校验请求)] → [写入 etcd]
阶段 作用 示例
Mutating 修改请求内容(注入默认值) 自动注入 Sidecar, 添加默认 labels
Validating 校验请求是否合规(不修改) 拒绝 privileged 容器, 要求必须有 resource limits

内置准入控制器

控制器 功能
PodSecurity 按 PSS 级别拒绝不合规 Pod(上一篇讲过)
LimitRanger 强制 Pod 必须设置 resource limits
ResourceQuota 限制 Namespace 资源总量
MutatingAdmissionWebhook 调用外部 Webhook 修改请求
ValidatingAdmissionWebhook 调用外部 Webhook 校验请求

Webhook 准入控制示例

# ValidatingWebhookConfiguration: 拒绝使用 latest tag 的镜像
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: deny-latest-tag
webhooks:
- name: deny-latest.example.com
admissionReviewVersions: ["v1"]
sideEffects: None
rules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
clientConfig:
service:
name: admission-webhook
namespace: security
path: /validate
failurePolicy: Fail # webhook 不可用时拒绝请求(安全优先)

failurePolicy 的选择

Fail: Webhook 不可用时拒绝所有请求, 安全但可能阻塞部署.
Ignore: Webhook 不可用时放行, 可用性好但安全降级.

生产环境建议 Fail + 确保 Webhook 高可用(多副本 + PDB).

审计日志(Audit Logging)

RBAC 管"防", 审计日志管"查", 谁在什么时间对什么资源做了什么操作.

# 审计策略示例
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Secret 操作记录完整请求体
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
# Pod exec 记录元数据
- level: Metadata
resources:
- group: ""
resources: ["pods/exec", "pods/attach"]
# 其他资源只记录请求级别
- level: Request
resources:
- group: ""
resources: ["*"]

审计日志的安全价值:

  • 事后溯源: 谁删除了生产环境的 Deployment?
  • 异常检测: 某 SA 突然开始 list secrets → 可能是 token 被盗
  • 合规要求: SOC2, ISO27001 等认证需要完整的操作审计

常见安全配置错误

错误 风险 修复
给所有开发者 cluster-admin 任何人可以做任何事 按团队/Namespace 分配最小权限 Role
default SA 有 list secrets 权限 所有 Pod 可以读取所有密钥 创建专属 SA + automountToken=false
Webhook failurePolicy=Ignore 安全策略可被绕过 改为 Fail + 确保 Webhook 高可用
没有开启审计日志 安全事件无法溯源 配置 audit policy + 日志存储
RoleBinding 绑定到 Group 通配符 意外授权给过多用户 显式列出 subjects

快速回顾

  • RBAC 最小权限: 按需分配, 重点审计 secrets/list, pods/exec, 通配符权限
  • ServiceAccount: 每服务专属 SA + automountServiceAccountToken=false
  • 准入控制: Mutating(修改)→ Validating(校验), 安全策略在此拦截
  • Webhook: 自定义准入逻辑, failurePolicy=Fail 确保安全优先
  • 审计日志: 记录所有敏感操作, 支持事后溯源和异常检测
  • 第 07 篇会讲如何用 Kyverno/OPA 以声明式方式定义准入策略(不用自己写 Webhook 代码)

动手练习

  1. 检查 default SA 权限: 用 kubectl auth can-i --list --as=system:serviceaccount:default:default 检查 default SA 的权限, 确认没有敏感权限
  2. 最小权限测试: 创建一个只能 get/list Pods 的 Role, 绑定给一个新 ServiceAccount, 用该 SA 的 token 尝试 create deployment(应被拒绝)
  3. 过度授权验证: 在测试 Namespace 给 default SA 绑定 cluster-admin, 从 Pod 内 curl K8s API 执行 kubectl get secrets -A, 观察结果(然后立即删除这个 binding)
  4. PSS enforce 测试: 给 Namespace 启用 PodSecurity enforce=restricted, 尝试部署一个 privileged Pod 观察被拒绝的错误信息