#cloud-formation #properties #rule #check #guard #cfn-guard #resources

bin+lib cfn-guard-preview

CloudFormation Guard (cfn-guard) 的预览

1 个不稳定版本

0.7.0 2020 年 9 月 18 日

#9 in #cloud-formation

自定义许可证

115KB
2K SLoC

[预览] AWS CloudFormation Guard

用于验证 AWS CloudFormation 资源是否符合策略的命令行工具。

目录

关于

cfn-guard 是一个用于使用轻量级、类似于防火墙规则语法的语法来检查 CloudFormation 资源属性的工具。

以下是如何使用它的一个示例,给定一个 CloudFormation 模板

 > cat ebs_volume_template.json
{
"Resources": {
    "NewVolume" : {
        "Type" : "AWS::EC2::Volume",
        "Properties" : {
            "Size" : 100,
            "Encrypted": false,
            "AvailabilityZone" : "us-east-1b"
        }
    },
    "NewVolume2" : {
        "Type" : "AWS::EC2::Volume",
        "Properties" : {
            "Size" : 99,
            "Encrypted": true,
            "AvailabilityZone" : "us-east-1b"
        }
    }
  }
}

和规则文件

> cat ebs_volume_rule_set
let encryption_flag = true
let disallowed_azs = [us-east-1a,us-east-1b,us-east-1c]

AWS::EC2::Volume AvailabilityZone NOT_IN %disallowed_azs
AWS::EC2::Volume Encrypted != %encryption_flag
AWS::EC2::Volume Size == 101 |OR| AWS::EC2::Volume Size == 99 |OR| AWS::EC2::Volume Size >= 101
AWS::IAM::Role AssumeRolePolicyDocument.Version == 2012-10-18
AWS::EC2::Volume AvailabilityZone != /us-east-.*/

您可以检查该模板是否符合这些规则

> cfn-guard check -t ebs_volume_template.json -r ebs_volume_rule_set
"[NewVolume2] failed because [AvailabilityZone] is [us-east-1b] and the pattern [us-east-.*] is not permitted"
"[NewVolume2] failed because [Encrypted] is [true] and that value is not permitted"
"[NewVolume2] failed because [us-east-1b] is in [us-east-1a,us-east-1b,us-east-1c] which is not permitted for [AvailabilityZone]"
"[NewVolume] failed because [AvailabilityZone] is [us-east-1b] and the pattern [us-east-.*] is not permitted"
"[NewVolume] failed because [Size] is [100] and the permitted value is [101]"
"[NewVolume] failed because [Size] is [100] and the permitted value is [99]"
"[NewVolume] failed because [Size] is [100] and the permitted value is [>= 101]"
"[NewVolume] failed because [us-east-1b] is in [us-east-1a,us-east-1b,us-east-1c] which is not permitted for [AvailabilityZone]"
Number of failures: 7

我们设计 cfn-guard 以便将其插入到您的构建过程中。

如果 CloudFormation Guard 成功验证 CloudFormation 模板,则不会输出任何内容,并以退出状态 $? (在 bash 中)退出状态为 0。如果 CloudFormation Guard 识别到规则违规,则提供违规规则的计数、规则失败的原因以及退出状态为 2。如果规则集或处理过程中存在运行时错误,它将退出并显示 1

如果您希望 CloudFormation Guard 获取规则检查的结果,但仍然得到退出值 0,请使用 -w 警告标志。

检查与 Rulegen

cfn-guard 有两种模式

检查

check(如上例所示)检查模板是否与规则集相匹配。

cfn-guard-check
Check CloudFormation templates against rules

USAGE:
    cfn-guard check [FLAGS] --rule_set <RULE_SET_FILE> --template <TEMPLATE_FILE>

FLAGS:
    -h, --help             Prints help information
    -s, --strict-checks    Fail resources if they're missing the property that a rule checks
    -v                     Sets the level of verbosity - add v's to increase output
    -V, --version          Prints version information
    -w, --warn_only        Show results but return an exit code of 0 regardless of rule violations

