AWS CloudFormation Guard is an open-source general-purpose policy-as-code evaluation tool. It provides developers with a simple-to-use, yet powerful and expressive domain-specific language (DSL) to define policies and enables developers to validate JSON- or YAML- formatted structured data with those policies.
As an example of how to use AWS CloudFormation Guard (cfn-guard), given a CloudFormation template (template.json):
json
{
"Resources": {
"NewVolume": {
"Type": "AWS::EC2::Volume",
"Properties": {
"Size": 500,
"Encrypted": false,
"AvailabilityZone": "us-west-2b"
}
},
"NewVolume2": {
"Type": "AWS::EC2::Volume",
"Properties": {
"Size": 100,
"Encrypted": false,
"AvailabilityZone": "us-west-2c"
}
}
},
"Parameters": {
"InstanceName": "NewInstance"
}
}
And a rules file (rules.guard):
```
let awsec2volume_resources = Resources.*[ Type == 'AWS::EC2::Volume' ]
rule awstemplateparameters { Parameters.InstanceName == "TestInstance" }
rule awsec2volume when %awsec2volumeresources !empty { %awsec2volumeresources.Properties.Encrypted == true %awsec2volumeresources.Properties.Size IN [50, 500] %awsec2volumeresources.Properties.AvailabilityZone IN ["us-west-2c", "us-west-2b"] } ```
You can check the compliance of template.json with rules.guard:
bash
$ ./cfn-guard validate --data template.json --rules rules.guard
_Summary Report_ Overall File Status = FAIL
PASS/SKIP rules
FAILED rules
aws_template_parameters FAIL
aws_ec2_volume FAIL
We designed cfn-guard
to be plugged into your build processes.
If CloudFormation Guard validates the templates successfully, it gives you an exit status ($?
in bash) of 0
. If CloudFormation Guard identifies a rule violation, it gives you a status report of the rules that failed.
Use the verbose flag -v
to see the detailed evaluation tree that shows how CloudFormation Guard evaluated each rule.
cfn-guard
has five modes of operation:
validate
(like the example above) validates data against rules.
````bash
Usage: cfn-guard validate [OPTIONS] <--rules [
Options:
-r, --rules [rules-dir1
above, scanning is only supported for files with following extensions: .guard, .ruleset
-d, --data [...]
Provide a data file or directory of data files in JSON or YAML. Supports passing multiple values by using this option repeatedly.
Example:
--data template1.yaml --data ./data-dir1 --data template2.yaml
For directory arguments such as data-dir1
above, scanning is only supported for files with following extensions: .yaml, .yml, .json, .jsn, .template
-i, --input-parameters [data
. Due to this, every file is expected to contain mutually exclusive properties, without any overlap. Supports passing multiple values by using this option repeatedly.
Example:
--input-parameters param1.yaml --input-parameters ./param-dir1 --input-parameters param2.yaml
For directory arguments such as param-dir1
above, scanning is only supported for files with following extensions: .yaml, .yml, .json, .jsn, .template
-t, --type
rulegen
takes a JSON- or YAML-formatted CloudFormation template file and autogenerates a set of cfn-guard
rules that match the properties of its resources. This is a useful way to get started with rule-writing or just create ready-to-use rules from known-good templates.
```bash cfn-guard-rulegen Autogenerate rules from an existing JSON- or YAML- formatted data. (Currently works with only CloudFormation templates)
USAGE: cfn-guard rulegen [OPTIONS] --template
FLAGS: -h, --help Prints help information -V, --version Prints version information
OPTIONS: -o, --output
For example, using the same template (template.json) from the above example:
bash
$ cfn-guard rulegen --data template.json
let aws_ec2_volume_resources = Resources.*[ Type == 'AWS::EC2::Volume' ]
rule aws_ec2_volume when %aws_ec2_volume_resources !empty {
%aws_ec2_volume_resources.Properties.Size IN [500, 100]
%aws_ec2_volume_resources.Properties.AvailabilityZone IN ["us-west-2b", "us-west-2c"]
%aws_ec2_volume_resources.Properties.Encrypted == false
}
Given the potential for hundreds or even thousands of rules to emerge, we recommend using the --output
flag to write the generated rules to a file:
cfn-guard rulegen --data template.json --output rules.guard
parse-tree
command generates a parse tree for the rules defined in a rules file. Use the --output
flag to write the generated tree to a file.
```bash cfn-guard-parse-tree Prints out the parse tree for the rules defined in the file.
Usage: cfn-guard parse-tree [OPTIONS]
Options:
-r, --rules
Use the test
command to write unit tests in JSON or YAML format for your rules
```bash cfn-guard-test Built in unit testing capability to validate a Guard rules file against unit tests specified in YAML format to determine each individual rule's success or failure testing.
Usage: cfn-guard test [OPTIONS]
Options:
-r, --rules-file
For example, given a rules file (rules.guard) as:
bash
rule assert_all_resources_have_non_empty_tags {
when Resources.* !empty {
Resources.*.Properties.Tags !empty
}
}
You can write a YAML-formatted unit test file (test.yml) as:
You can then test your rules file using the test
command as:
bash
$ cfn-guard test -r rules.guard -t test.yml
PASS Expected Rule = assert_all_resources_have_non_empty_tags, Status = SKIP, Got Status = SKIP
PASS Expected Rule = assert_all_resources_have_non_empty_tags, Status = FAIL, Got Status = FAIL
To setup Autocompletions you will need to follow instructions for the specific shell your are running.
Currently guard only supports autocompletions for zsh, bash, and fish shells. If you would like autocompletions for a specific shell feel free to open up a new github issue.
Autocompletions are only something available for version >= 3.0
sh
cfn-guard completions --shell='zsh' > /usr/local/share/zsh/site-functions/_cfn-guard && compinit
bash
cfn-guard completions --shell='bash' > ~/cfn-guard.bash && source ~/cfn-guard.bash
sh
cfn-guard completions --shell='fish' > ~/cfn-guard.fish
cd ~
./ ./cfn-guard.fish
NOTE: for both bash and fish shells you are able to output the completions script to any file in any location you would like, just make sure the file you output it to and the file you source are the same. For bash shells if you dont want to do this everytime you open up a new terminal, once you have the script you can add source ~/cfn-guard.bash to your .bashrc