ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

云原生安全实战:从开发到运行时的全链路防护策略

云原生安全实战:从开发到运行时的全链路防护策略

把公司核心系统从单体拆成几十个微服务、批量推进Kubernetes的那段时间,我几乎每天深夜都在想同一个问题:业务跑起来了,安全到底靠什么兜底?这不算什么新问题,但确实是每个团队转向云原生之后必须重新回答的问题。云原生应用的安全开发与防护策略,跟传统虚拟机时代那套玩法完全不是一回事。早期我以为把机房里的防火墙规则照搬过来就行,结果发现服务之间的流量根本不经过边界防火墙,东西向流量像毛细血管一样到处都是,整个信任模型直接被重构了。

这篇文章不打算写成理论科普,而是想把我在真实项目和故障现场里总结出来的那套东西讲清楚:哪些安全动作必须前置到开发阶段,哪些策略要固化在CI/CD流水线里,运行时又要盯住哪些信号。从威胁建模、密钥管理、依赖供应链,到准入控制、网络策略、运行时检测和GPU配额这类资源隔离问题,都会给到可以直接落地的方案和踩坑记录。适合正准备把安全机制接入云原生体系的开发、运维、SRE同学参考,也适合那些已经被容器安全搞得焦头烂额、想找个抓手的人。

1. 安全问题的根源:云原生到底改变了什么

1.1 信任边界没了,边界被拆散了

传统架构下,安全思路很简单:数据中心也好、机房也好,都有一个明确的物理边界。防火墙挡住外部流量,内部网络默认可信,数据库放在内网最深处,脱库之前先得穿过好几道防线。这套模型被叫做“城堡与护城河”,服务器是城堡里的宝藏,防火墙是护城河,边界守住了,问题就不大。

云原生把这座城堡拆成了几百个集装箱到处漂。Kubernetes集群里,Pod会被调度到任意节点,服务实例随时扩缩容,IP地址频繁变化。更关键的是,服务之间通过Service、Ingress、Sidecar互相调用,东西向流量直接发生在集群内部,根本不经过传统边界设备。于是“边界防御”瞬间失效——攻击者只要突破了一个业务Pod,就能以内网身份横向移动,摸到数据库、对象存储、配置中心。

所以云原生安全的第一步,是接受一个事实:不再有清晰的信任边界。零信任模型顺势成了主流的底层逻辑——不信任网络位置,只信任身份和策略。服务之间调用前先验证对方身份,数据路径全程加密,权限按最小化原则收敛。这套思路从一开始就要影响架构设计,而不是等上线后加几个网络策略就完事。

1.2 “安全开发”不只是上线前的扫描

很多团队一谈到安全开发,第一反应就是CI/CD里挂几个扫描工具,镜像扫一遍、代码扫一遍,扫描结果没有高危就算过关。但真正的安全开发,远比“扫描后放行”复杂。它本质上是把安全从末端质检变成全过程质量内建,就像做菜的时候不能只靠出锅前尝一口,得从买菜、洗菜、切配就开始控制。

在云原生语境里,安全开发覆盖的范畴至少包括:业务代码的安全编码规范、依赖与开源组件的供应链审计、基础设施代码的安全配置、镜像的构建与签名、密钥的管护方式、API的认证授权设计、运行时行为的安全基座。任何一个环节失控,都可能成为攻击链上的关键跳板。我见过太多因为一个硬编码的数据库密码导致核心数据全量泄露的案例,也见过因为RBAC配置不当,普通开发账号能删除namespace的严重事故。

同时,安全开发还必须是“左移”的。越早发现问题,修复成本越低。一个威胁建模阶段发现的架构级风险,改设计可能只需要几天;但等代码写完、部署上线、用户量起来之后再发现,往往要付出几十倍的代价。所以要把安全评审、安全测试、策略校验全部塞进开发流程和自动化管线里,让问题在最早环节就暴露。

2. 开发阶段的安全设计:把防护做进代码里