OPTIONS:
    -r, --rule_set <RULE_SET_FILE>    Rules to check the template against
    -t, --template <TEMPLATE_FILE>    CloudFormation Template

Rulegen

rulegen 从 CloudFormation 模板自动生成一组与资源属性匹配的 cfn-guard 规则。这是开始编写规则或从已知的良好模板创建可立即使用的规则集的有用方法。

cfn-guard-rulegen
Autogenerate rules from an existing CloudFormation template

USAGE:
    cfn-guard rulegen [FLAGS] <TEMPLATE>

FLAGS:
    -h, --help       Prints help information
    -v               Sets the level of verbosity - add v's to increase output
    -V, --version    Prints version information

ARGS:
    <TEMPLATE>

例如

> cfn-guard rulegen Examples/ebs-volume-template.json
AWS::EC2::Volume AvailabilityZone == us-west-2b |OR| AWS::EC2::Volume AvailabilityZone == us-west-2c
AWS::EC2::Volume Encrypted == false
AWS::EC2::Volume Size == 50 |OR| AWS::EC2::Volume Size == 500

考虑到可能产生数百甚至数千条规则,我们建议将输出通过 sort 管道传递并保存到文件中供编辑

cfn-guard rulegen Examples/aws-waf-security-automations.template | sort > ~/waf_rules

编写规则

基本语法

我们将 cfn-guard 规则模式化为防火墙规则。它们易于编写,并且具有声明性语法。

CloudFormation Guard 最基本的规则形式为

<CloudFormation Resource Type> <Property> <Operator> <Value>

可用的运算符包括

  • == - 等于
  • != - 不等于
  • < - 小于
  • > - 大于
  • <= - 小于等于
  • >= - 大于等于
  • IN - 在以下列表中:[x, y, z]
  • NOT_IN - 不在以下列表中:[x, y, z]

检查资源属性和属性

规则中的属性可以有两种形式。基本形式旨在使编写简单规则非常直接

AWS::EC2::Volume Encryption == true

这种简单形式假设您正在检查的属性位于资源的Properties部分

    "NewVolume" : {
           "Type" : "AWS::EC2::Volume",
           "Properties" : {
               "Size" : 101,
               "Encrypted": true,
               "AvailabilityZone" : "us-west-2b"
           }
       }

但是,您可能还想要编写一个检查资源属性的规则

    "NewVolume" : {
       "Type" : "AWS::EC2::Volume",
       "Properties" : {
          "Size" : "100",
          "Encrypted" : "true",
       },
       "DeletionPolicy" : "Snapshot"
    }

在这种情况下,假设我们想检查出于部署安全原因的DeletionPolicy。我们可以编写一个检查位于Properties之上的属性的规则,通过在属性位置前的符号前加上一个.来表示您想检查资源根部的值

AWS::EC2::Volume .DeletionPolicy == Snapshot

注释

可以通过#运算符向规则集添加注释

# This is a comment

规则逻辑

AND和OR

给定规则集中的每个规则都隐式地与每个其他规则进行AND运算。

您可以使用|OR|在单行上对规则进行OR,以提供任意类型的替代可接受值

AWS::EBS::Volume Size == 500 |OR| AWS::EBS::Volume AvailabiltyZone == us-east-1b

WHEN检查

有时,您可能不希望在一个模板中对特定类型的每个资源检查相同的值。您可以使用WHEN-CHECK语法编写条件检查

<CloudFormation Resource Type> WHEN <Property> <Operator> <Value> CHECK <Property> <Operator> <Value>

例如

AWS::DynamoDB::Table WHEN Tags.* == /.*PROD.*/ CHECK .DeletionPolicy == Retain

第一个部分(WHEN Tags.* == /.*PROD.*/)是要过滤的条件

第二个部分(CHECK .DeletionPolicy == Retain)是资源必须通过才能使规则通过的结果

如果条件匹配,则评估结果,并将评估结果添加到整体规则集结果中

请注意,WHEN检查只能一次操作一个资源类型。它们也可以像常规规则一样使用OR进行聚合

