资讯动态

云原生安全实战:从安全左移到K8s运行时防护与供应链治理

发布时间:2026/10/13 12:50:20 来源:尧图企业网站定制
1. 云原生安全从边界防守到全链路治理1.1 为什么传统安全手段在云原生时代开始失灵先说一个我自己的经历。三年前我在一家中型互联网公司负责运维平台当时公司刚从物理机迁移到容器化架构安全团队还沿用着老一套做法上线前用商业扫描器打一遍漏洞、买一堆WAF规则、给所有服务器装同一个Agent。结果呢扫描报告出了三百多个高危漏洞开发团队根本排不上期修复WAF规则在微服务之间完全不起作用因为流量已经不经过传统边界了装Agent那套更是鸡飞狗跳容器一重启就丢采集数据。后来我花了两周时间梳理整个应用的部署链路才意识到问题的本质云原生架构把原来一个应用跑在一台机器上变成了一个应用拆成几十个微服务跑在几百个容器里再由Kubernetes动态调度。这意味着攻击面从边界入口扩散到了应用内部的所有通信路径、镜像构建产物、编排配置、甚至CI/CD流水线本身。传统安全方案的思路是守好大门可云原生应用根本没有大门——每个Pod都有自己的IP服务之间通过Service和gRPC直接调用东西向流量才是主体。所以云原生安全开发这件事核心是换一套思路不再把安全当成上线前的检查项而是把它拆进交付链路的每个环节从写代码、构建镜像、部署编排到运行时的持续防护全链路覆盖。这个转变不是某个安全团队能单独完成的它需要开发、运维、安全三条线协同也就是大家常说的DevSecOps。1.2 云原生安全的威胁模型到底长什么样想清楚怎么防护之前得先搞清楚怕什么。我习惯把云原生应用的威胁面拆成四层来建模第一层是代码与依赖。这一层的问题是开发速度太快依赖天天在变。某个底层库出个CVE影响面可能覆盖公司一半的应用。举个例子log4j2那个漏洞爆出来的时候我们紧急排查了两千多个制品最终发现四十多个服务间接依赖了受影响版本——没人直接写过log4j2全是传递依赖带进来的。第二层是镜像与制品。镜像一旦构建完成内容就固化了。如果构建时用的基础镜像本身被污染或者Dockerfile把私钥、AK/SK打了进去那这个镜像就会带着风险一路传播到生产环境。镜像仓库如果没有严格的准入机制就等于允许带病的产物进入K8s集群。第三层是编排与配置。Kubernetes的YAML文件看起来人畜无害但配置不当就是漏洞。privileged容器、hostPath挂载、不需要的ClusterRole绑定、敏感信息写进ConfigMap……这些配置问题在实践中出现的频率远高于代码漏洞。第四层是运行时。容器跑起来之后攻击者可能通过应用漏洞进入容器然后尝试容器逃逸、横向移动、或者利用K8s的API Server做权限提升。这一层的防护最依赖观测能力和响应速度。把威胁模型画出来之后防护策略就清晰了每一层都要有对应的检查点和控制手段而且下一层不能完全信任上一层的检查结果——纵深防御在云原生里同样成立。下面我按这个分层思路结合实操经历说说每一步怎么做。2. 安全左移把安全嵌进开发流水线的三个关键卡点2.1 威胁建模别做成一次性的PPT很多团队做威胁建模就是上线前开个会画几张数据流图写几页文档然后就没有然后了。我踩过这个坑所以现在更倾向于把威胁建模变成一个轻量但持续的动作。具体做法是新服务创建时用一套固定问题清单引导开发自答——这个服务处理什么敏感数据对外暴露了哪些接口依赖了哪些外部系统调用链上谁可以访问它数据在哪里落盘根据答案确定安全等级再决定需要做到哪一档防护。比如只处理公开信息、不落库的查询服务跟处理用户手机号、身份证号的服务防护力度天然就应该不同。这个评级过程用模板化的方式做二十分钟就能完成而不是搞一堆冗长文档。真正有价值的是把威胁建模的结论落成两个产物一个是数据流清单标明每个服务入口的参数校验点、敏感字段的加密需求、外部接口的认证要求另一个是安全验收清单后续开发可以照着自测。这样威胁建模就从一次性的评审变成了可执行的开发输入。2.2 CI流水线里的自动化安全检查宁可慢两分钟不要漏一遍安全检查进CI最大的阻力不是技术而是速度。开发提交一个代码CI如果跑五分钟安全扫描团队还能接受跑半小时大家就要绕开你了。所以我的建议是分三层做每层的成本不同第一层是增量SAST只扫描本次提交修改的代码文件在MR阶段跑控制在几分钟内。工具上很多团队用Semgrep或SonarQube的增量模式重点检查SQL注入、硬编码密钥、反序列化漏洞这些常见问题。这一层追求的是速度不求全。第二层是全量SCA扫描整个项目的依赖清单比对漏洞库。这一步不用每次提交都跑可以放在MR合入主干的时候或者每天晚上跑一次全量扫描。重点盯的是传递依赖——用pipdeptree或者npm ls --all把依赖树打出来跟CVE库比对。第三层是镜像扫描在构建阶段对成品镜像做扫描包括基础镜像漏洞、依赖漏洞、配置检查。这一层是准入控制的核心依据后面细说。三层配合下来代码问题的检出基本覆盖了。这里有一个很重要的经验扫描结果必须分优先级不能把几百个漏洞平铺给开发。我们当时按可被外部利用的路径是否真实调用到受影响函数做了一次过滤把高危列表砍掉了七成开发配合度立刻上来了。关键不是让开发看到你有很多问题而是告诉他这一次只需要改这三个点。2.3 镜像构建阶段的安全卡点基础镜像和构建上下文镜像安全有一半的问题出在Dockerfile写得不讲究。我见过最夸张的一次开发为了方便调试把.aws/credentials文件COPY进了镜像结果镜像推到私有仓库之后才被发现只能全部重新构建。所以镜像构建阶段要有几个硬性规范基础镜像必须走公司内部的基础镜像发行版由平台团队统一维护定期更新补丁。开发不允许直接拉取外部的latest标签因为latest指向的内容是不确定的无法追溯。内部基础镜像通过自动化流水线每周扫描、升级改动有记录出了问题知道回退到哪个版本。多阶段构建一定要用起来。以Java为例编译阶段和运行阶段分离# 构建阶段 FROM maven:3.9-eclipse-temurin-17 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 运行阶段 FROM eclipse-temurin:17-jre-alpine RUN addgroup -S app adduser -S app -G app COPY --frombuilder /app/target/app.jar /app/app.jar USER app ENTRYPOINT [java, -jar, /app/app.jar]这段配置背后的逻辑很直接运行阶段的镜像只包含JRE和打包好的JAR不包含Maven、不包含源代码、更不包含编译中间产物。攻击者即使进去也拿不到太多有用的东西。同时用非root用户运行容器是必须的很多安全基线的第一条检查就是是否以root身份运行因为root在容器里一旦配合了不当的capabilities逃逸的概率会大幅上升。3. Kubernetes运行时的硬防护从Pod配置到网络隔离3.1 Pod安全把最小权限落实到配置里Kubernetes官方从1.25开始用Pod Security Admission替代了旧版的PodSecurityPolicy这是一件好事因为PSP配置太复杂很多团队配了等于没配。PSA把Pod的安全等级分为三个档privileged、baseline、restricted。我的建议是核心业务命名空间直接压到restricted边缘服务至少baseline。restricted档位下的关键约束包括必须非root运行、不允许privileged escalation、必须声明resource limits、只允许使用只读的rootfs/proc、/sys挂载除外。用一句话说就是把容器能做的事压到最小。配置上直接用Namespace的label就可以生效apiVersion: v1 kind: Namespace metadata: name: payment-service labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: v1.31 pod-security.kubernetes.io/audit: restricted这里要注意直接强行enforce很可能导致一堆Pod起不来因为很多老服务跑的镜像还是root用户。我当时采用的方式是渐进式的先设成audit只记录违规但不拦截跑两周收集违规报告推动业务团队改Dockerfile和Deployment配置再切到warn最后才设成enforce。整个迁移花了大概六周期间没有发生一例由于安全策略导致的故障。除了PSA还有几个重点配置项值得认真检查allowPrivilegeEscalation必须设为false这是防止容器内进程提权的关键。seccompProfile生产环境建议设置为RuntimeDefault只允许系统调用白名单。很多团队会忽略这个但其实这能挡掉相当一部分容器逃逸的尝试。readOnlyRootFilesystem业务容器尽量设为true需要写文件的目录单独挂emptyDir卷。这样即使被攻破攻击者在容器里的写操作空间也非常小。3.2 NetworkPolicy给微服务画一张通信白名单刚接触K8s的人最容易忽略的防护就是NetworkPolicy因为默认情况下K8s集群内所有Pod都可以互相通信——攻破一个Pod就等于获得了整个集群的局域网自由。NetworkPolicy要做的事情就是打破这种自由把通信关系变成显式的白名单。落地方式不复杂关键在于怎么梳理通信关系。我的做法是让业务团队基于调用关系画一张表然后转成NetworkPolicy的YAML。以一个典型订单服务为例apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: order-service-policy namespace: trade spec: podSelector: matchLabels: app: order-service policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: api-gateway ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: app: user-service ports: - protocol: TCP port: 9090 - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: observability podSelector: matchLabels: app: trace-agent ports: - protocol: TCP port: 4317这个策略表达的意思很明确order-service只接受来自api-gateway的入站流量只能访问user-service通常在另一个K8s集群或同集群的另一Namespace和观测Agent。如果业务上有突发情况要临时开放某个端口就改策略并走审批流程。从默认全通到默认全关这个转变带来的安全感是质变的。3.3 运行时防护不要迷信单一的安全Agent运行时安全是云原生安全里最热闹的一块市面上有Falco、Tetragon、HIDS类的产品等等。我的经验是不要指望单靠某一个Agent解决所有问题而是要把运行时防护拆成检测、阻断、取证三层。检测层用Falco是社区里比较成熟的选择。Falco通过内核模块或eBPF监听系统调用对异常行为——比如容器内执行shell、读写敏感文件、连接外部IP——产生告警。当时我们接入Falco之后最典型的发现是有同事为了排查问题在正在运行的Pod里执行了kubectl exec进去装了curl和netcat这在Falco的规则里很容易触发告警。阻断层取决于你对业务稳定性的容忍度。我的建议是初期先以告警为主把响应做成自动化的限速—例如触发高危规则时自动给Pod打上标签并隔离出流量调度不要一开始就做硬阻断否则误伤一次业务团队对你的信任就要归零。取证层要接入审计日志。K8s的API Server审计日志建议开启记录哪个账号在什么时间做了什么操作、是否成功。很多企业内部的安全事故最终定责靠的就是这层日志。在这里也想强调一个观点运行时防护工具不是越贵越好也不是功能越多越好。关键是你有没有把前面两节(安全左移、配置基线)这些开水闸做好。如果镜像干净、配置到位、网络白名单清楚了运行时需要处理的事件会少一个数量级。4. 软件供应链安全从依赖、镜像到密钥的一体化治理4.1 SBOM别再问这个漏洞影不影响我们了这几年供应链攻击的案例特别多从恶意npm包到base镜像投毒大家终于意识到依赖清单这件事的重要性。SBOM软件物料清单就是一份标准格式的依赖清单按CycloneDX或SPDX格式输出。SBOM的真正价值不是在出事故的时候才显现的而是在出漏洞公告的那天。比如某个开源组件被爆出高危漏洞你第一时间拿到所有相关应用的SBOM清单就能快速定位受影响的制品和服务评估是否真的调用了漏洞函数再决定要不要紧急修复。没有SBOM的团队这时候只能把代码仓库全部拉下来跑一遍SCA少则半天多则两三天。落地起来不难CI流水线在构建阶段用工具自动生成SBOM。以常见的Syft为例syft packages docker.io/library/nginx:1.25 -o cyclonedx-json sbom.nginx.json生成的SBOM和镜像一起存进制品仓库并在部署审批时作为一个必需的附件。后面配合漏洞库的推送就能实现新漏洞出来当天就知道哪些服务中招。4.2 镜像签名与准入控制拦住李鬼镜像供应链安全的另一个要点是确保镜像在从仓库拉取到集群部署的过程中没有被篡改。这个场景尤其在镜像仓库配置错误、或者某个内部镜像源被污染时非常重要。镜像签名的逻辑并不复杂构建完成后用一个私钥对镜像摘要签名部署时在K8s侧验证签名是否匹配。如果镜像在传输过程中被改动摘要不一致签名验证就会失败Pod拒绝启动。工具链上可以用cosign做签名配合K8s的准入控制器例如通过OPA Gatekeeper或Kyverno在部署时强制校验cosign sign --key cosign.key registry.example.com/payment-service:v1.2.0准入策略可以配置成只允许运行带有有效签名的镜像并且禁止latest标签部署。后面这条很多人会忽略——latest标签是可以被反复覆盖的今天部署的内容和明天部署的内容未必一致。生产环境强制使用不可变标签配合签名校验是对镜像可信度的双重保证。4.3 密钥管理不要在配置仓库里埋雷密钥管理是云原生安全里最说不出口但又最常出问题的地方。很多团队把数据库密码、API密钥直接写在K8s的Secret里甚至写在ConfigMap或者Git仓库里。K8s的Secret本质上是base64编码存储不设加密的话任何人只要能读到etcd就能还原出明文。我的建议是不要把Secret当保险箱只把它当临时存储真正的密钥运转要交给专用的密钥管理系统比如Vault或云厂商的KMS。应用中通过SDK动态获取密钥不在环境变量里写死更不放到镜像里。如果团队规模小、暂时不想引入额外的密钥管理系统那至少要做到以下几点一是Secret的访问权限通过RBAC严格控制默认不授权二是定期轮换密钥最好有自动化脚本三是审计日志里对Secret的读写进行记录四是绝不允许把Secret写进Git仓库哪怕私有仓库也不行。我见过太多私有仓库最终还是被拖库的案例了不要在这不可能泄露上赌。5. 常见问题与排查技巧实录5.1 安全扫描一堆漏洞开发却不改怎么办这是我在踩坑中总结出的最实际的回答不要直接丢一份全量漏洞报告过去而是先由安全团队做一次风险收敛过滤掉下面几类只影响构建镜像、但运行镜像并未包含的组件多阶段构建的好处在这里体现漏洞组件虽然存在但应用代码里没有调用到受影响函数漏洞的利用条件在当前网络策略下无法满足比如漏洞需要外部入站访问但该服务根本没有对外暴露端口。过滤之后剩下的列表再开会跟开发逐条确认修复计划。实践下来高危列表通常会从几十条收敛到几条这个粒度开发才愿意配合。同时把修复项作为迭代的硬性DoDDefinition of Done——不修复不让发版。有了这个机制后面新服务的漏洞增量就会慢慢下降。5.2 安全策略把业务搞挂了一个典型事故复盘有一次我们给某个核心服务加了NetworkPolicy配置是对外只允许Ingress网关访问。结果上线之后服务间歇性超时排查了半天才发现该服务需要调用一个外部支付接口而我配置的Egress只放行了特定几个内部Service没考虑外部出口的IP。这个事故最后影响了线上支付流程二十分钟复盘的时候我意识到安全配置的验证不能靠看YAML要靠对流量日志。后来我们形成了一套标准动作新上线或修改安全策略之前先在测试环境开启一段时间的流量审计记录所有被策略静默丢弃的连接项目组根据审计结果决定哪些流量需要加入白名单再正式切策略。这样就把策略上线导致业务故障的概率降到了最低。5.3 从告警到处置如何不淹死在告警海洋里Falco接进去之后第一个月的告警数据一天几百条其中大部分是业务正常行为的误报。比如有的服务定期读取/etc/hosts有的定时任务会在容器里跑ps命令做健康检查这些在默认规则下都会触发告警。我处理这个问题的一个核心方法是告警分级和规则演进。Falco规则支持定义输出字段和优先级我把规则分成了三类WARNING级别的只做记录针对的是容易误报但不致命的行为CRITICAL级别的才做页面告警和IM通知比如容器里出现提权系统调用、挂载宿主机目录等EMERGENCY级别的事件自动触发Pod隔离和工单创建。然后把每一条误报都当成规则改进的契机通过加例外条件来收敛噪声。一个月之后告警量从日均几百降到个位数但真正有价值的告警一条都没漏。还有一点要特别注意告警处置完之后一定要写事后分析记录触发链路、处置过程和改进项。不是为了写文档而写文档而是因为很多攻击链是组合式的——单条告警看着都不严重但串在一起可能就是一次完整的入侵尝试复盘能帮你看到这条链的全貌。6. 踩过这些坑之后我总结的几条安全开发底线原则6.1 安全左移不代表只要扫描过就等于安全很多团队把DevSecOps简单理解成在CI里加几步扫描扫过了就算安全了。但扫描只是检查真正的安全来自设计。比如微服务之间无论怎么加密通信服务端的鉴权逻辑如果有漏洞扫描器是看不出来的。威胁建模、权限设计、数据流向审查这些人肉工作仍然不可替代。工具能帮你找到已知的问题设计评审才能帮你发现未知的风险。6.2 安全策略要可测试否则就是给业务埋雷无论是NetworkPolicy、PodSecurity还是准入控制所有安全策略都应该像代码一样走测试流程在测试环境验证策略确实拦截了该拦截的流量、放行了该放行的流量再推广到生产。我们内部建了一套安全策略CI用kind跑起一个临时集群应用策略后自动跑一组探针用例任何策略改动都必须通过这个CI才允许合并。这套实践比任何安全评审都管用。6.3 没有观测就没有安全最后想说的是安全开发和防护几乎所有的环节都要依赖可观测性。没有完整的调用链你无法判断一个可疑流量是从哪个服务进来的没有审计日志你无法确定攻击者做了什么没有Metrics你连策略是否真的生效都看不出。所以如果团队刚起步预算有限与其先买各种安全产品不如先把日志、指标、链路这三件事做好。安全能力的上限大概就是你观测能力的天花板。我个人做了这几年云原生安全最大的体会是安全不是某个团队的独角戏也不是上线前的一道闸门更不是一堆冷冰冰的策略。它更像是给整个交付体系织一张网——开发把安全考虑进代码里平台把基线嵌进流程里运维把观测和响应连起来。哪一环松了网就会破一个口子。把这个体系逐步搭起来比任何一次性的安全整改都更重要。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