3. Kubernetes集群安全:RBAC权限控制、网络策略、Pod安全策略
聊到Kubernetes集群安全,我脑子里第一个蹦出来的词就是「层层设防」。你想想看,一个K8s集群里跑着几十上百个服务,有内部的、有外部的,有敏感的、有公开的。如果不做权限隔离,那跟把家门钥匙挂在门口有什么区别?
这一章,咱们就聚焦三个最核心的安全机制:RBAC权限控制、网络策略、Pod安全策略。这三板斧用好了,集群的安全水位能提升一大截。
3.1 RBAC权限控制:谁能在集群里干什么
RBAC,全称是Role-Based Access Control,基于角色的访问控制。说白了,就是给不同的人或服务分配不同的「工作证」,有的只能看,有的能改,有的能删。
我在项目中遇到过好几次这样的情况:开发同学不小心用kubectl delete删掉了生产环境的命名空间。嗯,那场面,真是「一地鸡毛」。从那以后,我强制要求所有非运维人员只能拥有只读权限,并且严格限制操作范围。
3.1.1 核心概念
- Role:定义一组权限,作用范围是某个命名空间。比如,允许读取Pod、创建Deployment。
- ClusterRole:和Role类似,但作用范围是整个集群。比如,查看所有命名空间的Pod、管理节点。
- RoleBinding:把Role绑定到用户或ServiceAccount上,限定在某个命名空间内生效。
- ClusterRoleBinding:把ClusterRole绑定到用户或ServiceAccount上,在整个集群生效。
重要原则:最小权限原则
只给用户或服务恰好够用的权限,多一个都不给。我见过有人图省事,直接给开发人员绑了个cluster-admin角色。这相当于把整个集群的root密码交出去了,风险极高。
3.1.2 实战:创建一个只读用户
假设我们想让一个开发人员只能查看default命名空间下的Pod和Service。可以这样配置:
# 1. 创建Role,只允许读取Pod和Service
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
---
# 2. 创建RoleBinding,绑定到用户dev-user
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: dev-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
这样配置完,dev-user就只能看,不能改。我曾经用这个模式帮一个团队解决了「误删命名空间」的顽疾,效果立竿见影。
小技巧:对于ServiceAccount,建议每个微服务都使用独立的ServiceAccount,并绑定最小权限的Role。不要所有服务共用一个默认的ServiceAccount。
3.2 网络策略:控制Pod之间的通信
默认情况下,K8s集群里的所有Pod是可以互相通信的。这听起来很方便,但安全角度来说,这简直是「裸奔」。你想想,如果某个Pod被攻破了,攻击者可以横向移动到任何其他Pod,那后果不堪设想。
网络策略(NetworkPolicy)就是用来解决这个问题的。它像是一道道防火墙规则,控制哪些Pod可以访问哪些Pod。
3.2.1 网络策略的工作原理
网络策略是Kubernetes原生的资源对象,但需要CNI插件支持(比如Calico、Cilium、Weave Net)。如果集群没有安装支持网络策略的CNI,那配置了也没用。
我个人习惯是:默认拒绝所有入站和出站流量,然后按需放行。这样最安全,也最清晰。
3.2.2 实战:隔离前端和后端
假设我们有一个前端Pod和一个后端Pod。前端需要访问后端的API,但后端不应该主动访问前端。可以这样配置:
# 默认拒绝所有入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
---
# 允许前端访问后端
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
这样配置后,只有带有app: frontend标签的Pod才能访问后端Pod的8080端口。其他Pod一律被拒绝。
注意:网络策略是「白名单」机制。如果你没有显式放行某个流量,默认就是拒绝。我曾经见过有人配置了放行规则,但忘了加默认拒绝策略,结果所有流量还是通的。所以,一定要先加默认拒绝策略。
3.3 Pod安全策略:限制Pod的行为
Pod安全策略(PodSecurityPolicy,简称PSP)是用来控制Pod在宿主机上能做什么的。比如,能不能以root用户运行?能不能挂载宿主机目录?能不能使用特权模式?
说实话,PSP在K8s 1.21版本之后已经被废弃了,取而代之的是Pod Security Admission(PSA)。但很多老项目还在用PSP,所以咱们两个都得了解。
3.3.1 Pod Security Admission(PSA)
PSA是K8s 1.23版本引入的,它通过标签来控制命名空间的安全级别。有三个级别:
| 级别 | 说明 | 典型限制 |
|---|---|---|
| Privileged | 无限制,最宽松 | 无 |
| Baseline | 最低限度的安全限制 | 禁止特权容器、禁止hostNetwork、禁止hostPID等 |
| Restricted | 最严格的安全限制 | 禁止所有特权操作,强制使用只读根文件系统等 |
我建议:生产环境至少使用Baseline级别,敏感业务使用Restricted级别。
3.3.2 实战:配置PSA
给命名空间打上标签,就能启用PSA:
# 启用Baseline级别,拒绝不符合规则的Pod
kubectl label namespace production pod-security.kubernetes.io/enforce=baseline
# 启用Restricted级别,并记录警告但不拒绝
kubectl label namespace sensitive pod-security.kubernetes.io/warn=restricted
这样配置后,任何试图在production命名空间创建特权容器的操作都会被拒绝。在sensitive命名空间,会收到警告但不会拒绝。
避坑指南:我曾经在迁移旧项目时,直接给所有命名空间打了Restricted标签,结果一堆Pod启动失败。因为很多旧镜像默认以root用户运行,而Restricted级别禁止这样做。所以,建议先使用warn或audit模式观察一段时间,确认没问题后再切换到enforce模式。
3.4 三者协同:构建纵深防御
RBAC、网络策略、Pod安全策略,这三者不是孤立的,而是层层递进的关系:
- RBAC:控制「谁」能操作「什么资源」。
- 网络策略:控制「哪个Pod」能访问「哪个Pod」。
- Pod安全策略:控制「Pod本身」能做什么。
举个例子:即使某个攻击者通过RBAC漏洞获得了集群的只读权限,他也无法通过网络策略访问敏感服务,更无法通过Pod安全策略创建特权容器。这就是纵深防御的价值。
我个人习惯是:先配RBAC,再配网络策略,最后配Pod安全策略。这个顺序能最大程度减少配置冲突和遗漏。
总结一句话:K8s集群安全没有银弹,但RBAC、网络策略、Pod安全策略这三板斧用好了,能挡住90%的常见攻击。剩下的10%,靠持续监控和应急响应来补。
好了,这一章就到这里。下一章咱们聊聊容器镜像安全,那可是另一个大坑。嗯,到时候再细说。