AWS CloudFormation Guard
1# 什么是AWS CloudFormation Guard?
AWS CloudFormation Guard(cfn-guard) 为合规性管理员提供了一种简单的策略即代码语言,用于定义规则,检查要求的和强制的资源配置。它使开发人员能够根据这些规则验证他们的 CloudFormation 模板。
cfn-guard 可帮助企业最大限度地降低与运营成本超支、安全漏洞、法律问题等相关的风险。例如,管理员可以创建规则,确保开发人员始终创建加密的亚马逊 S3 存储桶。cfn-guard 采用轻量级声明式语法,管理员无需学习编程语言即可快速定义规则。开发人员可以在本地编辑模板时使用 cfn-guard,也可以作为 CI/CD 管道的一部分自动使用 cfn-guard,以停止部署不合规的资源。如果模板中的资源不符合规则,cfn-guard 会为开发人员提供信息,帮助识别不符合规则的资源。
它允许对 CloudFormation 模板资源进行部署前安全检查。您既可以要求包含设置,也可以禁止以前曾导致问题的配置。
可以嵌入到CI/CD的流程中。
可以在本地运行,也可在 AWS 账户中作为 lambdas 运行,以便与其他 AWS 服务集成。
上手很容易。你可以使用 cfn-guard 的规则生成功能,从现有的已知良好模板中提取你想要的规则。
2# 如何使用AWS CloudFormation Guard?
cfn-guard 是一个开源命令行界面(CLI),可使用简单的策略即代码声明式语言检查 CloudFormation 模板是否符合策略。安装后,您可以使用给定的模板输入和规则集运行命令行,cfn-guard 将根据模板评估规则并反馈结果。
安装最新版的cfn-guard
参考Github的安装说明:https://github.com/aws-cloudformation/cloudformation-guard/tree/Guard1.0?tab=readme-ov-file#installation
假设添加安全检查策略用于检查创建EC2的IMDS版本,是否是IMDSv2的:
IMDS 提供对经常轮换的临时凭证的访问,因此您无需手动或以编程方式将敏感凭证分发到实例。 IMDS 本地连接到每个 EC2 实例。它运行在特殊的IP地址169.254.169.254上。该 IP 地址仅可由实例上运行的软件访问。
IMDSv2 增加了对可用于访问 IMDS 的漏洞的保护,IMDSv1没有进行任何校验,因此很容易被攻击者获取EC2上的AKSK。IMDSv2引入了token,可以避免攻击者获取AKSK。
验证成功的模板
Within the LaunchTemplateData
property, provide a MetadataOptions
configuration and set the value of HttpTokens
to required
.以下分别是JSON和YAML格式的样例:
JSON 样例
{
"EC2LaunchTemplate": {
"Type": "AWS::EC2::LaunchTemplate",
"Properties": {
"LaunchTemplateData": {
"InstanceType": "t3.micro",
"ImageId": {
"Ref": "LatestAmiId"
},
"MetadataOptions": {
"HttpTokens": "required"
}
}
}
}
}
YAML 样例
Parameters:
LatestAmiId:
Description: Region specific latest AMI ID from the Parameter Store
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
EC2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
InstanceType: t3.micro
ImageId:
Ref: LatestAmiId
MetadataOptions:
HttpTokens: required
创建一个CloudFormation文件pass_template.yaml,填写上面的内容后保存:
再创建一个文件ec2_imds2_rule_set.guard,填写下面的内容后保存。
# ###################################
## Rule Specification ##
#####################################
#
# Rule Identifier:
# ec2_launch_template_imdsv2_check
#
# Description:
# This control checks whether your Amazon EC2 launch templates are configured with Instance Metadata Service Version 2 (IMDSv2).
#
# Reports on:
# AWS::EC2::LaunchTemplate
#
# Evaluates:
# AWS CloudFormation, AWS CloudFormation hook
#
# Rule Parameters:
# None
#
# Scenarios:
# Scenario: 1
# Given: The input document is an AWS CloudFormation or AWS CloudFormation hook document
# And: The input document does not contain any EC2 launch template resources
# Then: SKIP
# Scenario: 2
# Given: The input document is an AWS CloudFormation or AWS CloudFormation hook document
# And: The input document contains an EC2 launch template resource
# And: 'LaunchTemplateData' has not been provided or 'LaunchTemplateData.MetadataOptions.HttpEndpoint' has
# been provided and is equal to 'disabled'
# Then: SKIP
# Scenario: 3
# Given: The input document is an AWS CloudFormation or AWS CloudFormation hook document
# And: The input document contains an EC2 launch template resource
# And: 'LaunchTemplateData' has been provided
# And: 'MetadataOptions.HttpEndpoint' in 'LaunchTemplateData' has not been provided or has been provided and
# is equal to 'enabled'
# And: 'MetadataOptions.HttpTokens' in 'LaunchTemplateData' has not been provided
# Then: FAIL
# Scenario: 4
# Given: The input document is an AWS CloudFormation or AWS CloudFormation hook document
# And: The input document contains an EC2 launch template resource
# And: 'LaunchTemplateData' has been provided
# And: 'MetadataOptions.HttpEndpoint' in 'LaunchTemplateData' has not been provided or has been provided and
# is equal to 'enabled'
# And: 'MetadataOptions.HttpTokens' in 'LaunchTemplateData' has been provided and set to a value other than 'required'
# Then: FAIL
# Scenario: 5
# Given: The input document is an AWS CloudFormation or AWS CloudFormation hook document
# And: The input document contains an EC2 launch template resource
# And: 'LaunchTemplateData' has been provided
# And: 'MetadataOptions.HttpEndpoint' in 'LaunchTemplateData' has not been provided or has been provided and
# is equal to 'enabled'
# And: 'MetadataOptions.HttpTokens' in 'LaunchTemplateData' has been provided and set to 'required'
# Then: PASS
#
# Constants
#
let EC2_LAUNCH_TEMPLATE_TYPE = "AWS::EC2::LaunchTemplate"
let INPUT_DOCUMENT = this
#
# Assignments
#
let ec2_launch_templates = Resources.*[ Type == %EC2_LAUNCH_TEMPLATE_TYPE ]
#
# Primary Rules
#
rule ec2_launch_template_imdsv2_check when is_cfn_template(%INPUT_DOCUMENT)
%ec2_launch_templates not empty {
check(%ec2_launch_templates.Properties)
<<
[CT.EC2.PR.1]: Require an Amazon EC2 launch template to have IMDSv2 configured
[FIX]: Within the 'LaunchTemplateData' property, provide a 'MetadataOptions' configuration and set the value of 'HttpTokens' to 'required'.
>>
}
rule ec2_launch_template_imdsv2_check when is_cfn_hook(%INPUT_DOCUMENT, %EC2_LAUNCH_TEMPLATE_TYPE) {
check(%INPUT_DOCUMENT.%EC2_LAUNCH_TEMPLATE_TYPE.resourceProperties)
<<
[CT.EC2.PR.1]: Require an Amazon EC2 launch template to have IMDSv2 configured
[FIX]: Within the 'LaunchTemplateData' property, provide a 'MetadataOptions' configuration and set the value of 'HttpTokens' to 'required'.
>>
}
#
# Parameterized Rules
#
rule check(launch_template) {
%launch_template [
# Scenario 2
filter_launch_template_imds_enabled(this)
] {
LaunchTemplateData exists
LaunchTemplateData is_struct
LaunchTemplateData {
# Scenario 3, 4 and 5
MetadataOptions exists
MetadataOptions is_struct
MetadataOptions {
HttpTokens exists
HttpTokens == "required"
}
}
}
}
rule filter_launch_template_imds_enabled(launch_template) {
%launch_template {
LaunchTemplateData exists
LaunchTemplateData is_struct
LaunchTemplateData {
MetadataOptions not exists or
filter_metadata_options_imds_enabled(this)
}
}
}
rule filter_metadata_options_imds_enabled(metadata_options) {
%metadata_options {
MetadataOptions is_struct
MetadataOptions {
HttpEndpoint not exists or
HttpEndpoint == "enabled"
}
}
}
#
# Utility Rules
#
rule is_cfn_template(doc) {
%doc {
AWSTemplateFormatVersion exists or
Resources exists
}
}
rule is_cfn_hook(doc, RESOURCE_TYPE) {
%doc.%RESOURCE_TYPE.resourceProperties exists
}
进入保存了这两个文件的文件夹,执行以下命令:
cfn-guard validate -d pass_template.yaml -r ec2_imds2_rule_set.guard --show-summary all
可以看到以下执行结果:
pass_template.yaml Status = PASS
PASS rules
ec2_imds2_rule_set.guard/ec2_launch_template_imdsv2_check PASS
验证失败的模板
如果模板中使用IMDSv1版本则使用以下内容创建文件fail_template.yaml:
Parameters:
LatestAmiId:
Description: Region specific latest AMI ID from the Parameter Store
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
EC2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
InstanceType: t3.micro
ImageId:
Ref: LatestAmiId
MetadataOptions:
HttpTokens: optional
然后执行以下命令:
cfn-guard validate -d fail_template.yaml -r ec2_imds2_rule_set.guard --show-summary all
将看到如下执行结果。
fail_template.yaml Status = FAIL
FAILED rules
ec2_imds2_rule_set.guard/ec2_launch_template_imdsv2_check FAIL
---
Evaluating data fail_template.yaml against rules ec2_imds2_rule_set.guard
Number of non-compliant resources 1
Resource = EC2LaunchTemplate {
Type = AWS::EC2::LaunchTemplate
Rule = ec2_launch_template_imdsv2_check {
ALL {
Rule = check {
Message {
[CT.EC2.PR.1]: Require an Amazon EC2 launch template to have IMDSv2 configured
[FIX]: Within the 'LaunchTemplateData' property, provide a 'MetadataOptions' configuration and set the value of 'HttpTokens' to 'required'.
}
ALL {
Check = HttpTokens EQUALS "required" {
ComparisonError {
Error = Check was not compliant as property value [Path=/Resources/EC2LaunchTemplate/Properties/LaunchTemplateData/MetadataOptions/HttpTokens[L:14,C:22] Value="optional"] not equal to value [Path=[L:0,C:0] Value="required"].
PropertyPath = /Resources/EC2LaunchTemplate/Properties/LaunchTemplateData/MetadataOptions/HttpTokens[L:14,C:22]
Operator = EQUAL
Value = "optional"
ComparedWith = "required"
Code:
12. ImageId:
13. Ref: LatestAmiId
14. MetadataOptions:
15. HttpTokens: optional
}
}
}
}
}
}
}
参考资料:[CT.EC2.PR.1] Require an Amazon EC2 launch template to have IMDSv2 configured
#3 如何嵌入到生产部署中
使用Control Tower
Control Tower预置了很多常用的Proactive controls,底层基于 AWS CloudFormation hooks。不需要写策略和进行繁琐的配置,激活使用即可。
使用AWS CloudFormation Hooks
如何使用AWS CloudFormation Hooks可以参见官方的帮助文档。
创建Lambda,CI/CD流程中引用这些lambda先检查,检查通过后才允许发版。
参考资料
最后更新于