2.1 威胁建模:先知道敌人是谁

写代码之前先做威胁建模,听起来像项目管理流程里的一个仪式,但在云原生场景下,它真的能救命。我用得最顺手的框架还是STRIDE,六个维度把威胁拆得很干净:Spoofing(欺骗)、Tampering(篡改)、Repudiation(否认)、Information Disclosure(信息泄露)、Denial of Service(拒绝服务)、Elevation of Privilege(权限提升)。拿这套模型去套云原生应用,每个维度都有非常具体的映射。

欺骗:镜像仓库里的镜像会不会被伪装替代?API网关能不能识别伪造身份?服务间的mTLS是否真正验证了调用方身份,还是只验了证书没验授权?篡改:镜像在构建和部署之间有没有可能被注入恶意层?ConfigMap、环境变量里的配置项会不会被非法篡改?否认:审计日志记录了谁在什么时间做了什么操作吗?出了问题能不能追溯到人或者服务账号?信息泄露:日志里有没有把密钥、token、个人敏感信息打出来?服务间的流量是否明文传输?拒绝服务:资源配额有没有设置上限?某个Pod内存泄漏会不会拖垮整个节点?一个盲调用第三方API会不会因为重试风暴打爆外部依赖?权限提升:容器运行时是否默认有大量Linux Capabilities?ServiceAccount的RBAC权限是否远超应用实际所需?Pod是否能挂载宿主目录、操作docker.sock?

每一类威胁都要对应一条防护策略。做完这一轮梳理,你基本能画出这个服务的攻击面地图,后续的代码、流水线、运行时加固都有了依据。没必要追求每一步都做得无穷细,但关键服务——网关、用户系统、支付、订单中心——必须过一遍。

2.2 密钥与配置安全:最常见的数据泄露来源

云原生应用里,密钥安全是我见过翻车最多的环节。原因很直接:微服务多了,每个服务都要连数据库、连消息队列、调第三方API,凭据数量爆炸式增长,于是有人图省事,把密码硬编码在代码里,或直接写进Kubernetes的ConfigMap,甚至直接放在镜像的Dockerfile里。这些做法等于把钥匙挂在门口。

Kubernetes原生提供Secret对象,但它只是Base64编码,没有任何加密能力。默认情况下,任何能在集群里读Secret的对象都可以拿到明文。如果你的etcd没有开启静态加密,或者RBAC没有严格限制get/list Secret的权限,所谓的Secret就是个摆设。所以我的建议是:要么用外部密钥管理服务,比如Vault、云厂商的KMS,配合External Secrets Operator同步到集群;要么至少使用Sealed Secrets这类工具把Secret加密进Git仓库,然后再在集群内解密。绝不能让明文密钥出现在CI日志、Git历史、镜像层里。

密钥轮换也得制度化。我的实践里,高优凭据(数据库密码、云厂商AK/SK)建议30到90天强制轮换,而且轮换过程要设计成无需停机:先写新凭据,让服务加载新值,确认运行正常后再吊销旧凭据。千万别一个人手工改配置文件然后重启所有Pod,那基本等于宣布一次事故。曾经有个团队把数据库密码轮换做成手工操作,结果漏掉了三个Pod的配置,某个午后流量高峰,部分实例突然连不上库,整个线上告警瞬间刷屏。后来他们改用External Secrets Operator,由密钥系统统一推送,轮换只要改一次远端值,集群内的控制器会自动更新并滚动重启工作负载。

2.3 依赖与供应链:SBOM与镜像签名

云原生应用大量依赖开源组件,供应链攻击已经成为非常现实的威胁。去年某知名开源库被植入恶意代码、通过伪装版本号分发的事件,应该给大家提了个醒:依赖不是白嫖的免费午餐,每引入一个组件,就是在信任一个第三方。所以开发阶段就要管好依赖清单,每一份依赖都要能追溯到来源、版本和已知漏洞。

