k8s 安全与认证授权

导读
Kubernetes 的安全模型由认证、授权、准入控制三道关卡串联组成,任何一个 API 请求都要依次通过这三层校验才能写入 etcd。ServiceAccount 是 Pod 在集群中的身份凭证,RBAC 则定义了这个身份能操作哪些资源。掌握这套链路,才能在多租户和生产环境中精准控制权限边界。
核心概念
每个发往 kube-apiserver 的请求都会经历三个阶段。第一阶段是认证(Authentication),确认"你是谁",支持客户端证书、Bearer Token、ServiceAccount Token 等多种方式。第二阶段是授权(Authorization),判断"你能做什么",Kubernetes 默认启用 RBAC 模式。第三阶段是准入控制(Admission Control),在对象持久化前做最后的校验或修改,分为 Mutating 和 Validating 两类 Webhook。三道关卡顺序固定,前一道不通过则请求直接被拒绝,不会进入下一阶段。
ServiceAccount 是命名空间级别的资源,为 Pod 提供访问 API Server 的身份。每个 Pod 创建时会自动挂载该 ServiceAccount 的 Token 到 /var/run/secrets/kubernetes.io/serviceaccount/token,应用程序通过读取该文件完成 API 调用时的身份标识。从 1.24 版本开始,ServiceAccount 不再自动生成 Secret 形式的长效 Token,改为按需通过 TokenRequest API 签发短期 Token,有效降低了凭证泄露后的风险窗口。
图 1:API 请求穿越认证、授权、准入三阶段链路的完整流程。认证阶段失败返回 401,授权阶段失败返回 403,准入阶段可以拒绝请求或修改对象内容。Mutating Webhook 在 Validating 之前执行,允许在对象写入前注入默认值或补充字段,而 Validating Webhook 只做校验不改数据,二者共同构成准入控制的最后一道屏障。
图解原理
RBAC 模型由四种核心资源构成。Role 定义命名空间内的权限集合,ClusterRole 定义集群范围的权限集合,二者的区别仅在于作用域,Role 受命名空间限制而 ClusterRole 可在全集群生效。RoleBinding 把 Role 绑定到具体主体,ClusterRoleBinding 把 ClusterRole 绑定到集群级主体。主体(Subject)可以是 User、Group 或 ServiceAccount,绑定关系决定了谁能获得对应角色所授予的权限,一条绑定规则可以同时关联多个主体。
一个 Role 通过 verbs 和 resources 的组合精确描述权限。verbs 包括 get、list、watch、create、update、patch、delete 等操作,resources 对应 pods、services、deployments 等 API 资源,也可以通过 resourceNames 限定到具体资源实例。可以用 * 表示通配,但生产环境应避免这种宽松写法。Pod Security Standards 提供了三种预设策略:privileged(无限制)、baseline(最小限制)、restricted(严格限制),通过 PodSecurity Admission Controller 在命名空间级别强制执行,替代了已废弃的 PodSecurityPolicy。三种模式可以分别配置 enforce(拒绝)、audit(审计日志)、warn(告警)三个维度,便于灰度过渡。
图 2:RBAC 中主体到权限的映射链路。左侧三种 Subject 类型通过 Binding 关联到 Role 或 ClusterRole,Role 再展开为具体的 verbs 和 resources 组合。虚线标注了作用域差异:RoleBinding 只在单个命名空间内生效,ClusterRoleBinding 则授予集群范围的权限。设计 Role 时应遵循最小权限原则,只授予业务运行所需的 verbs 集合,能用 RoleBinding 解决就不要使用 ClusterRoleBinding。
动手实操
先创建一个专用的命名空间和 ServiceAccount,模拟一个只读应用身份。以下命令创建 dev-team 命名空间,并在其中创建 pod-reader 这个 ServiceAccount。后续所有权限测试和 Pod 部署都围绕该身份展开,构建一个完整的权限隔离示例。
kubectl create namespace dev-team
kubectl create serviceaccount pod-reader -n dev-team定义一个只允许在 dev-team 命名空间内 get、list、watch pods 及 pods/log 的 Role。这个 Role 仅授予只读权限,不包含 create、delete 等写操作,符合最小权限原则。rules 中的 apiGroups 设为空字符串表示核心 API 组,resources 和 verbs 精确限定到所需的资源类型和操作。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev-team
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]将这个 Role 绑定到前面创建的 ServiceAccount。RoleBinding 中的 subjects 字段声明主体,roleRef 字段声明目标角色,二者共同完成授权绑定。注意 roleRef 一旦创建便不可修改,需要更换角色时必须删除重建 RoleBinding。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: dev-team
subjects:
- kind: ServiceAccount
name: pod-reader
namespace: dev-team
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io应用上述配置后,用该 ServiceAccount 的身份验证权限边界。以下命令先部署 YAML 文件,再通过 kubectl auth can-i 测试具体操作是否被允许。最后尝试删除操作以验证越权访问会被拒绝,从而确认权限隔离生效。
kubectl apply -f role.yaml -f rolebinding.yaml
# 检查是否有读取 Pod 的权限,应返回 yes
kubectl auth can-i get pods \
--as=system:serviceaccount:dev-team:pod-reader -n dev-team
# 尝试删除 Pod,应返回 no
kubectl auth can-i delete pods \
--as=system:serviceaccount:dev-team:pod-reader -n dev-team
# 生成短期 Token 用于应用配置
kubectl create token pod-reader -n dev-team配置 PodSecurity 准入控制,在命名空间级别强制 restricted 策略。enforce 标签会拒绝不合规 Pod 的创建,audit 和 warn 标签则在不阻断的情况下记录和提示。三个标签可以独立配置不同的策略级别,便于灰度迁移已有工作负载。
kubectl label namespace dev-team \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted此后该命名空间中创建的 Pod 如果不符合 restricted 标准(如使用特权容器、以 root 运行、未设置 runAsNonRoot),将被拒绝创建。创建一个 Secret 并通过环境变量注入 Pod,避免在镜像或配置文件中硬编码敏感信息。同时设置符合 restricted 标准的 securityContext,包含 runAsNonRoot、runAsUser、allowPrivilegeEscalation 和 capability 限制。
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: dev-team
type: Opaque
stringData:
DB_PASSWORD: "S3cr3tV@lue"
---
apiVersion: v1
kind: Pod
metadata:
name: app-pod
namespace: dev-team
spec:
serviceAccountName: pod-reader
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.25
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: DB_PASSWORD
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]使用 RBAC 诊断工具检查当前权限分配情况,排查权限过大的主体。kubectl auth can-i --list 会列出指定身份拥有的所有权限,方便审计。定期检查 ClusterRoleBinding 列表,及时发现异常授予的集群级权限。
# 查看某命名空间所有 RoleBinding
kubectl get rolebindings -n dev-team -o wide
# 列出某 ServiceAccount 的全部权限
kubectl auth can-i --list \
--as=system:serviceaccount:dev-team:pod-reader -n dev-team
# 检查集群范围所有 ClusterRoleBinding
kubectl get clusterrolebindings -o wide常见问题与避坑
Token 轮换:1.24 之前自动生成的 Secret Token 永不过期,泄露后只能手动删除重建。升级到 1.24+ 后应清理残留的 Secret 形式 Token,改用 TokenRequest 签发短期凭证,默认有效期 1 小时,可通过 --duration 参数自定义。残留的旧 Token 仍然有效,不会因升级而自动失效,需要显式删除对应的 Secret。
不要用 verbs: ["*"] 配合 resources: ["*"] 作为 Role 定义,这等同于授予集群管理员权限。生产环境应拆分细粒度 Role,按业务团队隔离,不同的应用使用不同的 ServiceAccount。共用同一个身份会导致权限蔓延,一旦该身份被攻破,影响范围将不可控。定期使用 kubectl auth can-i --list 审计各 ServiceAccount 的实际权限,及时回收不需要的 verbs。
default ServiceAccount 误用:Pod 默认挂载的 default ServiceAccount 在 1.6+ 已不自动绑定任何权限,但部分旧集群或第三方 Helm Chart 可能仍残留宽泛绑定。部署 Pod 时应显式指定 serviceAccountName,不要依赖默认行为,同时定期审计 default ServiceAccount 的绑定情况。
PodSecurity 的 enforce 标签一旦设置,已有违规 Pod 不会立即被驱逐,但更新操作会被拒绝。设置策略前先开启 audit 和 warn 模式观察一段时间,收集违规告警后再切换到 enforce,避免一刀切导致业务中断。restricted 模式对容器运行身份、权限提升、capability 等有多项硬性要求,迁移存量工作负载时需要逐项排查并修改 Pod spec。
Secret 在 etcd 中默认以 Base64 编码存储而非加密。生产环境应在 kube-apiserver 启动参数中配置 EncryptionConfiguration,对 etcd 中的 Secret 数据加密。对于更高安全要求的场景,应对接外部密钥管理系统如 Vault,通过 CSI Driver 将密钥挂载到 Pod 中,避免在 Kubernetes 集群内持久化敏感数据。
ClusterRoleBinding 范围过大:ClusterRoleBinding 授予的是集群级权限,一旦绑定到错误的 Subject 将影响所有命名空间。优先使用 RoleBinding,仅在需要跨命名空间权限(如节点管理、命名空间管理)时才使用 ClusterRoleBinding,并在代码评审中重点关注 ClusterRoleBinding 的变更。常见的误用场景是为某个命名空间内的 ServiceAccount 授予 cluster-admin,这会导致该 ServiceAccount 拥有对所有资源的完全控制权。
小结与进阶
认证、授权、准入三层链路构成了 Kubernetes 安全的骨架,RBAC 定义了权限的粒度,PodSecurity 收紧了工作负载的安全边界,Secret 管理则守护了敏感信息的存储与传递。下一篇将从安全视角转向性能视角,讲解资源调度与编排策略。