Skip to content

Commit

Permalink
Merge pull request #52 from aws-cloudformation/release-0.6.0
Browse files Browse the repository at this point in the history
Release 0.6.0
  • Loading branch information
nathanataws authored Aug 7, 2020
2 parents 18fb11e + 3a5e5b8 commit 9c6f66b
Show file tree
Hide file tree
Showing 30 changed files with 1,376 additions and 379 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ cloudformation-guard.tar.gz
*#
.idea/
*~
cmake-build-debug
cmake-build-debug
*gcno
*gcda
3 changes: 3 additions & 0 deletions Examples/conditional-ddb-template.ruleset
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-product-attribute-reference.html
AWS::DynamoDB::Table if Tags == /.*PROD.*/ then .DeletionPolicy == Retain
AWS::DynamoDB::Table if Tags == /.*PROD.*/ then .DeletionPolicy != Retain
64 changes: 64 additions & 0 deletions Examples/conditional-ddb-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"Resources": {
"DDBTable": {
"Type": "AWS::DynamoDB::Table",
"UpdateReplacePolicy": "Abort",
"DeletionPolicy": "Retain",
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "ArtistId",
"AttributeType": "S"
},
{
"AttributeName": "Concert",
"AttributeType": "S"
},
{
"AttributeName": "TicketSales",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "ArtistId",

"KeyType": "HASH"
},
{
"AttributeName": "Concert",
"KeyType": "RANGE"
}
],
"GlobalSecondaryIndexes": [
{

"IndexName": "GSI",
"KeySchema": [

{

"AttributeName": "TicketSales",
"KeyType": "HASH"
}
],
"Projection": {
"ProjectionType": "KEYS_ONLY"
},
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
},
"Tags": [
{"Key": "ENV", "Value": "PROD"}
]
}
}
}
}
64 changes: 64 additions & 0 deletions Examples/ddb-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"Resources": {
"DDBTable": {
"Type": "AWS::DynamoDB::Table",
"UpdateReplacePolicy": "Abort",
"DeletionPolicy": "Retain",
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "ArtistId",
"AttributeType": "S"
},
{
"AttributeName": "Concert",
"AttributeType": "S"
},
{
"AttributeName": "TicketSales",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "ArtistId",

"KeyType": "HASH"
},
{
"AttributeName": "Concert",
"KeyType": "RANGE"
}
],
"GlobalSecondaryIndexes": [
{

"IndexName": "GSI",
"KeySchema": [

{

"AttributeName": "TicketSales",
"KeyType": "HASH"
}
],
"Projection": {
"ProjectionType": "KEYS_ONLY"
},
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
},
"Tags": [
{"Key": "ENV", "Value": "PROD"}
]
}
}
}
}
1 change: 1 addition & 0 deletions Examples/ddb.ruleset
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AWS::DynamoDB::Table if Tags == /.*PROD.*/ then .DeletionPolicy == Retain
4 changes: 2 additions & 2 deletions Examples/ebs-volume-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
"NewVolume" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : 101,
"Size" : 500,
"Encrypted": false,
"AvailabilityZone" : "us-west-2b"
}
},
"NewVolume2" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : 99,
"Size" : 50,
"Encrypted": false,
"AvailabilityZone" : "us-west-2c"
}
Expand Down
4 changes: 1 addition & 3 deletions Examples/ebs-volume-template.ruleset
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
let encryption_flag = true
let allowed_azs = [us-east-1a,us-east-1b,us-east-1c]

AWS::EC2::Volume AvailabilityZone IN %allowed_azs
AWS::EC2::Volume Encrypted == %encryption_flag
AWS::EC2::Volume Size == 100
AWS::EC2::Volume Size <= 100
20 changes: 8 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ For example, given a CloudFormation template:
"NewVolume" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : 101,
"Size" : 500,
"Encrypted": false,
"AvailabilityZone" : "us-west-2b"
}
},
"NewVolume2" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : 99,
"Size" : 50,
"Encrypted": false,
"AvailabilityZone" : "us-west-2c"
}
Expand All @@ -40,24 +40,20 @@ And a set of rules:

```
let encryption_flag = true
let allowed_azs = [us-east-1a,us-east-1b,us-east-1c]
AWS::EC2::Volume AvailabilityZone IN %allowed_azs
AWS::EC2::Volume Encrypted == %encryption_flag
AWS::EC2::Volume Size == 100
AWS::EC2::Volume Size <= 100
```

You can check the template to ensure that it adheres to the rules.

```
$> cfn-guard -t Examples/ebs_volume_template.json -r Examples/ebs_volume_template.ruleset
"[NewVolume2] failed because [Encrypted] is [false] and the permitted value is [true]"
"[NewVolume2] failed because [Size] is [99] and the permitted value is [100]"
"[NewVolume2] failed because [us-west-2c] is not in [us-east-1a,us-east-1b,us-east-1c] for [AvailabilityZone]"
"[NewVolume] failed because [Encrypted] is [false] and the permitted value is [true]"
"[NewVolume] failed because [Size] is [101] and the permitted value is [100]"
"[NewVolume] failed because [us-west-2b] is not in [us-east-1a,us-east-1b,us-east-1c] for [AvailabilityZone]"
Number of failures: 6
[NewVolume2] failed because [Encrypted] is [false] and the permitted value is [true]
[NewVolume] failed because [Encrypted] is [false] and the permitted value is [true]
[NewVolume] failed because [Size] is [500] and the permitted value is [<= 100]
Number of failures: 3
```