我现在的做法是,所有项目在流水线里强制生成SBOM(软件物料清单),用Syft或Trivy的插件生成,列出所有依赖组件及其版本、许可证、来源。SBOM不是给监管看的,它是你自己排查问题的地图。当某个CVE爆发时,你能迅速回答“我们到底有没有用这个组件、用在哪个服务、哪个镜像”。没有SBOM,你只能人肉搜索代码库里所有pom.xml、package.json、go.mod,效率低且容易遗漏。

镜像签名是供应链安全的另一层关键防线。构建完镜像后,用cosign给它签名,并把签名信息存入镜像仓库。部署时通过准入控制器校验签名,只允许已签名的镜像进入集群。这样即使攻击者把恶意镜像推到你的仓库,只要没有私钥签名,它就永远无法被部署。结合SLSA框架的供应链级别要求,可以把构建、发布、部署的全链路可信度逐步提高。这套东西前期建设成本不高,但收益非常明确:你对你环境的掌控感会完全不一样。

3. 构建与发布管线的安全实施

3.1 CI流水线里加哪些安全检查

很多团队的CI流水线只管编译、打包、推送镜像,安全检测全靠事后人工抽查,这完全不够。我在实践中的做法是,把安全检查当成流水线里的一个阶段,一旦失败直接阻断发布。典型的构建阶段序列大概是:代码提交触发流水线,先跑SAST静态代码扫描,再跑SCA依赖成分分析,之后构建镜像,镜像推送到仓库前先做镜像漏洞扫描,通过后cosign签名,再推送。部署之前,还可以启动DAST动态测试对测试环境做一轮冒烟攻击检测。

SAST工具这里我用过Semgrep和SonarQube,各有优势。Semgrep规则灵活,适合自定义团队的安全编码规范,比如禁止使用不安全的反序列化函数、禁止在日志里打印用户敏感字段。SonarQube适合全局代码质量和常见漏洞扫描,能跟MR流程集成,直接在代码评审里给出提示。SCA层面,OWASP Dependency-Check和Trivy都可以,Trivy的好处是镜像和依赖都能扫,少维护一套工具。

关键在失败策略设计。我的经验是:Critical级别的漏洞必须阻断;High级别视业务风险设定阈值,比如超过3个默认阻断;Medium和Low可以记录但不阻断,防止流水线被误报埋没。另外要建立漏洞处理SLA,比如Critical在24小时内修复或缓解,High在72小时内。安全扫描不是摆设,你要给它对应的运营节奏。

3.2 基础设施即代码的“代码审查”

云原生环境下,Kubernetes的YAML、Terraform/Tofu的HCL、Helm Chart,全都是能被攻击者利用的配置面。一个privileged: true的Pod、一个挂载了宿主机目录的容器、一个权限过大的ServiceAccount,都相当于给攻击者开了一扇门。所以基础设施即代码必须走代码审查流程,同时用工具做静态检查。

Checkov和tfsec是我常用的IaC扫描工具,能发现诸如“容器以root运行”“允许特权模式”“在配置里暴露明文密码”等问题。它们可以作为流水线插件,在PR提交时自动扫描。但工具只能解决已知问题,更深层的是要对配置做评审:比如Ask:为什么这个ServiceAccount需要cluster-admin?为什么这个网络策略允许全出站?这些疑问往往是安全漏洞的起源。

这里我特别想说一下Policy-as-Code的价值。用Open Policy Agent(OPA)或者Kyverno,把安全规范翻译成机器可执行的策略,比如“禁止使用latest标签”“禁止特权容器”“必须设置CPU和内存limits”。部署时由准入控制器强制执行,不满足策略的工作负载直接拒绝创建。策略代码跟业务代码一样做版本管理、做评审、做灰度发布,这样安全规范就不会只停留在文档层面。

3.3 准入控制:把安全策略变成强制门槛

