v3.0.0-alpha
Pre-release
Pre-release
akshayrane
released this
23 Mar 18:26
·
20 commits
to rogue_one
since this release
New Features
- Added support for advanced regular expressions
- Improved handling for intrinsic functions in test command
- Added
--structured
flag to validate command to emit JSON/YAML parseable output
What's Changed
- Added OS-specific cargo targets to release workflow by @akshayrane in #310
- [Code Quality]: Rust-fmt action + formatting project by @joshfried-aws in #315
- [Code Quality]: Implementing custom writer, bug fixes, new integration test framework, and adding initial tests for all commands by @joshfried-aws in #325
- Bump tokio from 1.21.2 to 1.24.2 by @dependabot in #327
- +[fancy-regex] Added support for advanced regular expressions by @akshayrane in #326
- improved safety of serde_yaml::Value -> value conversion by @joshfried-aws in #328
- Improve handling of function references for test command by @joshfried-aws in #331
- PR to add Thiserror to cfn-guard by @joshfried-aws in #329
- Redirected verbose output from stdout to custom writer and added unit… by @akshayrane in #332
- Addit cargo-audit to CI + bump up clap to 3.0 by @joshfried-aws in #330
- Implemented custom reader, increasing test coverage for validate command. by @joshfried-aws in #334
- Update CONTRIBUTING.md by @swiercek in #335
- Clap4 by @joshfried-aws in #336
- Added integration tests against aws-guard-rules-registry on Ubuntu by @akshayrane in #337
- Update check-tags-present.guard by @Aishwarya4400 in #313
- Adding structured evaluator by @joshfried-aws in #339
- Added deprecated short flag for print-json in parse-tree by @akshayrane in #345
- bumping up to 3.0.0-alpha by @joshfried-aws in #347
New Contributors
- @swiercek made their first contribution in #335
- @Aishwarya4400 made their first contribution in #313
Full Changelog: 2.1.3...3.0.0-alpha
Details
1. Added support for advanced regular expressions
Supports usage of advanced regular expressions such as lookaround and backreferences.
Rules file (advanced_regex_negative_lookbehind_rule.guard)
NotAwsAccessKey != /(?<![A-Z0-9])[A-Z0-9]{20}(?![A-Z0-9])/
NotSecretAccessKey != /(?<![A-Za-z0-9\\/+=])[A-Za-z0-9\\/+=]{40}(?![A-Za-z0-9\\/+=])/
Data file (advanced_regex_negative_lookbehind_non_compliant.yaml) (click to expand)
NotAwsAccessKey: AKIAIOSFODNN7EXAMPLE
NotSecretAccessKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Command (click to expand)
cfn-guard validate \
-d guard/resources/validate/data-dir/advanced_regex_negative_lookbehind_non_compliant.yaml \
-r guard/resources/validate/rules-dir/advanced_regex_negative_lookbehind_rule.guard \
--show-summary all
Output with non-compliant template (click to expand)
advanced_regex_negative_lookbehind_non_compliant.yaml Status = FAIL
FAILED rules
advanced_regex_negative_lookbehind_rule.guard/default FAIL
---
Evaluation of rules advanced_regex_negative_lookbehind_rule.guard against data advanced_regex_negative_lookbehind_non_compliant.yaml
--
Property [/NotAwsAccessKey] in data [advanced_regex_negative_lookbehind_non_compliant.yaml] is not compliant with [advanced_regex_negative_lookbehind_rule.guard/default] because provided value ["AKIAIOSFODNN7EXAMPLE"] did match expected value ["/(?<![A-Z0-9])[A-Z0-9]{20}(?![A-Z0-9])/"]. Error Message []
Property [/NotSecretAccessKey] in data [advanced_regex_negative_lookbehind_non_compliant.yaml] is not compliant with [advanced_regex_negative_lookbehind_rule.guard/default] because provided value ["wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"] did match expected value ["/(?<![A-Za-z0-9\\/+=])[A-Za-z0-9\\/+=]{40}(?![A-Za-z0-9\\/+=])/"]. Error Message []
2. Improved handling for intrinsic functions in test command
With the test command, the intrinsic functions now get resolved to their equivalent JSON syntax.
Unit test file (intrinsic_fn_tests.yaml) (click to expand)
- name: a redshift cluster with short hand functions
input:
Resources:
myCluster:
Type: "AWS::Redshift::Cluster"
Properties:
DBName: "mydb"
KmsKeyId:
Fn::ImportValue:
!Sub "${pSecretKmsKey}"
expectations:
rules:
REDSHIFT_ENCRYPTED_CMK: PASS
Rule file (intrinsic_fn_rule.guard)
let redshift_clusters = Resources.*[ Type == 'AWS::Redshift::Cluster']
rule REDSHIFT_ENCRYPTED_CMK when %redshift_clusters !empty {
%redshift_clusters.Properties.KmsKeyId exists
%redshift_clusters.Properties.KmsKeyId == {"Fn::ImportValue": {"Fn::Sub":"${pSecretKmsKey}"}}
}
Command (click to expand)
cfn-guard test \
-t intrinsic_fn_tests.yaml \
-r intrinsic_fn_rule.guard
Output (click to expand)
Test Case #1
Name: a redshift cluster with short hand functions
PASS Rules:
REDSHIFT_ENCRYPTED_CMK: Expected = PASS
3. Added --structured
flag to validate command to emit JSON/YAML parseable output
Emits an output that could be directly parsed using native JSON and YAML parsers, in case of multiple files or directories passed as input with the new flag.
Command
cfn-guard validate \
-d guard/resources/validate/data-dir/s3-public-read-prohibited-template-non-compliant.yaml \
-d guard/resources/validate/data-dir/s3-public-read-prohibited-template-compliant.yaml \
-r guard/resources/validate/rules-dir/s3_bucket_public_read_prohibited.guard \
--structured -o json --show-summary none
Output (click to expand)
[
{
"name": "",
"metadata": {},
"status": "FAIL",
"not_compliant": [
{
"Rule": {
"name": "S3_BUCKET_PUBLIC_READ_PROHIBITED",
"metadata": {},
"messages": {
"custom_message": null,
"error_message": null
},
"checks": [
{
"Clause": {
"Unary": {
"context": " %s3_bucket_public_read_prohibited[*].Properties.PublicAccessBlockConfiguration EXISTS ",
"messages": {
"custom_message": "",
"error_message": "Check was not compliant as property [PublicAccessBlockConfiguration] is missing. Value traversed to [Path=/Resources/MyBucket/Properties[L:13,C:6] Value={\"BucketEncryption\":{\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]},\"VersioningConfiguration\":{\"Status\":\"Enabled\"}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyBucket/Properties",
"value": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
},
"VersioningConfiguration": {
"Status": "Enabled"
}
}
},
"remaining_query": "PublicAccessBlockConfiguration",
"reason": "Could not find key PublicAccessBlockConfiguration inside struct at path /Resources/MyBucket/Properties[L:13,C:6]"
},
"comparison": [
"Exists",
false
]
}
}
}
}
},
{
"Clause": {
"Binary": {
"context": " %s3_bucket_public_read_prohibited[*].Properties.PublicAccessBlockConfiguration.BlockPublicAcls EQUALS true",
"messages": {
"custom_message": "",
"error_message": "Check was not compliant as property [PublicAccessBlockConfiguration.BlockPublicAcls] to compare from is missing. Value traversed to [Path=/Resources/MyBucket/Properties[L:13,C:6] Value={\"BucketEncryption\":{\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]},\"VersioningConfiguration\":{\"Status\":\"Enabled\"}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyBucket/Properties",
"value": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
},
"VersioningConfiguration": {
"Status": "Enabled"
}
}
},
"remaining_query": "PublicAccessBlockConfiguration.BlockPublicAcls",
"reason": "Could not find key PublicAccessBlockConfiguration inside struct at path /Resources/MyBucket/Properties[L:13,C:6]"
},
"comparison": [
"Eq",
false
]
}
}
}
}
},
{
"Clause": {
"Binary": {
"context": " %s3_bucket_public_read_prohibited[*].Properties.PublicAccessBlockConfiguration.BlockPublicPolicy EQUALS true",
"messages": {
"custom_message": "",
"error_message": "Check was not compliant as property [PublicAccessBlockConfiguration.BlockPublicPolicy] to compare from is missing. Value traversed to [Path=/Resources/MyBucket/Properties[L:13,C:6] Value={\"BucketEncryption\":{\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]},\"VersioningConfiguration\":{\"Status\":\"Enabled\"}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyBucket/Properties",
"value": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
},
"VersioningConfiguration": {
"Status": "Enabled"
}
}
},
"remaining_query": "PublicAccessBlockConfiguration.BlockPublicPolicy",
"reason": "Could not find key PublicAccessBlockConfiguration inside struct at path /Resources/MyBucket/Properties[L:13,C:6]"
},
"comparison": [
"Eq",
false
]
}
}
}
}
},
{
"Clause": {
"Binary": {
"context": " %s3_bucket_public_read_prohibited[*].Properties.PublicAccessBlockConfiguration.IgnorePublicAcls EQUALS true",
"messages": {
"custom_message": "",
"error_message": "Check was not compliant as property [PublicAccessBlockConfiguration.IgnorePublicAcls] to compare from is missing. Value traversed to [Path=/Resources/MyBucket/Properties[L:13,C:6] Value={\"BucketEncryption\":{\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]},\"VersioningConfiguration\":{\"Status\":\"Enabled\"}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyBucket/Properties",
"value": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
},
"VersioningConfiguration": {
"Status": "Enabled"
}
}
},
"remaining_query": "PublicAccessBlockConfiguration.IgnorePublicAcls",
"reason": "Could not find key PublicAccessBlockConfiguration inside struct at path /Resources/MyBucket/Properties[L:13,C:6]"
},
"comparison": [
"Eq",
false
]
}
}
}
}
},
{
"Clause": {
"Binary": {
"context": " %s3_bucket_public_read_prohibited[*].Properties.PublicAccessBlockConfiguration.RestrictPublicBuckets EQUALS true",
"messages": {
"custom_message": "; Violation: S3 Bucket Public Write Access controls need to be restricted.; Fix: Set S3 Bucket PublicAccessBlockConfiguration properties for BlockPublicAcls, BlockPublicPolicy, IgnorePublicAcls, RestrictPublicBuckets parameters to true.; ",
"error_message": "Check was not compliant as property [PublicAccessBlockConfiguration.RestrictPublicBuckets] to compare from is missing. Value traversed to [Path=/Resources/MyBucket/Properties[L:13,C:6] Value={\"BucketEncryption\":{\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]},\"VersioningConfiguration\":{\"Status\":\"Enabled\"}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyBucket/Properties",
"value": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
},
"VersioningConfiguration": {
"Status": "Enabled"
}
}
},
"remaining_query": "PublicAccessBlockConfiguration.RestrictPublicBuckets",
"reason": "Could not find key PublicAccessBlockConfiguration inside struct at path /Resources/MyBucket/Properties[L:13,C:6]"
},
"comparison": [
"Eq",
false
]
}
}
}
}
}
]
}
}
],
"not_applicable": [],
"compliant": []
},
{
"name": "",
"metadata": {},
"status": "PASS",
"not_compliant": [],
"not_applicable": [],
"compliant": [
"S3_BUCKET_PUBLIC_READ_PROHIBITED"
]
}
]