The cfn-nag tool looks for patterns in CloudFormation templates that may indicate insecure infrastructure. Roughly speaking it will look for:
- IAM rules that are too permissive (wildcards)
- Security group rules that are too permissive (wildcards)
- Access logs that aren't enabled
- Encryption that isn't enabled
For more background on the tool, please see:
Presuming Ruby 2.2.x is installed, installation is just a matter of:
gem install cfn-nag
To run cfn_nag
as an action in CodePipeline, you can deploy via the AWS Serverless Application Repository.
Pretty simple to execute:
cfn_nag_scan --input-path <path to cloudformation json>
The path can be a directory or a particular template. If it is a directory, all *.json, *.template, *.yml and *.yaml files underneath there recursively will be processed.
The default output format is free-form text, but json output can be selected with the --output-format json
flag.
Optionally, a --debug
flag will dump information about the internals of rule loading.
Run with --help
for a full listing of supported switches.
To see a list of all the rules the cfn-nag currently supports, there is a command-line utility that will dump them to stdout:
cfn_nag_rules
- The results are dumped to stdout
- A failing violation will return a non-zero exit code.
- A warning will return a zero/success exit code.
- A fatal violation stops analysis (per file) because the template is malformed in some severe way
In the event that there is a rule that you want to suppress, a cfn_nag
Metadata
key can be added to the affected resource to tell cfn_nag to not raise a failure or warning for that rule.
For example, if you are setting up a public-facing ELB that's open to inbound connections from the internet with resources like the following:
public_alb.yaml
# Partial template
PublicAlbSecurityGroup:
Properties:
GroupDescription: 'Security group for a public Application Load Balancer'
VpcId:
Ref: vpc
Type: AWS::EC2::SecurityGroup
PublicAlbSecurityGroupHttpIngress:
Properties:
CidrIp: 0.0.0.0/0
FromPort: 80
GroupId:
Ref: PublicAlbSecurityGroup
IpProtocol: tcp
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress
cfn_nag will raise warnings like the following:
$ cfn_nag_scan -i public_alb.yaml
------------------------------------------------------------
public_alb.yaml
------------------------------------------------------------------------------------------------------------------------
| WARN W9
|
| Resources: ["PublicAlbSecurityGroup"]
|
| Security Groups found with ingress cidr that is not /32
------------------------------------------------------------
| WARN W2
|
| Resources: ["PublicAlbSecurityGroup"]
|
| Security Groups found with cidr open to world on ingress. This should never be true on instance. Permissible on ELB
Failures count: 0
Warnings count: 2
By adding the metadata, these warnings can be suppressed:
public_alb_with_suppression.yaml
# Partial template
PublicAlbSecurityGroup:
Properties:
GroupDescription: 'Security group for a public Application Load Balancer'
VpcId:
Ref: vpc
Type: AWS::EC2::SecurityGroup
Metadata:
cfn_nag:
rules_to_suppress:
- id: W9
reason: "This is a public facing ELB and ingress from the internet should be permitted."
- id: W2
reason: "This is a public facing ELB and ingress from the internet should be permitted."
PublicAlbSecurityGroupHttpIngress:
Properties:
CidrIp: 0.0.0.0/0
FromPort: 80
GroupId:
Ref: PublicAlbSecurityGroup
IpProtocol: tcp
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress
$ cfn_nag_scan -i public_alb_with_suppression.yaml
------------------------------------------------------------
public_alb_with_supression.yaml
------------------------------------------------------------
Failures count: 0
Warnings count: 0
CloudFormation Template Parameters can present a problem for static analysis as the values are specified at the point of deployment. In other words, the values aren't available when the static analysis is done - static analysis can only look at the "code" that is in front of it. Therefore a security group ingress rule of 0.0.0.0/0 won't be flagged if the cidr is parameterized and the 0.0.0.0/0 is passed in at deploy time.
To allow for checking parameter values, a user can specify the parameter values in a JSON file passed on the command line
to both cfn_nag
and cfn_nag_scan
with the --parameter-values-path=<filename/uri>
flag.
The format of the JSON is a single key "Parameters" whose value is a dictionary with each key/value pair mapping to the Parameters like such:
{
"Parameters": {
"Cidr": "0.0.0.0/0"
}
}
will fill in "0.0.0.0/0" to the following Parameter:
Parameters:
Cidr:
Type: String
BEWARE that if there are extra parameters in the JSON they are quietly ignored (to allow cfn_nag_scan
to apply
the same JSON across all the templates)
If the JSON is malformed or doesn't meet the above specification, then parsing will fail with FATAL violation.
To author new rules for your own use and/or community contribution, see migration.md for details.