准入控制是Kubernetes里最后一道强制关卡。API Server在对象持久化之前,会经过一批准入插件或准入Webhook,我们可以在这里校验镜像签名、检查Pod安全配置、校验网络策略完整性。Kubernetes自带的Pod Security Admission(PSA)提供了privileged、baseline、restricted三档策略,能直接在命名空间粒度上限制Pod安全级别。

我更推荐Kyverno这种策略引擎,因为它的规则是用Kubernetes资源本身来描述的,维护成本低,表达能力也更强。下面是一条很实用的Kyverno策略示例,它强制所有新Pod丢弃NET_RAW能力、设置只读根文件系统、启用Seccomp安全配置:

apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-pod-hardening spec: validationFailureAction: Enforce background: false rules: - name: drop-net-raw match: any: - resources: kinds: - Pod validate: foreach: - list: "request.spec.containers" pattern: securityContext: capabilities: drop: - NET_RAW readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault

注意validationFailureAction字段,我强烈建议新策略先设成Audit运行一段时间,观察它会拦截哪些现存工作负载,确认没有大面积误伤后再切到Enforce。直接Enforce是一步险棋,很多团队把策略一上线,整个发布全被卡住,到处救火。无论是PSA、Kyverno还是OPA Gatekeeper,都应遵循“先审计、再告警、最后强制执行”的灰度节奏。

4. 运行时防护策略:容器里外都要盯

4.1 网络层面的最小权限:NetworkPolicy

网络策略是运行时防护里最基础也最容易被忽略的部分。默认情况下,Kubernetes集群里的Pod可以互相访问,没有任何网络隔离。一个业务Pod被攻破后,攻击者可以扫描整个集群网段,尝试连接所有可达IP。如果数据库Pod开在ClusterIP上,且没有网络策略限制,横向移动会异常轻松。

所以要给关键服务配置NetworkPolicy,只允许明确的服务访问关系。下面是一个实际案例:某个订单服务只能被网关调用,它只能访问DNS和内部的MySQL,其他出站流量一律拒绝:

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: order-api-policy namespace: commerce spec: podSelector: matchLabels: app: order-api policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: api-gateway ports: - protocol: TCP port: 8080 egress: - to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - to: - podSelector: matchLabels: app: mysql ports: - protocol: TCP port: 3306

配置网络策略时要特别注意Egress放行DNS,否则服务解析不了域名,流量直接被断掉。另外如果使用Cilium,还可以使用CiliumNetworkPolicy,支持基于FQDN、CIDR、七层协议的精细化控制,比基础NetworkPolicy灵活不少。网络策略上线后一定要做回归验证:在测试环境先模拟业务调用的全链路,确认没有策略阻断正常流量,再推广到生产。

4.2 运行时异常检测:Falco规则实例

网络策略管得住连接,但管不住容器内的行为。一个被攻破的容器可能会启动shell、写入奇怪的文件、执行系统调用。运行时检测工具里,Falco是社区最成熟的开源方案,它会监控内核系统调用事件,结合规则引擎,实时检测异常行为。部署方式也很简单,直接通过Helm或DaemonSet方式装到每个节点,配合审计日志采集,就能形成一套运行时监控网。

Falco默认规则集已经覆盖了很多常见攻击模式,比如“在容器内启动shell”“读取敏感文件”“创建特权容器”。实际使用中还是要针对业务定制规则,减少噪声。比如检测容器内运行/bin/bash或/bin/sh,对普通业务镜像来说确实是异常事件,但很多调试场景确实会临时进容器执行命令,所以要么按命名空间放行,要么对指定工作负载豁免。

我印象很深的一个案例是,有次Falco告警频繁提示某个Pod在持续写/tmp下的可执行文件,后来定位发现是一个被投毒的依赖在定时下载挖矿程序。如果没有运行时检测,这个行为在网络层根本看不到,也没有任何镜像扫描能提前发现,因为恶意代码是在运行期才拉取下来的。所以镜像扫描解决“已知的坏”,运行时检测解决“未知的坏”,两者缺一不可。

