ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Checkov 新 IaC Runner 贡献指南:从 example_runner 到注册接入的完整实战

Checkov 新 IaC Runner 贡献指南:从 example_runner 到注册接入的完整实战 Checkov 新 IaC Runner 贡献指南从 example_runner 到注册接入的完整实战【免费下载链接】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/checkovCheckov 通过统一的 CLI 扫描 Terraform、CloudFormation、Kubernetes、Helm、ARM、Serverless 等多种 IaC 框架其可扩展性核心之一就是Runner运行器机制。本文以仓库内真实源码为准系统讲解如何为一种全新的 IaC 语言/格式贡献一个 Runner从理解 Runner 与 Registry 的架构概念、识别资源类型到基于 checkov/example_runner 模板复制改造、接入 checkov/main.py 的DEFAULT_RUNNERS注册链再到编写首个 Check 并纳入 Policy Index。读完你可以独立为 Checkov 贡献一个新的 IaC 扫描后端。什么是 Checkov、什么是 RunnerCheckov 的定位Checkov 扫描云基础设施配置在部署前发现错误配置misconfiguration。它通过同一个命令行接口来管理并分析多种 IaC 平台的扫描结果覆盖 Terraform、CloudFormation、Kubernetes、Helm、ARM Templates 与 Serverless framework 等。Runner 的定义Runner是插入 Checkov 核心引擎的一段代码单元专门负责处理某一种 IaC 语言的解析parsing与特有格式将其翻译成一组 Checkov 内部的definitions定义数据结构。在此基础上贡献者可以为该语言编写checks检查项用于发现最佳实践与安全错误配置。也就是说Runner 负责把语言变成 Checkov 能理解的内部结构Check 负责在这个结构上做规则判断。核心术语速查术语含义IaC既包括专门声明式的基础设施语言如 Terraform、CloudFormation也包括能被唯一解释为有状态格式的通用格式如 Kubernetes 的 YAML/JSON、GitHub Actions 的 YAML。对于后者可直接基于已有的通用 JSON 或 YAML Runner 扩展Registry收集一组代码对象的数据结构。既有 Checks 的 Registry也有 Runners 自身的 Registry正是它们让 Checkov 保持可扩展——只要新代码被正确注册新 Check 与新 Runner 可以相互独立地添加Runner Registry一个预先存在的、跟踪 Checkov 当前可用全部 Runner 的注册表ResourceIaC 文件中可对其运行检查的单个单元。一个资源可能包含子资源类型一个 IaC 文件可以有多个可被检查的资源Definition/Entity将 IaC 资源抽象成 Checkov 内部数据结构的抽象表示Checkov 规则作用于其上Check一段自治的逻辑遍历并理解某个声明式代码结构的特有 schema对其中的 resource 应用特定的最佳实践或安全检查Report将检查结果汇总成一份报告随后再以多种格式输出如 CycloneDX、JSON、CLI 文本。与 definitions 一样报告起初是与最终输出格式无关的数据结构关于 Resource 粒度有一个值得注意的权衡宽泛的资源类型可以扩展到整个文件会让写检查容易得多但修复建议的定位精度会降低反之越细粒度的资源类型定位越精确越能支撑平台特性如 Smart Fixes。案例研究识别 GitHub Actions YAML 中的资源类型每种resource类型都需要自己的 checksregistry和checks。以 GitHub Actions YAML 为例on: pull_request name: unsecure-workflow jobs: unsecure-job: name: job2 runs-on: ubuntu-latest env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true steps: - name: unsecure-step2 run: | echo goo secure-job: name: job3 runs-on: ubuntu-latest env: ACTIONS_ALLOW_UNSECURE_COMMANDS: false run: | echo ok上述文件可以定义三种候选资源类型整个 workflow 文件错误配置及修复将针对整个文件呈现。最简单但定位不精细。jobs数组错误配置及潜在修复会以指定行号呈现到对应 job 上。用户体验更好。job 内的 steps也是数组此时错误配置及修复最精确能够支撑后续平台特性如 Smart Fixes。这个案例在仓库中的真实落地可见于 checkov/github_actions/runner.py 的get_resource方法——其注释明确列出 GHA 支持的资源jobs、jobs.*.steps[]、permissions、on并通过resolve_sub_name、resolve_step_name等工具将行号区间解析为类似jobs(unsecure-job).steps1的资源标识这些工具方法定义在 checkov/yaml_doc/runner.py。主路径基于 YAML / JSON 基础 Runner 扩展Option 1如果你的 IaC 基于已知的 JSON 或 YAML 语言那么大部分工作都可以从现有 Runner 中继承。下图展示了示例 Runner 需要修改或继承的主要文件1. 复制 example_runner 作为起点将 checkov/example_runner 目录复制一份改名为你的新 Runner 类型名下文以mynewiac_runner指代cp -r example_runner mynewiac_runner开箱即得一套带注释的文件每个文件内部都写明了需要修改的内容。目录树如下mynewiac_runner ├── __init__.py ├── checks │ ├── __init__.py │ ├── base_github_action_check.py │ ├── base_github_action_job_check.py │ ├── job │ │ ├── ExampleCheckTrueFalse.py │ │ └── __init__.py │ └── job_registry.py ├── common │ └── __init__.py └── runner.py说明模板文件注释中的文件名如base_github_action_check.py沿用了 GitHub Actions 示例的命名习惯实际复制后应统一改为你自己 Runner 的命名。2. 修改基础__init__.py第一行把 checkov/example_runner/init.py 中导入自身 checks 包的行改为你的 Runner 名from checkov.mynewiac_runner.checks import *3. 在 CheckType 中新增检查类型CheckType类定义在 checkov/common/bridgecrew/check_type.py是 Checkov 全局检查类型枚举。为你的新 Runner 增加一个成员MYNEWIAC mynewiac仓库中真实例子同文件GITHUB_ACTIONS github_actions4. 在 runner.py 中设置 check_type打开mynewiac_runner/runner.py在Runner类顶部把check_type指向你新增的类型。以真实源码 checkov/github_actions/runner.py 为参照class Runner(YamlRunner): check_type CheckType.GITHUB_ACTIONS模板 checkov/example_runner/runner.py 中对应的占位写法是check_type CheckType.MY_TYPEMY_TYPE需要在checkov/common/output/report.py的CheckType类中定义并附有block_type_registries字典将资源块类型映射到对应的 check registryblock_type_registries { jobs: job_registry, }5. 定义资源类型与对应的检查 Registry在示例 Runner 的checks目录下有三个关键文件├── checks │ ├── base_github_action_check.py # 资源无关的基础 Check │ ├── base_github_action_job_check.py # 特定资源类型job的基础 Check 子类 │ └── job_registry.py # 针对该资源类型的 Registry当一个 IaC 文件中可能存在多个资源类型时建议创建一个基础 Check再为每个具体资源类型派生一个子类示例中是job。每个资源类型都需要一份基础 Check 一个 Registry。job_registry.py默认直接复用 YAML Registry如果是 JSON 资源则切换到 JSON 的 Registryfrom checkov.common.bridgecrew.check_type import CheckType from checkov.yaml_doc.base_registry import Registry registry Registry(CheckType.YAML)见 checkov/example_runner/checks/job_registry.py。base checkbase_example_runner_check.py通常只需修改检查分类CheckCategories.XXXXX它继承checkov.common.checks.base_check.BaseCheck在__init__中传入 name、id、categories、supported_entities、block_type。job 的基础 Checkbase_example_runner_job_check.py把supported_entities设为资源类型字符串必须与 runner.py 中block_type_registries的 key 一致即jobs并在__init__末尾调用registry.register(self)完成注册class BaseExampleRunnerJobCheck(BaseExampleRunnerCheck): def __init__(self, name: str, id: str, block_type: str, path: str | None None) - None: super().__init__( namename, idid, supported_entities(jobs,), block_typeblock_type, ) self.path path registry.register(self)6. 覆盖 ObjectRunner 的抽象方法checkov/common/runners/object_runner.py 中的基础ObjectRunner定义了若干需要覆盖的抽象方法checkov/yaml_doc/runner.py已实现其中大部分import_registry(self)注册你为每个 block/资源类型准备的 Registry返回BaseCheckRegistry。示例见 checkov/example_runner/runner.pydef import_registry(self) - BaseCheckRegistry: return self.block_type_registries[jobs]_parse_file(self, f)根据该 IaC 特有的身份判据路径、头部、内容等决定文件f是否属于本 Runner 处理。关键注意点默认情况下所有 IaC 文件都会传给所有 Runner由各 Runner 自己决定其 check registry 是否适用——这个决策就在_parse_file里做出。GitHub Actions 示例按路径过滤checkov/github_actions/runner.py 实际使用is_workflow_file(f)并做 schema 校验模板中的示意写法为staticmethod def _parse_file(f: str, file_content: str | None None): if .github/workflows/ in os.path.abspath(f): return YamlRunner._parse_file(f) return None模板文件中的注释特别强调这里必须有条件判断否则你会解析所有文件见 checkov/example_runner/runner.py。get_start_end_lines(self, end, result_config, start)用于报告阶段确定不同 IaC 资源块的起始/结束行号。YAML/JSON Runner 已经替我们实现了该函数——checkov/yaml_doc/runner.py 中针对 list 与 dict 两种result_config借助解析时注入的__startline__/__endline__元数据计算行号区间。如果默认实现不满足需求再在子类中自行覆盖。7. 接入 docs_generator 与 main.py让 Checkov 真正调用你的 Runner第一步在 checkov/docs_generator.py 文件顶部导入你的 check registryfrom checkov.mynewiac_runner.checks.job_registry import registry as your_runner_registry仓库中真实写法checkov/docs_generator.pyfrom checkov.github_actions.checks.registry import registry as github_actions_jobs_registry第二步在 checkov/main.py 中导入你的 Runner 类该类位于文件顶部的大量 Runner 导入中见 checkov/main.pyfrom checkov.mynewiac_runner.runner import Runner as mynewiac_runner第三步把 Runner 实例加入DEFAULT_RUNNERS元组/列表文档中的写法是元组仓库当前版本为列表见 checkov/main.pyDEFAULT_RUNNERS [ tf_graph_runner(), cfn_runner(), k8_runner(), sls_runner(), arm_runner(), # ... 其他已有 Runner mynewiac_runner(), ]从源码结构看Checkov类在__init__中通过self.runners DEFAULT_RUNNERS.copy()checkov/main.py持有全部 Runner 并据此执行扫描因此加入DEFAULT_RUNNERS是 Runner 生效的关键一步。8. 将新 Check 持久化进 Policy Index自动为了让文档中的策略索引自动收录新 Runner 的检查项需要把 Runner 目录名加入 CI 构建脚本.github/workflows/build.yml中生成策略索引的 for 循环文档原文指向该文件第 141 行附近的写法for i in cloudformation terraform kubernetes serverless arm dockerfile secrets github_configuration gitlab_configuration bitbucket_configuration mynewiac_runner all即在现有列表末尾追加mynewiac_runner以及用于汇总的all。该循环驱动的生成逻辑与 checkov/docs_generator.py 协同最终产出docs/5.Policy Index/下各语言如 terraform.md、github_actions.md的策略清单。创建第一个 CheckRunner 接入后即可参照 Contribute Python-Based Policies 编写 Python 检查。example_runner 自带的 ExampleCheckTrueFalse.py 是一个可直接照抄的范本其要点class ExampleCheckTrueFalse(BaseExampleRunnerJobCheck): def __init__(self) - None: name Ensure ACTIONS_ALLOW_UNSECURE_COMMANDS isnt true on environment variables on a job id CKV_GHA_1 # CKV 是 Python checks 的标准前缀TLA 是 Runner 的三字母缩写编号必须唯一 super().__init__( namename, idid, # ARRAY期望一个或多个资源OBJECT期望单个资源 block_typeBlockType.ARRAY, ) def scan_entity_conf(self, conf: dict[str, Any], entity_type: str) - tuple[CheckResult, dict[str, Any]]: if env not in conf: return CheckResult.PASSED, conf env_variables conf.get(env, {}) if env_variables.get(MY_ENV_IS_PASSED, False): return CheckResult.FAILED, conf return CheckResult.PASSED, conf check ExampleCheckTrueFalse()编写要点源码注释中的官方建议name面向用户描述检查意图id格式为CKV_TLA_NCKV是 Python 检查的标准前缀TLA是 Runner 的三字母缩写如 GHA GitHub ActionsN是该 Runner 内递增且必须唯一的序号block_type取自 checkov/yaml_doc/enums.py 的BlockTypeARRAY表示可能匹配多个资源、OBJECT表示单个scan_entity_conf收到的conf是资源块对应的数据结构逻辑务必覆盖所有分支并始终返回 PASSED 或 FAILED——复杂逻辑中最容易遗漏某个结果。编写测试用例文档对测试部分标注为 TBD待补充。从仓库现有实践看可以参照同类 Runner 的测试组织方式来补充你的测试例如 GitHub Actions 的测试位于 tests/github_actions包含test_runner.py、test_runner_with_graph.py、test_schema_validation.py等YAML 文档类 Runner 的测试也可参考 tests/generic_yaml。通常需要准备一个包含待扫描 YAML/JSON 样例的测试资源目录、一条基于 Runner 执行扫描并断言Report中 FAILED/PASSED 检查项的用例以及针对_parse_file文件过滤逻辑的单元测试。总结新 Runner 接入清单步骤文件/位置要点1. 复制模板checkov/example_runner→checkov/mynewiac_runner改名并阅读文件内注释2. 修改__init__.pymynewiac_runner/__init__.py导入指向自身 checks 包3. 新增 CheckTypecheckov/common/bridgecrew/check_type.py添加如MYNEWIAC mynewiac4. 设置 check_typemynewiac_runner/runner.pycheck_type CheckType.MYNEWIAC5. 定义资源与 Registrychecks/目录每种资源类型基础 Check 子类 Registry6. 覆盖抽象方法runner.pyimport_registry、_parse_file、必要时get_start_end_lines7. 注册接入checkov/main.pyDEFAULT_RUNNERS checkov/docs_generator.py导入 Runner 与 registry8. 纳入 Policy Index.github/workflows/build.ymlfor 循环列表追加 Runner 目录名9. 编写 Checkchecks/resource/继承资源基础 Check返回唯一id10. 编写测试tests/runner/参照tests/github_actions组织完成以上步骤后Checkov 就会在每次扫描时自动调用你的 Runner将新 IaC 格式纳入统一的扫描、报告与策略索引体系。【免费下载链接】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),仅供参考
返回列表