AWS::DynamoDB::Table when Tags == /.*PROD.*/ check .DeletionPolicy == Retain |OR| AWS::DynamoDB::Table WHEN Tags.* == /.*DEV.*/ CHECK .DeletionPolicy == Delete

要查看条件规则的实际示例,请查看Examples目录中的conditional-ddb-template文件。

检查嵌套字段

使用显式路径

CloudFormation 资源属性内部的字段可以使用点符号来表示

AWS::IAM::Role AssumeRolePolicyDocument.Statement.0.Principal.Service.0 == lambda.amazonaws.com

请注意,该规则中的列表索引语法与以下Resources部分的CloudFormation模板相匹配

Resources:
  LambdaRoleHelper:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com

使用通配符

您还可以将模板项目、列表和映射称为通配符(*)。通配符是一种预处理器宏,它检查规则文件和模板,将通配符展开成与正在检查的模板中包含的规则长度相同的规则列表。

换句话说,给定以下形式的模板

Resources:
  LambdaRoleHelper:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com

以及以下形式的规则

AWS::IAM::Role AssumeRolePolicyDocument.Statement.*.Principal.Service.* == lambda.amazonaws.com

CloudFormation Guard 将遍历模板,并将内部通配符规则转换为

AWS::IAM::Role AssumeRolePolicyDocument.Statement.0.Principal.Service.0 == lambda.amazonaws.com |OR| AWS::IAM::Role AssumeRolePolicyDocument.Statement.1.Principal.Service.0 == ec2.amazonaws.com

通配符语义

请注意,等于(==)或在列表中(IN)运算符与不等式(!=)或在列表外(NOT_IN)运算符与通配符之间的不同语义意义

AWS::IAM::Role AssumeRolePolicyDocument.Statement.*.Principal.Service.* == lambda.amazonaws.com

意味着 "至少有一个匹配这些通配符的项目应该匹配该值",并且作为一组 OR 规则执行。

AWS::IAM::Role AssumeRolePolicyDocument.Statement.*.Principal.Service.* != lambda.amazonaws.com

意味着 "那些通配符匹配的项目中没有任何一个匹配该值",并且作为一组 AND 规则执行。

要查看规则在运行时的展开情况,请使用 - 标志运行,并在输出中查找 "应用规则"。

正则表达式

您还可以编写与 Rust 正则表达式语法(Rust Regex 语法)匹配的规则,该语法与 Perl 兼容正则表达式(PCRE)语法匹配。

形式为 /<regex pattern>/ 因此

AWS::IAM::Role AssumeRolePolicyDocument.Version == /(\d{5})-(\d{2})-(\d{2})/
AWS::EC2::Volume AvailabilityZone != /us-east-.*/

变量语法

赋值

您可以使用 let 语法声明变量

let <VAR NAME> = <list or scalar>

例如

let size = 500
# Regular list
let azs = [us-east-1b, us-east-1b]
# JSON list
let tag_vals = ["tests", 1, ["a", "b"], {"Key":"A","Value":"a"},{"Key":"A","Value":{"Ref":"a"}}]

然后使用 % 在规则中引用这些变量

AWS::EBS::Volume Size == %size

JSON 列表与非 JSON 列表

JSON 列表

任何有效的 JSON 列表字面量都是有效的 JSON 列表。以下列表

let tag_vals = ["tests", 1, ["a", "b"], {"Key":"A","Value":"a"},{"Key":"A","Value":{"Ref":"a"}}]

将展开成以下值的列表

"tests",
1,
["a, b"],
{"Key":"A","Value":"a"},
{"Key":"A","Value":{"Ref":"a"}}

您可以使用 INNOT_IN 来匹配模板资源的属性。

非 JSON 列表

任何非 JSON 字面量的列表只是逗号分隔的值列表。

混合列表类型

包含 JSON 和非 JSON 值的列表被解释为非 JSON

所以如果

let tag_vals = ["tests", {"Key":"A","Value":"a"},{"Key":"A","Value":{"Ref":"a"}}]

被写成