4.3 服务网格与身份互信:mTLS的实用价值

微服务架构下的身份可信,不能依赖IP或者堆内网信任。服务网格方案目前最成熟的就是Istio,它能在Sidecar层面透明地注入mTLS,让服务间通信自动加密,并通过SPIFFE标准为每个工作负载颁发身份证书。启用mTLS之后,即使攻击者突破了某个Pod,他也无法轻易冒充其他服务去调用敏感接口,因为拿不到对应的SPIFFE身份。

不过服务网格的接入成本也不低。如果你已经有几十上百个微服务,直接全量启用Istio会带来性能开销和运维复杂度。我的建议是分阶段:先做关键链路,比如网关、用户中心、支付服务之间强制mTLS,验证稳定后再逐步扩大范围。同时要关注证书轮换的问题——Sidecar之间的证书默认有效期不长,如果控制平面异常,证书无法续期,会导致大量服务调用中断。我曾经在升级Istio时遇到过控制平面失联,整个网格的mTLS证书过期,一大片服务互访失败,当时真是连仪表盘都打不开。后来除了完善监控告警,还把证书到期纳入演练项目,每季度强制做一次证书过期切换演练。

4.4 资源和配额隔离:CPU、内存与GPU的坑

运行时安全除了防攻击,还要防“自伤”。资源配额是防护策略里最容易被忽视的一块。给Pod设置requests和limits,不只是为了稳定性,更是为了防止一个异常Pod耗尽节点资源形成变相DoS。没有limits的容器像没系安全带的飙车,出了事才后悔。所有工作负载都应该设置CPU和内存的requests、limits,并用LimitRange或准入策略强制校验。

GPU配额问题尤其值得单独说。ML训练任务跑在Kubernetes里,GPU是一类特殊资源,配置不当的后果非常直接:显存打爆、进程被OOM Kill、任务中断。如果集群里多团队共享GPU资源,必须由配额体系来控制分配。很多系统在GPU资源不足时会触发预冻结机制,任务在队列里等待,这时候如果团队不清楚配额上限,就会反复提交任务,进一步加剧队列拥塞。我见过一个典型的场景:训练平台日志里持续提示GPU配额不够,任务被预冻结,折合核时白白消耗,调度器里面全是僵尸等待任务。解决方案是先梳理各团队的真实GPU用量,设定明确的配额上限,并在任务提交时校验配额余量,而不是等资源不足时才冻结;同时引入GPU虚拟化和共享技术,比如把一张卡切给多个小任务用,把整体利用率拉上去。

配额的意义不只是“够不够用”,它还是一种安全边界:没有配额约束,一个失控的训练任务可以把整台GPU机器的显存全部占掉,顺手拖垮同一节点上其他业务Pod。所以资源配额和运行时隔离是同一个问题的两面,它们共同守住了可用性安全这条线。

5. 常见问题与排查技巧实录

5.1 镜像扫描结果大量误报怎么办

Trivy扫出来的漏洞列表经常一眼望不到头,很多团队直接麻了,干脆把扫描结果忽略。我的处理逻辑是分三档看:第一档,漏洞对应的组件是否真的被打进最终镜像,很多漏洞出在构建阶段的多阶段构建中间层,最终产物里根本没有;第二档,漏洞是否存在于运行时加载的路径上,比如某些Python包的漏洞函数你根本没调用过;第三档,严重级别加可利用性综合判断。误报要建立豁免机制,每次豁免写清楚原因和复核时间,而不是永久忽略。绝对不要把Critical漏洞因为“好像不影响我们”这种理由放过,至少要评估攻击路径。

5.2 准入策略上线后Pod一直创建失败

这个坑我踩过不止一次。新写的Kyverno或OPA策略直接Enforce,结果发布系统全线红灯。问题往往出在策略没全面评估存量负载,比如你要求所有容器drop NET_RAW,但有个穿山甲代理的镜像默认加了NET_RAW,直接就被拦了。正确的上线路径永远是Audit先行,先让策略跑几天,看它会命中哪些Pod、哪些字段不匹配,确认命中面可控后再Enforce。另外要给策略加排除规则,比如排除系统命名空间、监控组件、CI专用的Job,避免把基础设施Pod一起误伤。

