使用 Guard 验证模板
Amazon CloudFormation Guard(cfn-guard)是一种策略即代码工具。您可以使用 Guard 语言编写描述必需或禁止配置的规则,然后根据这些规则检查 JSON 或 YAML 数据。例如,您可以要求模板中的每个 Amazon S3 存储桶都使用加密,或者屏蔽向互联网开放端口 22 的安全组规则。
Guard 适用于任何 JSON 或 YAML 数据。除了 CloudFormation 模板外,您还可以查看 CloudFormation 更改集和 Amazon Config 配置项目。本主题侧重于检查模板。
有关发布说明和完整的命令参考,请参阅 GitHub 上的 Guard
有关本地验证的限制以及部署前需采取的步骤,请参阅了解验证范围。
安装 Guard
在 macOS 上,使用 Homebrew 安装 Guard:
brew install cloudformation-guard
在 Linux 或 macOS 上,您可以改为运行安装脚本。该脚本将最新版本安装到 ~/.guard/bin。脚本完成后,请将该目录添加到您的 PATH。
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/aws-cloudformation/cloudformation-guard/main/install-guard.sh | sh
如果您有 Rust 工具链,也可以通过 Cargo 安装 Guard:
cargo install cfn-guard
要确认安装,请输出已安装的版本:
cfn-guard --version
有关 Windows 安装、Docker 映像和版本验证的信息,请参阅 Setting up Guard。
了解 Guard 语言
现在 Guard 已安装完毕,您可以开始编写规则了。Guard 规则由以下部分构成:
-
查询:使用虚线路径从数据中选择值,例如
Resources.MyBucket.Properties.BucketName。使用*选择映射中的每个值,使用[*]选择列表中的每个项目。在方括号中添加筛选条件以缩小选择范围。例如,Resources.*[ Type == 'AWS::S3::Bucket' ]选择每个 Amazon S3 存储桶。 -
子句:做出判定为真或假的断言。子句将查询与运算符(例如
==、!=、>=、in、exists、empty或is_string)组合在一起。位于不同行上的子句必须全部通过。要接受两个子句中的任何一个,请将其与or联接。 -
变量:使用
let存储查询结果,并在以后使用%前缀引用它。变量允许您一次性选择一组资源,并在多条规则中重复使用它。 -
命名规则:使用名称对
rule块中的子句进行分组。添加一个when条件,以便在规则不适用时将其跳过,例如,当模板没有 Amazon S3 存储桶时。规则可以引用其他规则,因此您可以从小部分构建复杂的策略。 -
自定义消息:在子句后的
<<和>>之间添加文本,以解释输出中的失败。
有关完整语法,请参阅 Writing Guard rules。
编写规则
将规则保存为扩展名为 .guard 的文件。rules.guard 中的以下示例要求模板中的每个 Amazon S3 存储桶都必须指定存储桶加密并屏蔽公共访问权限:
let s3_buckets = Resources.*[ Type == 'AWS::S3::Bucket' ] rule S3_BUCKET_ENCRYPTED when %s3_buckets !empty { %s3_buckets.Properties.BucketEncryption exists << Violation: S3 buckets must specify BucketEncryption. Fix: Add a BucketEncryption property with ServerSideEncryptionConfiguration. >> } rule S3_BUCKET_PUBLIC_ACCESS_BLOCKED when %s3_buckets !empty { %s3_buckets.Properties.PublicAccessBlockConfiguration { BlockPublicAcls == true BlockPublicPolicy == true IgnorePublicAcls == true RestrictPublicBuckets == true } }
第一行将每个 Amazon S3 存储桶存储在 s3_buckets 变量中。仅当模板包含至少一个存储桶时,每条规则才会运行。第一条规则检查 BucketEncryption 属性是否存在,并包含一条在检查失败时由 Guard 输出的消息。第二条规则检查 PublicAccessBlockConfiguration 内部的四个属性。由于子句位于不同的行中,因此所有四个子句均须通过。
您可以将多条规则保存在同一个文件中,也可以按主题将规则拆分到不同的文件中,例如,将存储规则存入一个文件,将网络规则存入另一个文件。当您将目录传递给命令时,Guard 会评估该目录中的每个 .guard 文件。
验证模板
将规则文件传递给 --rules,将模板传递给 --data。添加 --type CFNTemplate 以便 Guard 按资源逻辑 ID 报告调查发现。
cfn-guard validate --rules rules.guard --data template.yaml --type CFNTemplate
模板通过后,Guard 会输出 PASS 状态并返回退出代码 0。当规则未通过时,Guard 会列出未通过的规则;对于每个不合规的资源,它还会列出未通过的检查、属性路径以及原因。对于存储桶缺失 BucketEncryption 的模板,其输出以如下内容开头:
template.yaml Status = FAIL FAILED rules rules.guard/S3_BUCKET_ENCRYPTED FAIL --- Evaluating data template.yaml against rules rules.guard Number of non-compliant resources 1 Resource = MyBucket { Type = AWS::S3::Bucket Rule = S3_BUCKET_ENCRYPTED { ...
当一条或多条规则未通过时,Guard 会返回退出代码 19;当无法解析规则或数据文件时,则返回退出代码 5。您可以使用这些退出代码来停止自动化构建。
在验证模板时,以下选项非常有用:
-
多次传递
--rules或--data,或传递一个目录,以在一次运行中检查多个规则文件或模板。传递到--data的目录必须仅包含数据文件,而传递到--rules的目录必须仅包含规则文件。 -
将
--show-summary与pass、fail、skip、all或none配合使用以控制摘要表中显示哪些规则。默认值为fail。 -
将
--output-format与json、yaml、junit或sarif配合使用,为其他工具生成输出。junit和sarif格式适用于大多数构建系统和代码扫描工具。 -
使用
--input-parameters传递包含规则所引用的值的 JSON 或 YAML 文件,例如已批准的安全组 ID 列表。这使得环境特定的值不会出现在您的规则中。
有关所有选项,请参阅《Guard 用户指南》中的 validate。
测试规则
在自动化工作流中使用规则之前,请利用内置的单元测试支持对其进行测试。测试文件列出了示例输入以及针对每条规则所预期的结果:PASS、FAIL 或 SKIP。rules_tests.yaml 中的以下示例测试了上一个示例中的 S3_BUCKET_ENCRYPTED 规则:
--- - input: Resources: {} expectations: rules: S3_BUCKET_ENCRYPTED: SKIP - input: Resources: MyBucket: Type: AWS::S3::Bucket Properties: {} expectations: rules: S3_BUCKET_ENCRYPTED: FAIL - input: Resources: MyBucket: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: aws:kms expectations: rules: S3_BUCKET_ENCRYPTED: PASS
使用 test 命令运行测试:
cfn-guard test --rules-file rules.guard --test-data rules_tests.yaml
Guard 为每个期望值输出 PASS 或 FAIL,并在任何期望失败时返回退出代码 7。有关更多信息,请参阅 Testing Guard rules。
从模板生成规则
若想快速上手,您可以根据已满足您要求的模板生成规则。rulegen 命令会读取模板,并为需要模板中的属性值的每种资源类型编写规则:
cfn-guard rulegen --template template.yaml --output generated.guard
检查生成的文件,只保留代表您策略的检查。生成的规则是一个起点,通常需要源模板中的精确值,这对于其他模板可能过于严苛。
向您的工作流添加 Guard
您可以在以下位置运行 Guard:
-
在您的编辑器中:CloudFormation 语言服务器会在您编辑模板时运行 Guard 规则包,并以内联方式显示失败。有关设置,请参阅CloudFormation 语言服务器。
-
在 Git 提交之前:Guard 提供了一个
pre-commit钩子,可以在更改的模板上运行validate或在更改的规则上运行test。请将以下内容添加到.pre-commit-config.yaml文件中,并将路径替换为您自己的路径:repos: - repo: https://github.com/aws-cloudformation/cloudformation-guard rev: pre-commit-v0.0.2 hooks: - id: cfn-guard args: - --operation=validate - --rules=rules/ files: ^templates/.* -
在自动化构建中:将
cfn-guard validate作为构建步骤运行,并使用退出代码使构建失败。使用--output-format junit或--output-format sarif发布结果。此外还提供了一个 GitHub 操作和一个容器映像。请从public.ecr.aws/aws-cloudformation/cloudformation-guard提取映像。 -
使用
cloudformation-validate:cfn-validate命令和 Amazon CDK 验证插件可以运行支持的 Guard 规则子集及其内置检查。有关更多信息,请参阅 使用 cloudformation-validate 验证模板。 -
堆栈操作期间:要在 CloudFormation 或 Cloud Control API 创建、更新或删除资源时强制执行规则,请使用 Guard 钩子。有关更多信息,请参阅 Guard Hooks。
有关涵盖常见安全和合规控制的即用型规则,请参阅 GitHub 上的 Amazon Guard Rules Registry