### Evaluating Security Policies
Expand Down
4 changes: 2 additions & 2 deletions cfn-guard-lambda/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cfn-guard-lambda/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cfn-guard-lambda"
version = "0.5.2"
version = "0.6.0"
edition = "2018"

[dependencies]
Expand Down
6 changes: 5 additions & 1 deletion cfn-guard-lambda/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ fn my_handler(e: CustomEvent, _c: Context) -> Result<CustomOutput, HandlerError>
//dbg!(&e);
info!("Template is [{}]", &e.template);
info!("Rule Set is [{}]", &e.rule_set);
let (result, exit_code) = cfn_guard::run_check(&e.template, &e.rule_set, e.strict_checks);
let (result, exit_code) = match cfn_guard::run_check(&e.template, &e.rule_set, e.strict_checks)
{
Ok(t) => t,
Err(e) => (vec![e], 1),
};

let exit_status = match exit_code {
0 => "PASS",
Expand Down
6 changes: 3 additions & 3 deletions cfn-guard-rulegen-lambda/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cfn-guard-rulegen-lambda/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cfn-guard-rulegen-lambda"
version = "0.5.2"
version = "0.6.0"
edition = "2018"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion cfn-guard-rulegen/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cfn-guard-rulegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cfn-guard-rulegen"
version = "0.5.2"
version = "0.6.0"
edition = "2018"

[dependencies]
Expand Down
38 changes: 20 additions & 18 deletions cfn-guard-rulegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ pub fn run_gen(template_file_contents: &str) -> Vec<String> {
Err(_) => match serde_yaml::from_str(template_file_contents) {
Ok(y) => y,
Err(e) => {
let msg_string = format!("Template file format was unreadable as json or yaml: {}", e);
let msg_string =
format!("Template file format was unreadable as json or yaml: {}", e);
error!("{}", &msg_string);
return vec![msg_string]
},
return vec![msg_string];
}
},
};
trace!("CFN Template is {:#?}", &cfn_template);
Expand All @@ -41,18 +42,17 @@ pub fn run_gen(template_file_contents: &str) -> Vec<String> {
None => {
let msg_string = format!("Template lacks a Resources section");
error!("{}", &msg_string);
return vec![msg_string]
},
return vec![msg_string];
}
};
let cfn_resources: HashMap<String, Value> = match serde_json::from_value(cfn_resources_clone) {
Ok(y) => y,
Err(e) => {
let msg_string = format!("Template Resources section has an invalid structure: {}", e);
error!("{}", &msg_string);
return vec![msg_string];
}
};
let cfn_resources: HashMap<String, Value> =
match serde_json::from_value(cfn_resources_clone) {
Ok(y) => y,
Err(e) => {
let msg_string = format!("Template Resources section has an invalid structure: {}", e);
error!("{}", &msg_string);
return vec![msg_string]
},
};
trace!("CFN resources are: {:?}", cfn_resources);
gen_rules(cfn_resources)
}
Expand All @@ -65,7 +65,7 @@ fn gen_rules(cfn_resources: HashMap<String, Value>) -> Vec<String> {
let props: HashMap<String, Value> =
match serde_json::from_value(cfn_resource["Properties"].clone()) {
Ok(s) => s,
Err(_) => continue
Err(_) => continue,
};
for (prop_name, prop_val) in props {
let stripped_val = match prop_val.as_str() {
Expand All @@ -76,7 +76,8 @@ fn gen_rules(cfn_resources: HashMap<String, Value>) -> Vec<String> {
let key_name = format!("{} {}", &cfn_resource["Type"].as_str().unwrap(), prop_name);
// If the key doesn't exist, create it and set its value to a new HashSet with the rule value in it
if !rule_map.contains_key(&key_name) {
let value_set: HashSet<String> = vec![no_newline_stripped_val].into_iter().collect();
let value_set: HashSet<String> =
vec![no_newline_stripped_val].into_iter().collect();
rule_map.insert(key_name, value_set);
} else {
// If the key does exist, add the item to the HashSet
Expand All @@ -88,7 +89,9 @@ fn gen_rules(cfn_resources: HashMap<String, Value>) -> Vec<String> {
for (key, val_set) in rule_map {
let mut rule_string: String = String::from("");
let mut count = 0;
for r in val_set {
let mut sorted_val_set: Vec<String> = val_set.into_iter().collect::<Vec<String>>();
sorted_val_set.sort();
for r in sorted_val_set {
let temp_rule_string = format!("{} == {}", key, r);
if count > 0 {
rule_string = format!("{} |OR| {}", rule_string, temp_rule_string);
Expand All @@ -101,4 +104,3 @@ fn gen_rules(cfn_resources: HashMap<String, Value>) -> Vec<String> {
}
rule_set.into_iter().collect()
}

3 changes: 2 additions & 1 deletion cfn-guard-rulegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ fn main() {

info!("Generating rules from {}", &template_file);

let result = cfn_guard_rulegen::run(template_file).unwrap_or_else(|err| {
let mut result = cfn_guard_rulegen::run(template_file).unwrap_or_else(|err| {
println!("Problem generating rules: {}", err);
process::exit(1);
});

if !result.is_empty() {
result.sort();
for res in result.iter() {
println!("{}", res);
}
Expand Down
Loading

0 comments on commit 9c6f66b

Please sign in to comment.