CI/CD流水线安全实战:别让攻击者通过你的部署管道进生产
本内容发表于:2026-04-16 10:53:33
浏览量
1024

CI/CD流水线安全实战:别让攻击者通过你的部署管道进生产

微信图片_2026-04-16_105126_156.png

去年,一个客户的工程师在GitHub上不小心泄露了CI token。几个小时后,攻击者利用这个token,在他们的CI流水线里插入了一段恶意代码——把数据库连接信息悄悄发到了一个境外IP。

三天后,数据库里的用户数据开始外泄。安全团队溯源发现,攻击者不是通过应用漏洞进来的,而是通过他们的CI/CD流水线。代码审核没发现问题,因为恶意代码在CI阶段才注入,根本没进代码仓库。

这是最可怕的安全盲区:你的部署管道,可能比你的应用更容易被攻破。

今天聊聊CI/CD流水线安全。不是那种“安全很重要”的废话,而是帮你理清楚:攻击者怎么打进来?你该怎么防?密钥怎么管?依赖怎么检查?镜像怎么扫描?

01 为什么攻击者盯上你的CI/CD?

攻击者打你的应用,要过WAF、要绕认证、要挖漏洞,费劲。但打你的CI/CD流水线,可能只需要一个泄露的token。

CI/CD流水线有几个“天生”的安全弱点:

  • 权限极高:流水线能部署到生产、能访问数据库、能读写代码仓库。拿到CI权限,等于拿到半个生产环境。

  • 审计薄弱:很多人盯着应用日志,但没人看CI日志。攻击者在流水线里搞小动作,可能几周都没人发现。

  • 第三方依赖多:GitHub Actions、Jenkins插件、各种action,每个都可能成为攻击入口。

反常识观点:CI/CD不是内部工具就安全。 你的CI/CD跑在云上、依赖开源action、密钥存在环境变量里——攻击面和公网应用一样大。

02 攻击者怎么打进你的流水线?

几个真实发生过的攻击路径,看看你有没有中招。

路径一:密钥泄露

最常见。开发者把CI token、云密钥硬编码在代码里,或者写在.env文件提交到GitHub。攻击者扫描到,直接接管CI流水线。

路径二:恶意第三方action

CI脚本里引用了社区action,比如actions/checkout@v3。如果这个action被投毒,或者你拼错了名字(action/checkout),可能拉到一个冒牌action,里面藏着后门。

路径三:依赖投毒

CI里会跑npm installpip install。如果依赖仓库里有恶意包,你的构建过程就被污染了。2021年,就有攻击者在npm上发布了event-stream的恶意版本,影响了数百万项目。

路径四:代码仓库被污染

攻击者不是直接改你的代码,而是改你的CI脚本——.github/workflows/下的YAML文件。代码审核没注意到,合并后流水线就跑恶意代码了。

03 第一道防线:密钥管理

密钥泄露是CI/CD安全的第一大漏洞。怎么防?

别把密钥写死在代码里。 这是底线。用CI平台自带的secrets管理(GitHub Secrets、GitLab CI Variables、Jenkins Credentials)。密钥在日志里会被自动打码。

用临时凭证,别用长期密钥。 AWS、GCP、Azure都支持OIDC(OpenID Connect)。CI平台可以临时申请云权限,用完即废,不需要把长期密钥存在CI里。就算泄露了,几分钟就过期。

定期轮换。 假设密钥总有一天会泄露,定期换。CI平台一般支持自动轮换,打开它。

那家被攻击的客户,后来全面改用OIDC,不再存储任何长期密钥在CI里。工程师说:“以前存了几十个密钥在CI里,哪个泄露了都不知道。现在OIDC配好,心里踏实了。”

04 第二道防线:依赖与action安全

CI脚本引用的action和依赖,是另一个大风险。

锁定依赖版本。 别用@v3这种大版本号,用完整的commit hash,比如actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab。hash不可变,不会在你不知情时被替换。

使用私有action镜像。 把常用的action fork到公司内部,自己审核代码,再从内部引用。避免直接从社区拉。

依赖扫描。 在CI里加一步npm auditpip-audittrivy fs,扫描依赖是否有已知漏洞。有高危漏洞就中断构建。

用私有依赖仓库。 别直接从公网npm/pypi拉包。用私有代理(如Artifactory、Nexus),只拉经过审核的包。

05 第三道防线:构建环境隔离

CI job跑在共享环境里,可能被其他job影响,也可能泄露数据。

用临时构建环境。 每次构建用全新的容器或虚拟机,跑完销毁。GitHub Actions的runner本身就是临时的,这很好。自建Jenkins要注意,别让job之间共享工作区。

最小权限原则。 每个CI job只授予它需要的权限。比如测试job不需要写制品库,构建job不需要访问生产数据库。分开设。

环境隔离。 PR触发的job,别让它访问任何敏感信息。攻击者可以发个PR,让你的CI跑他的代码。

限制出站网络。 CI job跑的时候,允许它访问哪些外部服务?大部分情况只需要访问git、镜像仓库、依赖仓库。其他都拦住。

06 第四道防线:镜像与制品安全

构建出来的镜像和制品,是最终进生产的。

基础镜像安全。 用官方镜像,别用latest tag,指定具体版本。扫描基础镜像漏洞(Trivy、Grype)。

多层扫描。 构建时扫一次依赖,打包镜像时再扫一次。有些漏洞在构建时没有,但镜像里多了一层包就有。

镜像签名。 构建完给镜像签名(Cosign、Notary),部署时验证签名。确保部署的镜像就是CI构建的那个,没人篡改过。

制品库权限。 只有CI能写制品库,其他人都只能读。防止有人手动上传恶意镜像。

07 一个真实案例:CI pipeline如何被攻破

去年,一个客户的GitHub token泄露了。攻击者拿到后,没有直接改代码,而是修改了CI脚本——在构建步骤里加了一条命令,把.env文件内容发到外部服务器。

代码审核没发现,因为改动很小,看起来像正常的日志输出。合并后,流水线跑起来,生产环境的密钥全部泄露。

修复过程:

  • 立即吊销泄露的token,换新密钥

  • 回滚CI脚本,增加审核规则:任何对workflow文件的修改,必须两人审核

  • 启用OIDC,停止在CI里存长期密钥

  • 增加CI日志监控,异常外发流量告警

安全负责人说:“以前觉得CI是内部工具,没人会盯着。现在才知道,攻击者早就盯上了。”

写在最后

CI/CD流水线是企业软件供应链的核心,也是攻击者的高价值目标。你把安全堆在应用层、网络层、主机层,但流水线本身是敞开的,等于白干。

那家客户后来总结了几条经验:

  • 密钥用OIDC,别存在CI里

  • action和依赖锁版本,定期扫描

  • 构建环境临时隔离,权限最小化

  • 镜像签名,部署时验证

  • CI脚本变更需要双人审核

技术负责人说:“以前觉得CI就是让代码上线更快,现在觉得,让代码安全上线才是本事。”

你的CI/CD流水线,锁好了吗?