:从基类选择到测试落地的完整实战指南)
为 Checkov 编写新的 OpenAPI 安全策略Policy从基类选择到测试落地的完整实战指南【免费下载链接】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本指南以 Checkov 开源仓库中 Contribute New OpenAPI Policies 文档为骨架结合 OpenAPI 扫描器源码 与真实测试用例完整演示如何为 OpenAPI 2.0 / 3.x 接口定义文件新增一条配置安全检查Check。读完本文你将掌握 v2 / v3 / generic 三类检查的基类与扫描方法选择、scan_entity_conf的返回值约定、检查注册与自动发现机制以及如何用仓库既有的测试模板为新增检查编写可验证的单元测试最终让你的策略在贡献合并后随 Checkov 扫描自动生效。一、背景Checkov 如何扫描 OpenAPI 文件在动手写检查之前先理解 OpenAPI 扫描器在 Checkov 中的定位。相关代码集中在 checkov/openapi 目录runner.py —— 扫描入口同时继承YamlRunner与JsonRunner因此 OpenAPI 检查天然支持.json、.yml、.yaml三种文件格式见 runner.py 中的file_extensions。registry.py 与 base_registry.py —— 检查注册表所有 OpenAPI 检查在实例化时自动注册check_type CheckType.OPENAPI。checks/resource —— 所有 OpenAPI 策略的实现目录按版本拆分为v2、v3、generic三个子目录。扫描器在解析文件时会先做两层校验见 runner.pypre_validate_file粗略检查文件内容是否包含swagger或openapi关键字不包含则直接跳过避免把无关 YAML/JSON 文件误判为 OpenAPI。is_valid解析后进一步校验文档根节点必须包含swaggerv2或openapiv3字段且info必须是 dict见 runner.py。这两步决定了你的检查所面对的conf一定是通过了上述预校验的、根级合法的 OpenAPI 文档结构你可以在scan_entity_conf中放心地按conf.get(...)取字段。二、三种检查类型v2、v3 与 generic 的选择新增检查的第一步是确定它要针对哪个 OpenAPI 版本然后进入 checkov/openapi/checks/resource 下对应的子目录目录适用版本继承的父类需要实现的扫描方法v2OpenAPI 2.0Swagger以swagger: 2.0声明BaseOpenapiCheckV2scan_openapi_confv3OpenAPI 3.x以openapi: 3.x.y声明BaseOpenapiCheckV3scan_openapi_confgeneric同时适用于 OpenAPI 2 与 3BaseOpenapiCheckscan_entity_conf三个父类之间的版本分派逻辑可以从源码看得非常清楚BaseOpenapiCheckV2其scan_entity_conf会检查conf中是否存在swagger字段且值为字符串2.0命中才把处理交给你的scan_openapi_conf否则返回CheckResult.UNKNOWN不参与结论。BaseOpenapiCheckV3逻辑对称检查openapi字段是否以3.开头命中才调用scan_openapi_conf。BaseOpenapiCheck直接继承框架的BaseCheck构造时自动完成注册registry.register(self)需要你直接实现scan_entity_conf。所以规则很简单只关心 2.0 用 V2只关心 3.x 用 V3两者都要管用 generic。选择 generic 时由于scan_entity_conf直接收到整个文档你通常需要自己兼容两种版本的字段差异例如 v2 用securityDefinitions、v3 用components.securitySchemes可参考 ClearTextAPIKey.py 中同时处理两个版本字段的写法。三、实战编写一个全新的检查GlobalSecurityFieldIsEmpty下面以原文档给出的示例——新增检查CKV_OPENAPI_4“全局 security 字段必须定义规则”——完整走一遍编码流程。该检查对 OpenAPI 2 和 3 都适用因此放在generic目录文件名为GlobalSecurityFieldIsEmpty.py仓库中已合入的实现见 checkov/openapi/checks/resource/generic/GlobalSecurityFieldIsEmpty.py。3.1 检查代码逐段解析from __future__ import annotations from typing import Any from checkov.common.models.enums import CheckResult, CheckCategories from checkov.common.checks.enums import BlockType from checkov.openapi.checks.base_openapi_check import BaseOpenapiCheck class GlobalSecurityFieldIsEmpty(BaseOpenapiCheck): def __init__(self) - None: id CKV_OPENAPI_4 name Ensure that the global security field has rules defined categories [CheckCategories.API_SECURITY] supported_resources [security] super().__init__(namename, idid, categoriescategories, supported_entitiessupported_resources, block_typeBlockType.DOCUMENT) def scan_entity_conf(self, conf: dict[str, Any], entity_type: str) - tuple[CheckResult, dict[str, Any]]: security_rules conf.get(security) if security_rules: return CheckResult.PASSED, security_rules return CheckResult.FAILED, conf check GlobalSecurityFieldIsEmpty()关键点说明ID 与命名id采用CKV_OPENAPI_N编号体系。当前仓库已存在 CKV_OPENAPI_1 至 CKV_OPENAPI_21 共 21 条检查完整清单见 docs/5.Policy Index/openapi.md新贡献的检查应顺延使用下一个未占用的编号避免冲突。类别categories使用CheckCategories.API_SECURITY枚举定义见 checkov/common/models/enums.py该类别专用于 API 安全策略。支撑实体supported_resources [security]表示该检查面向文档根级的security字段。块类型block_typeBlockType.DOCUMENT枚举见 checkov/common/checks/enums.py表示检查作用于整个 OpenAPI 文档对象而非按数组/对象逐个拆分的子块。扫描方法签名scan_entity_conf(self, conf, entity_type)返回二元组(CheckResult, dict)其中第二个元素是用于报告定位的资源配置。框架基类BaseCheck.run会直接取该返回值作为检查结果见 checkov/common/checks/base_check.py。结果语义conf.get(security)取到非空值含非空列表即PASSED缺失或为空列表[]则FAILED。注意if security_rules对[]求值为假这正是该检查要拦截的场景。模块级实例文件末尾的check GlobalSecurityFieldIsEmpty()是必须的——构造函数会触发 registry.py 的自动注册Checkov 启动扫描时通过注册表发现全部检查。3.2 检查是如何被自动发现的BaseOpenapiCheck.__init__中执行了registry.register(self)见 base_openapi_check.py而 registry.py 中定义的openapi_registry是全局单例。扫描器在 runner.py 的import_registry中导入它因此新增的检查文件不需要任何额外配置——只要放在checkov/openapi/checks/resource/v2|v3|generic/下、类继承正确的父类并在模块级实例化就会被注册表自动拾取。这也是原文档“So there you have it!”所描述的零配置生效机制。四、为新增检查编写测试原文档要求“follow the examples intests/openapi/test_runner.pyand add a test to the new check”。需要说明的是仓库当前版本的测试布局已比文档写作时更细化实际存在三处测试资产4.1 每检查独立的单元测试推荐主路径每个检查都有对应的test_CheckName.py与示例资源目录。以本检查为例见 tests/openapi/checks/resource/generic/test_GlobalSecurityFieldIsEmpty.py其配套资源目录 example_GlobalSecurityFieldIsEmpty 下放置了四个样本文件pass.yaml/pass.json声明了非空的security列表如security: - test: []应当判定为通过。fail.yaml/fail.jsonsecurity: []为空列表应当判定为失败。测试的核心逻辑是构造Runner用RunnerFilter(checks[check.id])只跑目标检查然后断言 summary 的passed/failed/skipped/parsing_errors数量并逐一比对通过/失败的文件路径集合report Runner().run(root_folderstr(test_files_dir), runner_filterRunnerFilter(checks[check.id])) summary report.get_summary() assert summary[passed] 2 assert summary[failed] 2一个规范的做法是同时提供 YAML 与 JSON 两种格式的通过/失败样例因为 OpenAPI 扫描器同时支持三种扩展名.json/.yml/.yaml。4.2 按目录聚合的测试与逐文件 expected 模式tests/openapi/checks/test_python_policies.py为每个 v2/generic 检查提供test_CheckName函数通过run_check辅助函数读取示例目录下的expected.yaml其中以pass/fail列表声明预期通过/失败的文件再断言summary与文件集合完全一致。tests/openapi/runner/test_runner.py针对扫描器整体行为的回归测试例如同时运行 CKV_OPENAPI_1/3/4 断言失败与通过数量、验证pre_validate_file对非 OpenAPI 文件返回False、对含openapi/swagger的 YAML/JSON 返回True以及 enforcement rules 生效时结果被关闭。新增检查建议至少补齐第 4.1 节的单检查测试若想覆盖更完整的版本兼容行为可仿照 4.2 的模式补充 expected.yaml 断言。五、本地验证与运行在提交贡献前可以用 CLI 直接验证新检查在真实文件上的表现。OpenAPI 扫描框架通过--framework openapi指定例如# 对单个 OpenAPI 文件运行全部 openapi 检查含新增的 checkov -f openapi.yaml --framework openapi # 对目录递归扫描 checkov -d ./api_specs --framework openapi仓库中可直接用作验证样例的资源包括 tests/openapi/runner/resources/v2/example.yaml含security与securityDefinitions的完整 v2 示例以及 tests/openapi/runner/resources/v3 目录下的 v3 样例。若希望新增检查只针对 OpenAPI 2.0可直接基于 example.yaml 修改若希望验证 generic 检查可同时准备 v2 与 v3 两个版本的文件。另外RunnerFilter支持checks[...]精确圈定检查集合见 tests/openapi/runner/test_runner.py 的用法在调试单个新检查时非常高效无需等待全部检查跑完。六、参考现有实现仓库中的检查模式清单为了让新检查的写法与仓库既有风格保持一致可按需参考以下已合入的实现完整编号清单见 docs/5.Policy Index/openapi.mdv2 检查如 SecurityDefinitions.pyCKV_OPENAPI_1校验securityDefinitions非空、GlobalSchemeDefineHTTP.pyCKV_OPENAPI_18校验全局 schemes 使用 https。v3 检查如 CleartextOverUnencryptedChannel.pyCKV_OPENAPI_3检查components.securitySchemes中是否存在明文 basic 认证其scan_openapi_conf内部会处理__startline__/__endline__之类的解析辅助键值得在编写 v3 检查时留意。generic 检查除本文的 GlobalSecurityFieldIsEmpty.py 外还有 SecurityOperations.pyCKV_OPENAPI_5逐 path 检查操作级security非空、NoMaximumNumberItems.pyCKV_OPENAPI_21递归遍历数组 schema 检查maxItems。从源码结构看generic 检查通常需要处理更多版本差异与递归遍历而 v2/v3 检查由于父类已做好版本分派代码更聚焦。新贡献者可以根据检查目标的复杂度选择最合适的类别。七、小结一条新策略的完整生命周期确定目标版本2.0 / 3.x / 通用进入 checkov/openapi/checks/resource 对应子目录继承对应父类实现scan_openapi_conf或scan_entity_conf分配下一个CKV_OPENAPI_N编号模块级实例化以完成注册在 tests/openapi 下为检查补齐 pass/fail 样例与单元测试本地用checkov --framework openapi对样例文件验证结果提交 PR合并后该检查即随注册表自动参与所有 OpenAPI 文件的扫描。整个过程中不需要修改任何框架代码或注册配置——这正是 Checkov OpenAPI 检查体系“新增即生效”的扩展性设计。若想进一步了解 Python 风格检查的通用编写规范可参考仓库中的 Contribute Python-Based Policies 文档。【免费下载链接】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),仅供参考