let tag_vals = [tests, {"Key":"A","Value":"a"},{"Key":"A","Value":{"Ref":"a"}}]

它将评估为以下项的列表

tests,
{"Key":"A",
"Value":"a"},
{"Key":"A",
"Value":{"Ref":"a"}}

这几乎肯定不是您想要的。

如果您在处理 JSON 列表的规则中看到奇怪的行为,请使用 - 运行,您将看到类似以下行

2020-07-01 14:49:18,411 DEBUG [cfn_guard::util] List [tests, {"Key":"A","Value":"a"},{"Key":"A","Value":{"Ref":"a"}}] is not a json list

这将为您提供有关 cfn-guard 如何处理它的更多信息。

(有关详细信息,请参阅 故障排除,了解如何使用不同的日志级别来查看模板和规则集的处理方式。)

环境变量

您还可以使用 Makefile 风格的符号引用 环境变量%{Name}

因此,您可以重写上面的 IAM 角色规则为

AWS::IAM::Role AssumeRolePolicyDocument.Statement.0.Principal.Service.0 == %{IAM_PRIN}

然后通过设置该变量从命令行调用 cfn-guard

IAM_PRIN=lambda.amazonaws.com cfn-guard -t iam_template -r iam_rule_set

注意:所有环境变量在运行时都可用。它们不需要在 cfn-guard 调用期间明确设置。

环境变量不会被记录,以避免持久化敏感信息。您应该使用它们将敏感值传递到 cfn-guard 而不是 let 形式。

自定义错误消息

在规则语法中有一个可选字段,您可以通过添加 << 和消息文本到规则末尾来提供自己的自定义消息

AWS::EC2::Volume Encrypted == %encryption_flag << lorem ipsum

此外,重要的是要记住 |OR| 构造是离散规则的连接。因此

AWS::EC2::Volume Size == 201 |OR| AWS::EC2::Volume Size == 199 << lorem ipsum

只会在第二条规则上返回自定义消息,而不是两条。如果您希望两条规则都有自定义消息,您需要将自定义消息添加到 |OR| 的两边

AWS::EC2::Volume Size == 201 << ipsum lorem |OR| AWS::EC2::Volume Size == 199 << lorem ipsum

类似地,当将相同的自定义消息添加到多个规则时,要小心。这可能会掩盖实际的失败。

例如,如果您应用以下 CloudFormation Guard 规则集

let allowed_azs = [us-east-1a,us-east-1b,us-east-1c]

AWS::EC2::Volume AvailabilityZone IN %allowed_azs
AWS::EC2::Volume AvailabilityZone == /.*d/

到 Examples/ebs_volume_template.json。 cfn-guard 会返回

"[NewVolume2] failed because [AvailabilityZone] is [us-west-2c] and the permitted pattern is [.*d]"
"[NewVolume2] failed because [us-west-2c] is not in [us-east-1a,us-east-1b,us-east-1c] for [AvailabilityZone]"

但如果两条规则都有相同的自定义错误消息

AWS::EC2::Volume AvailabilityZone IN %allowed_azs << lorem ipsum
AWS::EC2::Volume AvailabilityZone == /.*d/ << lorem ipsum

结果看起来像是一个错误的重复

 "[NewVolume2] failed because [AvailabilityZone] is [us-west-2c] and lorem ipsum"
 "[NewVolume2] failed because [AvailabilityZone] is [us-west-2c] and lorem ipsum"

自定义消息在 WHEN 检查 的两边都是语法有效的

AWS::DynamoDB::Table WHEN Tags == /.*PROD.*/ << custom conditional message CHECK .DeletionPolicy != Retain << custom consequent message

但是,condition 的自定义消息仅作为错误消息中包含的原始规则的一部分内联显示

[DDBTable] failed because [.DeletionPolicy] is [Retain] and custom consequent message when AWS::DynamoDB::Table Tags == /.*PROD.*/ << custom conditional message

与 CloudFormation 内置函数一起工作