5.3 Seccomp/AppArmor导致应用启动崩溃

开启Seccomp是安全加固的好习惯,但不是所有应用都兼容默认策略。有些老旧的Java应用或者特殊内核模块调用,一旦系统调用被Seccomp拦截就直接崩溃,而且崩溃得非常诡异,没有任何日志输出。我遇到过的情况是应用启动后几秒就被杀掉,查看事件才发现是seccompProfile导致的权限错误。排查时先看Pod事件的报错信息,再用strace在测试环境跑一遍应用,观察被阻塞的系统调用,逐个放行。Don’t put Seccomp on every workload from day one, 先评估应用类型,对已知兼容良好的服务开启,逐步推广。

5.4 运行时检测告警太多噪声大

Falco上线第一周,告警可能多到让人怀疑人生。问题在于规则越严,告警越猛,但真实的攻击事件就淹没在里面。我的优化经验是:建立告警分级,高优先级规则独立通道发飞书/钉钉,低优先级话只记录到ES并提供按天聚合的报表;对已知正常的运维行为做豁免,比如CICD的Job容器执行命令、监控Agent的读取动作;在规则上增加namespace和label过滤,看哪个业务域的告警最集中、偏差最大,再决定要不要调整。

常见问题典型症状核心排查思路
镜像扫描误报漏洞列表很长、阻断发布分层分析组件是否打入最终镜像,建立带原因的豁免机制
准入策略误伤新Pod创建失败、发布卡住改Audit模式观察命中面,排除系统命名空间,逐步Enforce
Seccomp兼容性容器启动后立即崩溃查看Pod事件和strace输出,针对性放行系统调用
运行时告警噪声告警量大但真实攻击少分级告警、按命名空间过滤、对正常运维行为豁免
GPU配额耗尽任务被预冻结、排队积压梳理用量、设配额上限、引入GPU共享与虚拟化
审计日志泄露日志含token或敏感字段日志采集端脱敏,配置敏感字段屏蔽,限制访问权限

5.5 密钥轮换引发的“雪崩”

最后提一个很反直觉的坑:密钥轮换本来是安全操作,但轮换方式不对会酿成事故。团队某次为了提高安全性,把几百个服务的数据库密码统一轮换,结果因为有的服务没有接入密钥管理系统,还是从环境变量里读取硬编码,轮换后大批服务启动即失败。我的教训是:轮换之前先建立密钥依赖清单,确认每个服务读取密钥的方式;先改读取端,让服务从统一密钥源获取新值,确认全链路橙色后再吊销旧值;轮换窗口选在业务低峰期,并准备好回滚方案。安全操作的每一步都要像发布新版本一样慎重,因为失误带来的损失比不安全的损失更直观。

基于实际经验的一点收尾

回看这几年在云原生安全上踩过的坑,我自己最大的一个体会是:安全能力从来不是某个“安全专家”一个人的事,它必须长在开发流程、交付流程和运维流程的每一个环节里。那套“先跑起来、后补安全”的做法,在云原生环境里会加倍偿还——因为攻击面太大、迭代太快,事后补救根本来不及。

如果你团队刚开始做这件事,不需要追求一步到位。先把PA密钥扫描、镜像漏洞扫描、准入策略Audit这几个动作做起来,再逐步扩展网络策略、运行时检测、mTLS的覆盖范围。每一步都按“审计→告警→强制”的节奏推进,让开发、测试、运维同学都有时间适应,比一次性上十来个安全工具要有效得多。安全开发与防护策略的本质,是用工程的手段管理风险,真正落地后你会发现,它不只是挡住攻击,还顺手帮你把流水线质量、可观测性和团队协作习惯都带上了一个台阶。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进