64个K8s安全机制,我来给你捋一遍
Kubernetes的安全机制算是云原生领域最劝退的一块内容了,网上资料要么是官方文档那种"正确但看不懂"的风格,要么是只讲了一两个点的碎片化教程。我自己从裸奔集群一路踩坑到现在,把认证、授权、准入控制、网络策略、Secret管理、审计日志这一整套东西摸了个遍,这篇就把K8s安全机制从原理到实操完整拆一遍。
这篇内容适合谁看?一种是刚搭好集群不知道下一步该做什么的运维,另一种是已经被RBAC、PodSecurity、NetworkPolicy这些名词绕晕的开发,还有一种是正在做等保合规、想给集群整体加固的同学。看完你能收获一套可以直接抄作业的加固清单,以及每个关键选择背后的"为什么这么干"。
K8s的安全机制说白了就是回答三个问题:你是谁、你能干什么、你干的事合不合规矩。围绕这三个问题,衍生出一整套组件和流程,我按实际操作的顺序来聊。
1. 先搞清楚K8s到底在防什么:安全威胁模型
1.1 为什么K8s安全机制这么容易绕晕
很多初学者上来就背RBAC的YAML,结果还是不知道怎么配,本质原因是没理解K8s的信任边界。Kubernetes不像传统单体应用那样只有一个入口,它由控制面(API Server、etcd、Scheduler、Controller Manager)和工作节点(kubelet、kube-proxy、容器运行时)组成,每一层通信都存在被利用的可能。
我把常见的攻击路径梳理了一下,大致有这几类:
- 未授权访问API Server:这是最致命的,拿到API Server权限等于拿到整个集群的root,可以任意创建Pod、读取Secret、删除资源。
- 恶意镜像或漏洞容器:开发者从公共仓库拉了个有后门的镜像,或者镜像里的依赖存在远程代码执行漏洞,容器一旦跑起来就被攻破。
- 容器逃逸:攻击者先打穿应用,再借助内核漏洞或错误配置逃出容器边界,直接落到宿主机。
- 横向移动:集群内Pod之间没有任何隔离,攻击者拿下A服务后,通过Service或者Pod IP直接扫内网,把整个集群打穿。
- 数据泄露:Secret明文存在于etcd中,或者RBAC配置过宽,任何服务账号都能读所有命名空间的密钥。
- 供应链攻击:镜像构建过程被污染,依赖源被替换,或者镜像仓库本身被入侵。
理解了这些路径,你就知道为什么K8s的安全机制这么多层。它不是为了解决某一个漏洞,而是要做纵深防御。就算某一道防线被突破,后面还有好几道拦住攻击者。
1.2 K8s安全的三个核心命题
纵深防御落到K8s,其实就是三层问题:
第一层是认证(Authentication),解决"你是谁"。K8s里面身份分两种,一种是人类用户(通过kubeconfig里的证书或token识别),另一种是Pod里的服务身份(ServiceAccount)。API Server接到的每一个请求,第一步永远是认证。
第二层是授权(Authorization),解决"你能干什么"。K8s默认开启RBAC(基于角色的访问控制),通过Role、ClusterRole、RoleBinding、ClusterRoleBinding四件套来控制权限范围。RBAC是K8s安全里最核心、也最容易被配错的模块。
第三层是准入控制(Admission Control),解决"你干的事合不合规矩"。请求过了认证和授权之后,在对象持久化到etcd之前,会被一串准入控制器拦截检查。你可以在这里强制要求所有Pod必须带资源限制、所有镜像必须来自私有仓库、禁止特权容器等等。
这三层之外,还有网络策略(NetworkPolicy)、Secret加密、PodSecurity标准、审计日志等配套机制。接下来每一层我都给你拆开讲,附上可以直接用的配置。
2. 认证与授权:把"你是谁"和"你能干嘛"管明白
2.1 认证体系:kubeconfig、ServiceAccount与TLS证书
K8s的认证方式有好几种,但实际生产里最常见的是两种:X509客户端证书和ServiceAccount token。
先说客户端证书。集群初始化时(比如用kubeadm或KubeKey),会生成一套CA,管理员用它签出admin证书。之后你创建新用户,流程是:生成私钥和证书签名请求,用集群CA签发,然后把CA证书、客户端证书、私钥打包进kubeconfig配置文件。API Server验证请求时,通过CA公钥校验客户端证书是否由可信CA签发,并从这个证书里提取CN字段作为用户名。
实战中我建议你在每台需要访问集群的机器上都单独配置kubeconfig,不要为了图省事把admin的kubeconfig到处拷。有个小技巧:用kubectl config set-credentials配合--embed-certs=true可以把证书嵌进kubeconfig文件,但注意这个文件一定要用chmod 600限制权限,否则泄露出去等于把集群管理权限拱手送人。
再讲ServiceAccount。这是Pod访问API Server的身份凭证,它比客户端证书更适合给工作负载用。每个Namespace默认有一个default ServiceAccount,但很多团队就直接用default跑业务,这其实隐患很大。因为default ServiceAccount往往被赋予了比较大的权限(取决于你集群里绑定的Role),而且所有没显式指定ServiceAccount的Pod都会用它,一旦一个Pod被攻破,攻击者就能借用这个身份继续横向移动。
我自己的习惯是:每个应用单独建一个ServiceAccount,只绑定最小权限,Pod的spec里显式声明serviceAccountName。这条看起来不起眼,但能在真实事故里把爆炸半径缩小一大截。
2.2 RBAC授权实战:从一次真实配置说起
RBAC的配置思路很清晰:先定义角色(Role或ClusterRole),再把角色绑定到用户或ServiceAccount(RoleBinding或ClusterRoleBinding)。区分Role和ClusterRole的核心是作用范围:Role只作用于某个Namespace,ClusterRole作用于整个集群。
我拿一个真实场景举例:给一个日志采集的DaemonSet配权限,它需要读取集群里所有Namespace的Pod和节点信息,但不需要修改任何资源。这时候应该建一个ClusterRole,配置如下:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: log-collector-reader rules: - apiGroups: [""] resources: ["pods", "services", "nodes"] verbs: ["get", "list", "watch"]然后把这个ClusterRole绑定到日志采集组件的ServiceAccount上:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: log-collector-binding subjects: - kind: ServiceAccount name: log-aggregator namespace: kube-system roleRef: kind: ClusterRole name: log-collector-reader apiGroup: rbac.authorization.k8s.io这里有个特别容易踩的坑:roleRef一旦确定就不能再改绑定的Role,只能删除重建Binding。所以如果你后续要调整权限,别想着原地改,直接新建一个ClusterRole再替换Binding。
RBAC排查时最常用的命令是这两个:
# 查看当前用户/ServiceAccount能执行哪些操作 kubectl auth can-i --list --as=system:serviceaccount:default:log-aggregator # 模拟执行某个操作,看是否被允许 kubectl auth can-i get pods --as=system:serviceaccount:default:log-aggregator -n kube-system这两个命令可以让你不用瞎猜权限够不够,直接验证。每次配完RBAC,我都建议用kubectl auth can-i自检一遍再上线,比等用户反馈快得多。
2.3 ServiceAccount的自动挂载与Token过期问题
在K8s 1.24之前,创建ServiceAccount会自动生成一个永不过期的Secret token,这个设计一直被安全圈诟病。后来K8s引入了TokenRequest API,支持生成有过期时间的短期token,1.24版本开始不再自动创建Secret。
如果你还在用旧版本的自动挂载token,建议尽快迁移到Bound Service Account Token。检查一下Pod里的token挂载情况,如果发现不需要访问API Server的工作负载也挂了token,可以在Pod的spec里加一行:
automountServiceAccountToken: false这个配置我最早是在极简安全的加固清单里看到的,实测能把大部分Pod的攻击面瞬间缩小。因为大多数业务Pod根本不需要直接调API Server,token挂在里面就是一颗定时炸弹,容器一旦被攻破,攻击者直接就能用这个token尝试访问集群资源。
3. 准入控制与策略落地:把规矩定在前面
3.1 Admission Controller:对象持久化之前最后一道闸门
认证过了、授权也过了,不代表请求就一定合法。准入控制器(Admission Controller)在请求被持久化到etcd之前运行,可以修改或拒绝请求。Kubernetes默认开启了很多内置的准入控制器,你可以在API Server的启动参数里通过--enable-admission-plugins开启更多。
生产环境我强烈建议开启这几个:
NamespaceLifecycle:防止在正在终止的Namespace里创建新资源。LimitRanger:强制Namespace里的Pod遵守资源配额限制。ResourceQuota:给Namespace设置总体资源上限。PodSecurity:这是Pod Security Standards的落地准入控制器,用来强制执行特权限制。NodeRestriction:限制kubelet只能修改自身的节点和Pod对象。ServiceAccount:自动给Pod注入ServiceAccount。
其中与日常安全最相关的是PodSecurity标准(在K8s v1.25之前是PodSecurityPolicy,现在已弃用)。它定义了三个级别:
| 级别 | 安全要求 | 适用场景 |
|---|---|---|
| privileged | 不限制特权 | 系统组件、需要裸设备访问的特殊工作负载 |
| baseline | 禁止特权容器、禁止hostNetwork等 | 大部分中间件和业务应用 |
| restricted | 最严格,限制capabilities、seccomp等 | 严格合规场景,多租户集群 |
举个例子,如果你想强制某个命名空间的所有Pod遵守restricted标准,给命名空间打上标签:
kubectl label namespace production pod-security.kubernetes.io/enforce=restricted kubectl label namespace production pod-security.kubernetes.io/audit=restricted kubectl label namespace production pod-security.kubernetes.io/warn=restricted这三个标签分别是enforce(拒绝不合规Pod)、audit(记录审计日志但不拦截)、warn(仅返回警告)。我建议刚从privileged迁移到restricted的团队,先用warn和audit模式跑一段时间,观察有哪些存量工作负载不合规,改完再切enforce。直接切enforce可能导致线上服务起不来,这个坑我踩过。
3.2 NetworkPolicy:网络层面的微隔离
默认情况下,K8s集群里所有Pod可以互相通信,这和数据中心时代的扁平网络一样,攻破一个点就能横扫全网。NetworkPolicy就是用来打破这种"默认互信"的。
它的实现原理依赖网络插件(CNI)。Calico、Cilium等主流插件都支持NetworkPolicy,但Flannel默认不支持,如果你用的是Flannel就得先换CNI或者加装Calico。
我拿一个典型的三层架构举例:前端Pod只允许被Ingress访问,前端访问后端,后端访问数据库,数据库不接受任何外部流量。可以这样配后端服务的入站策略:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-allow-frontend namespace: production spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080再配一条数据库的入站策略,只允许后端访问它的3306端口:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: db-allow-backend namespace: production spec: podSelector: matchLabels: app: database policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: backend ports: - protocol: TCP port: 3306配NetworkPolicy有几个关键点要记住。第一,podSelector为空时匹配该命名空间下的所有Pod;第二,NetworkPolicy是作用在命名空间内的,跨命名空间访问要用namespaceSelector;第三,如果一条NetworkPolicy的policyTypes只写Ingress,那默认不限制Egress,反之亦然。
3.3 OPA/Gatekeeper:把安全策略变成代码
内置的PodSecurity标准能解决通用问题,但真正精细化的策略还得靠OPA Gatekeeper这类策略引擎。比如强制要求所有镜像必须从公司私有仓库拉取,这种规则用PodSecurity就做不到,但用Gatekeeper可以。
Gatekeeper的思路是:把策略写成ConstraintTemplate(模板),再通过Constraint(约束)指定作用于哪些资源、匹配哪些规则。下面这个约束可以禁止所有Pod以root用户运行:
apiVersion: templates.gatekeeper.sh/v1beta1 kind: ConstraintTemplate metadata: name: k8srequiredrunasnonroot spec: crd: spec: names: kind: K8sRequiredRunAsNonRoot targets: - target: admission.k8s.gatekeeper.sh rego: | package k8srequiredrunasnonroot violation[{"msg": msg}] { container := input.review.object.spec.containers[_] not container.securityContext.runAsNonRoot msg := "容器必须设置 runAsNonRoot=true" }然后定义一个约束,把这个模板应用在所有命名空间:
apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sRequiredRunAsNonRoot metadata: name: require-run-as-non-root spec: match: kinds: - apiGroups: ["apps"] kinds: ["Deployment"] - apiGroups: [""] kinds: ["Pod"]Gatekeeper的Rego语法有学习门槛,但日常场景你不需要写太多复杂规则,网上有开源的policy-library(Gatekeeper官方库),直接复用场景模板就行。我个人建议第一阶段先做这三条:禁止latest镜像标签、强制runAsNonRoot、限制宿主机路径挂载。
4. 数据与运行时的安全细节:别让你的密钥裸奔
4.1 Secret的正确打开方式
很多团队的Secret管理方式让我看了直摇头——直接把明文密码写进YAML文件,然后提交Git仓库。从K8s安全机制的角度来说,Secret对象本身只是base64编码,这不是加密,任何能读Secret的人都能秒解出来。
用Secret的正确姿势是:
- 用
kubectl create secret命令创建,避免明文写文件的习惯。例如:
kubectl create secret generic db-credentials \ --from-literal=username=admin \ --from-literal=password='P@ssw0rd!'- 配合外部密钥管理服务,比如Vault、AWS Secrets Manager、阿里云KMS,让K8s从外部系统动态拉取密钥,etcd里不落盘。写业务代码时通过CSI Secret Store Driver或External Secrets Operator把云厂商的密钥同步成K8s的Secret。
- etcd中存储的Secret要开加密,配置API Server的
--encryption-provider-config参数,使用aesgcm或secretbox加密。
我还想强调一个容易被忽视的点:Secret的权限控制。Secret所在的Namespace里,任何拥有get权限的人都能看到明文,哪怕他没有写权限。所以不要把Secret放在共享的命名空间里,要给敏感应用单独开命名空间,并且严格限制get/list权限。
我在实际项目中遇到过这么一个事故:一个开发同学为了排查问题,用admin权限把生产环境所有Secret导出了,里面有数据库密码、第三方API密钥、私钥证书,全都截图发到了群里。后来整个集群的密钥全部轮换了一遍。从那以后我就强制规定:生产环境的高危Secret只允许特定ServiceAccount读取,任何bulk导出操作都要走审计流程。
4.2 镜像与容器运行时安全
镜像安全是K8s安全里最容易忽视、但也是攻击者最爱利用的环节。镜像构建完成后,应该做几件事:用Trivy或Clair扫描已知漏洞,把镜像签名(cosign或Notation),运行时用只读根文件系统启动。
扫描漏洞这个步骤在日常CI流水线里就能接入。以Trivy为例:
trivy image --severity HIGH,CRITICAL registry.example.com/myapp:v1.0.0 trivy image --exit-code 1 --severity CRITICAL registry.example.com/myapp:v1.0.0在CI里加上第二行命令,一旦发现严重漏洞就终止构建。这个策略我用下来效果很好,能阻断绝大多数"明知有洞还上线"的情况。
运行时安全也有几个关键配置。一是不要在容器里跑成root,尽量用非root用户启动进程;二是去掉容器不需要的Linux capabilities,比如NET_RAW、SYS_ADMIN;三是挂载只读根文件系统,在securityContext里配置:
securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"]drop所有capabilities这个操作我特别推荐,能显著降低容器逃逸成功的概率。但要注意,一些基础镜像里的进程可能需要某些能力,比如监听80端口不需要额外capability,但执行ping需要NET_RAW,具体根据应用实际需要再添加。
4.3 节点证书过期与自动续签:集群最大的定时炸弹
很多生产集群出问题都不是因为复杂的攻击,而是因为证书过期。K8s的控制面组件通信用的TLS证书都有有效期,如果不清不楚过了期,整个集群的kubectl命令马上就不好使了,现象千奇百怪:有时是APIServer报x509错误,有时是kubelet连不上,有时是scheduler一直报错。
用kubeadm搭的集群,证书有效期默认是一年,但kubeadm提供了一套自动续签的机制。生产实践里我建议这样做:
- 先检查当前证书的过期时间:
kubeadm certs check-expiration在kubeadm配置里开启自动续签。新版kubeadm会在证书剩余时间少于180天时,通过kubeadm-controller-manager的证书续签功能自动处理。如果你用的是KubeKey(KubeSphere的部署工具)搭的集群,它自带的证书管理组件同样支持自动续签,配置项在集群的cluster configuration里。
对于手动管理证书的集群,建议用CronJob定期检查证书剩余时间,临近过期时自动执行续签脚本。续签命令是:
kubeadm certs renew all kubeadm init phase kubeconfig --config=kubeadm-config.yaml续签完要重启控制面组件的Pod:
docker restart $(docker ps -q --filter name=etcd --filter name=kube-apiserver --filter name=kube-scheduler --filter name=kube-controller-manager)或者如果你用的是containerd,用crictl来重启对应的容器。
我自己管理的一批集群,就曾经因为证书过期导致整个生产环境API Server不可用,当时值班同学凌晨两点打电话说kubectl全部报错。从那以后我就在每个集群的monitoring里加了一个证书过期时间的监控指标,在证书剩余时间小于60天时触发告警。这件事放在安全机制里说,是因为证书过期本质上是认证体系的失效,影响面等同于认证被攻破。
4.4 单节点与GPU场景的安全要点
关于热词里提到的"单节点K8s"和"K8s调用GPU",这里也补充两个安全要点。
单节点集群由于控制面和数据面都在同一台机器上,攻击面其实是更大的,因为一旦宿主机被攻破,整个集群的控制面也就沦陷了。单节点环境至少要做三件事:关闭kubelet的匿名认证(--anonymous-auth=false),给kubelet配置只读端口为0(--read-only-port=0),以及严格控制SSH的访问来源。很多人觉得单节点测试环境无所谓,但攻击者拿到内网权限后,第一步就是扫描集群端口,匿名认证如果开着就直接拿下了。
GPU节点在生产里很常见(比如跑AI推理),它的安全关注点主要在设备插件和驱动。NVIDIA的设备插件运行在kube-system里,需要访问宿主机的/dev/nvidia*设备和驱动目录。给GPU工作负载配置Pod时,要确保没有给容器挂载宿主机目录的权限,否则攻击者可以通过宿主机路径绕过只读根文件系统的限制。另外,GPU节点尽量打上污点(taint),只允许AI相关的Pod调度上去,不要和其他业务混跑。
5. 可观测与攻击检测:安全审计不能靠猜
5.1 审计日志:记录每一次可疑动作
审计日志是安全机制里最不起眼但最重要的一块。它记录了对K8s的所有API请求,包括谁、什么时间、对什么资源做了什么操作。一旦集群里发生异常,审计日志是追踪攻击路径的第一手资料。
我的审计日志配置文件(audit-policy.yaml)长这样:
apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata # 记录所有读写操作,但仅记录元数据 resources: - group: "" resources: ["secrets", "configmaps", "serviceaccounts"] - level: RequestResponse users: ["system:admin"] # admin的操作都要记录,且保留请求和响应体 - level: Metadata verbs: ["create", "delete", "patch", "update"] # 写操作默认全部记录 - level: None # 健康检查和静态资源不记录 users: ["system:kube-proxy", "kubelet", "system:serviceaccount:kube-system:..."],然后需要在API Server启动参数里指定策略文件和日志输出位置:
--audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml --audit-log-path=/var/log/kubernetes/audit/audit.log --audit-log-maxsize=100 --audit-log-maxbackup=10审计日志文件建议接入到你的日志平台(比如ELK或Loki),定期对它做告警分析。重点关注的告警规则:同一IP频繁调用get secret、创建特权Pod、尝试访问不存在的资源(可能是攻击者在探测)。
5.2 Prometheus监控K8s安全指标:从热词里挖重点
"k8s集群搭建prometheus"是热词榜上的常客,大家都想监控集群,但很多人的监控只关注CPU和内存,安全指标完全缺失。我强烈建议你的Prometheus里补充以下几组安全相关的指标:
- kube-apiserver的认证和授权失败次数:
apiserver_authentication_attempts apiserver_authorization_attempts_total{decision="forbid"}这个数值异常升高,往往意味着有人在暴力破解或撞库。
- kubelet的启动异常和证书过期剩余时间:
kubelet_certificate_manager_rotation_errors_total kube_certificates_certificate_expiration_seconds工作负载的非root运行比例。通过组合kube-state-metrics的label和自定义exporter来算,专门用来做安全合规度量。
deployment副本数和预期不符。如果某个Deployment的可用副本突然变大,很可能是被恶意扩容用来挖矿。
配合Grafana做一张安全看板,把所有安全相关指标放一起,每天看一眼就能快速发现异常。这套方案比等安全通告再查日志要主动得多。
我在实践时还发现一个问题:Prometheus本身也是一个高权限的组件,如果它被攻破,攻击者可以通过它的ServiceAccount访问大量集群元数据。所以Prometheus的RBAC权限一定不要配过大,只让它读metrics相关的资源就够,不要给它get secret之类的权限。
6. 一套可以直接抄作业的加固清单
6.1 从"裸奔集群"到"生产安全基线"的十五个检查项
我把日常检查的安全项目整理成了一份清单,每次新集群上线前按这个过一遍,基本能覆盖90%的常见风险:
| 序号 | 检查项 | 检查命令或位置 | 期望结果 |
|---|---|---|---|
| 1 | 匿名请求是否关闭 | kubectl get clusterrolebinding | grep anon | 无绑定anonymous的ClusterRoleBinding |
| 2 | kubelet匿名认证 | 查看kubelet配置--anonymous-auth | false |
| 3 | kubelet只读端口 | --read-only-port | 0 |
| 4 | 是否开启RBAC | API Server参数--authorization-mode | 包含RBAC |
| 5 | etcd访问是否需TLS | 查看etcd监听端口 | 只监听本机,且启用TLS |
| 6 | Secret是否加密 | API Server参数--encryption-provider-config | 已配置 |
| 7 | PodSecurity标签 | kubectl get ns --show-labels | 生产namespace已设enforce级别 |
| 8 | NetworkPolicy覆盖 | kubectl get netpol -A | 关键命名空间有入站和出站策略 |
| 9 | 默认ServiceAccount使用率 | 检查Pod的serviceAccountName | 业务Pod不用default |
| 10 | 特权容器数量 | kubectl get pods -A -o jsonpath查securityContext | 无特权容器或已单独放行 |
| 11 | 镜像tag | kubectl get deploy -A -o jsonpath | 没有latest标签 |
| 12 | 容器运行用户 | securityContext.runAsNonRoot | true或未设置但镜像默认非root |
| 13 | 节点SSH来源限制 | 查看安全组/防火墙策略 | 只允许跳板机访问 |
| 14 | 审计日志落盘 | ls /var/log/kubernetes/audit/ | 有日志滚转文件 |
| 15 | 证书过期时间 | kubeadm certs check-expiration | 剩余时间大于180天 |
6.2 安全运维必备的常用命令速查
日常安全运维离不开的命令,这里整理一份速查,K8s安全排查高频场景覆盖:
# 查看当前上下文和用户 kubectl config get-contexts kubectl config view --minify # 查看某个ServiceAccount是否有权限做某项操作 kubectl auth can-i create pod --as=system:serviceaccount:prod:my-sa -n prod # 查看集群里所有ClusterRoleBinding,检查有没有不该存在的绑定 kubectl get clusterrolebinding -o wide # 查看所有Pod是否挂载了宿主机路径 kubectl get pods -A -o jsonpath='{range .items[?(@.spec.hostPath)]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' # 查看所有特权容器 kubectl get pods -A -o jsonpath='{range .items[?(@.spec.containers[*].securityContext.privileged==true)]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' # 查看Secret是否有非预期读取者(配合RBAC审计) kubectl get rolebindings -A -o wide | grep secret # 查看审计日志中的敏感操作 grep -E '"verb":"(get|list)"' /var/log/kubernetes/audit/audit.log | grep secret这里我特别说下第二个命令,它是排查权限问题的神器。比如你配置好了RBAC,但是服务就是报403,用kubectl auth can-i --list --as=system:serviceaccount:命名空间:服务账号可以一眼看到这个服务账号能干什么不能干什么,省去大量试错时间。
6.3 从热词看大家问得最多的安全误区
综合"K8s常用命令""控制器""管理工具"这些热词,我来统一回答几个被问爆的安全相关问题。
第一,控制器(controller)本身安全吗?Deployment、StatefulSet这类控制器只是API Server里的控制循环,它们本身不直接处理外部请求,但它们创建的Pod如果有安全配置缺陷(比如特权模式、admin权限),就等于给攻击者留了门。所以控制器的安全要落到Pod模板的securityContext上。
第二,管理工具(比如KubeSphere、Rancher、Lens)安全吗?这类工具有很好的可视化能力,但也引入了额外的攻击面。我的原则是:管理工具的登录账号必须接企业SSO和MFA,管理工具的命名空间要单独隔离,管理工具的RBAC要遵循最小权限。我见过有人把KubeSphere的admin密码设置成123456,集群直接等同裸奔,这种习惯非常要不得。
第三,"k8s和docker区别"这个热词背后其实也有安全含义。K8s在docker之上额外增加了大量的安全边界:RBAC、准入控制、NetworkPolicy这些都是docker不具备的。所以在docker里"跑一下测试"没问题,但直接把docker容器原封不动搬到K8s上,必须过一遍安全配置,否则就是带着裸奔配置上了生产。
7. 我踩过的坑和给你最后的建议
安全机制这东西,光看文档记不住,最好是自己亲手把集群"打穿"一次,才能真正理解每层防护的价值。我早期的做法是在测试环境故意弱化配置,然后用各种攻击工具(比如kube-hunter)扫描自己集群,看能扫出什么结果,再针对性地修复。这个过程比读十遍文档都管用。
最后分享一个我真实踩过的坑:有一次我在生产环境给某个命名空间开启了PodSecurity的restricted级别,结果当天就收到告警,说某核心服务一直CrashLoopBackOff。排查半天发现是这个服务需要在容器里临时创建子进程,而restricted级别的allowPrivilegeEscalation: false禁止了setuid这类操作。最后只能给这个特定Deployment的ServiceAccount单独授权一个baseline的策略。这个经历告诉我:安全策略落地最好分阶段走,先用audit模式观察兼容性,再逐步收紧,不要一步到位切enforce。毕竟安全的目标是保障业务,不是让业务跑不起来。
按照这套思路去加固,你的K8s集群不敢说绝对安全,但至少能挡住99%的初级攻击和大部分中级攻击。剩下的1%,就交给持续监控和快速响应了。