由于 serde_yaml 解析 YAML 的方式,函数如 !GetAtt 被视为注释并忽略。例如

  NewVolume:
    Type: AWS::EC2::Volume
    Properties:
      Size: 512
      AvailabilityZone: !GetAtt [EC2Instance, AvailabilityZone]

与规则进行校验

AWS::EC2::Volume AvailabilityZone == !GetAtt [EC2Instance, AvailabilityZone]

导致失败

"[NewVolume] failed because [AvailabilityZone] is [["EC2Instance","AvailabilityZone"]] and the permitted value is [!GetAtt [EC2Instance, AvailabilityZone]]"

这种效果,加上解析器删除值之间的空白,意味着规则必须写成

AWS::EC2::Volume AvailabilityZone == ["EC2Instance","AvailabilityZone"]

其中值被引用,且在 , 后面没有空格才能匹配。

如果您看到某些应该匹配但实际上没有匹配的内容,失败消息(["EC2Instance","AvailabilityZone"])将帮助您确定原因。

关于删除空白的最后部分也适用于 Fn::GetAtt 函数的 JSON 版本

{
"Resources": {
    "NewVolume" : {
        "Type" : "AWS::EC2::Volume",
        "Properties" : {
            "Size" : 100,
            "Encrypted": false,
            "AvailabilityZone" : { "Fn::GetAtt" : [ "EC2Instance", "AvailabilityZone" ] }
        }
    },
    "NewVolume2" : {
        "Type" : "AWS::EC2::Volume",
        "Properties" : {
            "Size" : 99,
            "Encrypted": true,
            "AvailabilityZone" : "us-east-1b"
        }
    }
  }

它会以类似的消息失败

"[NewVolume] failed because [AvailabilityZone] is [{"Fn::GetAtt":["EC2Instance","AvailabilityZone"]}] and the permitted value is [["EC2Instance","AvailabilityZone"]]"

为了处理两种模板格式中的这两种情况,使用以下类似(无需转义引号和中间空白)的 |OR| 规则

AWS::EC2::Volume AvailabilityZone == ["EC2Instance","AvailabilityZone"] |OR| AWS::EC2::Volume AvailabilityZone == {"Fn::GetAtt":["EC2Instance","AvailabilityZone"]}

如果您对 YAML 或 JSON 的解析方式不确定,请在您要检查的模板上使用 cfn-guard-rulegen。它输出符合解析器相同属性的形式。

> cfn-guard-rulegen guard-test-ec2-dev.yaml
AWS::EC2::Instance SecurityGroups == ["InstanceSecurityGroup"]
AWS::EC2::Instance KeyName == KeyName
AWS::EC2::Volume AvailabilityZone == ["EC2Instance","AvailabilityZone"]
AWS::EC2::Volume Size == 512
AWS::EC2::Instance ImageId == LatestAmiId
AWS::EC2::SecurityGroup GroupDescription == Enable SSH access via custom port 33322
AWS::EC2::SecurityGroup SecurityGroupIngress == [{"CidrIp":"SSHLocation","FromPort":22,"IpProtocol":"tcp","ToPort":22}]
AWS::EC2::Instance InstanceType == t3.medium

⋊> cfn-guard-rulegen ebs_volume_template_example.json
AWS::EC2::Volume Size == 100 |OR| AWS::EC2::Volume Size == 99
AWS::EC2::Volume Encrypted == true |OR| AWS::EC2::Volume Encrypted == false
AWS::EC2::Volume AvailabilityZone == {"Fn::GetAtt":["EC2Instance","AvailabilityZone"]}

严格检查

--strict-check 标志会导致资源在它不包含规则检查的属性时失败检查。这有助于强制执行可选属性的存在,例如 Encryption == true

在组合使用严格检查和通配符之前需要仔细考虑。通配符在运行时创建规则,这些规则映射到所有类型的资源在该通配符位置的所有值。这意味着过于宽泛的通配符会导致过于宽泛的失败。

以下是一个通配符场景的示例

这是一个模板片段

{
    "Resources": {
        "NewVolume" : {
            "Type" : "AWS::EC2::Volume",
            "Properties" : {
                "AutoEnableIO": true,
                "Size" : 101,
                "Encrypted": true,
                "AvailabilityZone" : "us-west-2b"
            }
        },
        "NewVolume2" : {
            "Type" : "AWS::EC2::Volume",
            "Properties" : {
                "Size" : 99,
                "Encrypted": true,
                "AvailabilityZone" : "us-west-2c"
            }
        }
    }
}

在语义上完全有效(尽管实际价值可疑)使用通配符来确保至少有一个属性的值等于 true

AWS::EC2::Volume * == true

如上节关于通配符的讨论所述,这将在运行时转换为每个属性创建的规则,并通过一个|OR|进行连接

> cfn-guard -t ~/scratch-template.yaml -r ~/scratch.ruleset -vvv
...
2020-08-07 17:25:59,000 INFO  [cfn_guard] Applying rule 'CompoundRule(
    CompoundRule {
        compound_type: OR,
        raw_rule: "AWS::EC2::Volume * == true",
        rule_list: [
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "AvailabilityZone",
                    operation: Require,
                    value: "true",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "Size",
                    operation: Require,
                    value: "true",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "Encrypted",
                    operation: Require,
                    value: "true",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "AutoEnableIO",
                    operation: Require,
                    value: "true",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
        ],
    },
)'

检查将通过。

但是,如果你将通配符规则更改为!=

AWS::EC2::Volume * != false

OR规则变为AND规则

2020-08-07 17:33:20,637 INFO  [cfn_guard] Applying rule 'CompoundRule(
    CompoundRule {
        compound_type: AND,
        raw_rule: "AWS::EC2::Volume * != false",
        rule_list: [
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "AvailabilityZone",
                    operation: RequireNot,
                    value: "false",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "AutoEnableIO",
                    operation: RequireNot,
                    value: "false",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "Size",
                    operation: RequireNot,
                    value: "false",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
            SimpleRule(
                Rule {
                    resource_type: "AWS::EC2::Volume",
                    field: "Encrypted",
                    operation: RequireNot,
                    value: "false",
                    rule_vtype: Value,
                    custom_msg: None,
                },
            ),
        ],
    },
)'

如果你用--strict-checks运行它,它将失败,因为NewVolume2不包含AutoEnableIO属性

> cfn-guard -t ~/scratch-template.yaml -r ~/scratch.ruleset --strict-checks
[NewVolume2] failed because it does not contain the required property of [AutoEnableIO]
Number of failures: 1

诚然,这是一个非常牵强的例子,但了解这种行为很重要。

故障排除

cfn-guard旨在作为工具链的一部分使用。例如,它不会检查它收到的CloudFormation模板是否是有效的CloudFormation。已经有cfn-lint工具对模板结构进行了深入和彻底的检查,并为用户提供了大量的反馈,以帮助用户编写高质量的模板。

cfn-guard也不对检查的类型或这些类型可以检查的属性施加限制。当你手工编写规则时,这可能会引起一些困惑,因为你没有得到预期的结果。

要查看规则集是如何处理的,最佳方法是利用不同的日志级别(例如-vvv)。当启用日志记录时,您可以跟踪整个执行过程,并查看cfn-guard是如何在内部工作的。

例如,这是一个简单的模板

{
    "Resources": {
        "NewVolume" : {
            "Type" : "AWS::EC2::Volume",
            "Properties" : {
                "Size" : 101,
                "Encrypted": false,
                "AvailabilityZone" : "us-west-2b"
            }
        },
        "NewVolume2" : {
            "Type" : "AWS::EC2::Volume",
            "Properties" : {
                "Size" : 99,
                "Encrypted": false,
                "AvailabilityZone" : "us-west-2c"
            }
        }
    }
}

以及一个示例规则集

let encryption_flag = true
AWS::EC2::Volume Encrypted == %encryption_flag

启用-vvv跟踪日志记录后,您可以看到赋值的解析

2020-06-27 13:18:00,097 DEBUG [cfn_guard::parser] Parsing 'let encryption_flag = true'
2020-06-27 13:18:00,112 DEBUG [cfn_guard::parser] line_type is Assignment
2020-06-27 13:18:00,122 TRACE [cfn_guard::parser] Parsed assignment's captures are: Captures(
    {
        0: Some(
            "let encryption_flag = true",
        ),
        "var_name": Some(
            "encryption_flag",
        ),
        "operator": Some(
            "=",
        ),
        "var_value": Some(
            "true",
        ),
    },
)
2020-06-27 13:18:00,122 TRACE [cfn_guard::parser] Inserting key: [encryption_flag], value: [true] into variables

以及规则

2020-06-27 13:18:00,122 DEBUG [cfn_guard::parser] Parsing 'AWS::EC2::Volume Encrypted == %encryption_flag'
2020-06-27 13:18:00,134 DEBUG [cfn_guard::parser] line_type is Rule
2020-06-27 13:18:00,135 DEBUG [cfn_guard::parser] Line is an 'AND' rule
2020-06-27 13:18:00,135 TRACE [cfn_guard::parser] Entered destructure_rule
2020-06-27 13:18:00,154 TRACE [cfn_guard::parser] Parsed rule's captures are: Captures(
    {
        0: Some(
            "AWS::EC2::Volume Encrypted == %encryption_flag",
        ),
        "resource_type": Some(
            "AWS::EC2::Volume",
        ),
        "resource_property": Some(
            "Encrypted",
        ),
        "operator": Some(
            "==",
        ),
        "rule_value": Some(
            "%encryption_flag",
        ),
    },
)
2020-06-27 13:18:00,155 TRACE [cfn_guard::parser] Destructured rules are: [
    Rule {
        resource_type: "AWS::EC2::Volume",
        field: "Encrypted",
        operation: Require,
        value: "%encryption_flag",
        rule_vtype: Variable,
        custom_msg: None,
    },
]
2020-06-27 13:18:00,155 DEBUG [cfn_guard::parser] Parsed rule is: CompoundRule {
    compound_type: AND,
    rule_list: [
        Rule {
            resource_type: "AWS::EC2::Volume",
            field: "Encrypted",
            operation: Require,
            value: "%encryption_flag",
            rule_vtype: Variable,
            custom_msg: None,
        },
    ],
}

每当你的规则没有按预期表现时,这是一种查看原因的好方法。

故障排除FAQ

问题:我一直在尝试用错误的规则值强制失败,但没有得到任何结果

答案:这几乎总是由于你在规则中尝试检查的属性名称中存在拼写错误。开启--strict-checks,如果名称不匹配,你会得到一个错误。这是一个查找拼写错误的简单方法。

构建和运行

安装Rust

请参阅顶级README中的说明

运行工具

打开你喜欢的任何shell(例如,在Mac/Linux上bash或在Windows上cmd.exe)并将cd切换到源文件下载的目录。

使用Cargo

Cargo允许你直接在git目录中运行,但它的速度不如编译后的build-release快。

cargo run -- -t <CloudFormation Template> -r <Rules File>

(注意:中间的--是必要的,以区分标志是传递给Cargo还是程序)

构建二进制文件

注意:默认情况下,rust会将二进制文件编译为你在构建时运行的平台的二进制文件。如果你需要,你可以在rust中交叉编译

Mac/Linux

运行

make

将编译的发布二进制文件放入编译它的目录下的bin/目录中。

Windows

  1. 运行cargo build --release
  2. 使用target\release\cfn-guard.exe运行二进制文件

日志记录

如果您想查看cfn-guard在运行时应用的逻辑,您可以使用多个日志级别。

要增加详细程度,只需将详细程度标志(例如,-v、-vv、-vvv)中的 v 字符添加更多即可。

注意:相同的日志级别可以通过目标二进制文件或使用 cargo run 来访问。

测试

如果您修改了源代码并希望运行单元测试,只需执行以下操作:

cargo test

如果您希望使用示例 CloudFormation 模板和规则集,请参阅 Examples 目录。

依赖项

~6.5–9.5MB
~159K SLoC