aws-cloudformation / aws-cloudformation/cloudformation-guard

[BUG]

Open
#567 11 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
1.4k
Forks
196
Avg merge
3d 6h
Merged PRs (30d)
5

Description

Describe the bug
A clear and concise description of what the bug is.

The rule I wrote checking for S3 permissions on wildcard Resource is running and failing on IAM roles without any S3 permissions.

To Reproduce
Please supply:

Example rules and template that results in the error
Template:
```
rImmutaRdsLambdaRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: immunment
PermissionsBoundary: !Sub "arn:aws:iam::${AWS::AccountId}:policy/L-Boundary"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service: "rds.amazonaws.com"
Action: "sts:AssumeRole"
Policies:
- PolicyName: "RdsInvokeLambdaPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "lambda:InvokeFunction"
Resource: !GetAtt rIImmuta.Arn
```

CloudFormation Guard Rule:
### _**I KNOW THIS SEEMS TOTALLY UNRELATED TO THE CODE ABOVE BUT THIS IS THE CHECK THAT KEEPS FAILING**_

```
# R5.0 Automatically inspect the code for * in S3 folder (prefix) access and present a warning statement to the developer if found

let aws_iam_policies_no_full_access_for_s3 = Resources.*[
Type in [/AWS::IAM::Policy/, /AWS::IAM::ManagedPolicy/]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_POLICY_NO_FULL_ACCESS_FOR_S3"
]

let aws_iam_roles_no_full_access_for_s3 = Resources.*[
Type in [/AWS::IAM::Role/]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_ROLE_NO_FULL_ACCESS_FOR_S3"
]

# Checks there is no wildcard in the bucket name in an IAM Role

rule IAM_ROLE_FULL_BUCKET_NAME_USED when %aws_iam_roles_no_full_access_for_s3 !empty {
let violationsString = Resources.*[
Type in [/AWS::IAM::Role/]
some Properties.Policies[*].PolicyDocument.Statement[*] {
some Resource[*] in [/^arn:aws:s3:::(.*?)(.*?)(\*)(.*?)\/$/]
}
]
let violationsSub = Resources.*[
Type in [/AWS::IAM::Role/]
some Properties.Policies[*].PolicyDocument.Statement[*] {
some Resource[*][keys == "Fn::Sub"] in [/^arn:aws:s3:::(.*?)(.*?)(\*)(.*?)\/$/]
}
]
%violationsString empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
%violationsSub empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
}

# Checks the full folder path is used with no wildcards before the second "/" in an IAM Role

rule IAM_ROLE_FULL_FOLDER_PATH_USED when %aws_iam_roles_no_full_access_for_s3 !empty {
let violationsString = Resources.*[
Type in [/AWS::IAM::Role/]
some Properties.Policies[*].PolicyDocument.Statement[*] {
some Resource[*] in [/^arn:aws:s3:::llp(.*?)(\*)(.*?)\/(.*?)\/(.*?)/, /^arn:aws:s3:::llp(.*?)\/(.*?)(\*)(.*?)\/(.*)/]
}
]
let violationsSub = Resources.*[
Type in [/AWS::IAM::Role/]
some Properties.Policies[*].PolicyDocument.Statement[*] {
some Resource[*][keys == "Fn::Sub"] in [/^arn:aws:s3:::llp(.*?)(\*)(.*?)\/(.*?)\/(.*?)/, /^arn:aws:s3:::llp(.*?)\/(.*?)(\*)(.*?)\/(.*)/]
}
]
%violationsString empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
%violationsSub empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
}

# Checks there is no wildcard in the bucket name in an IAM Policy

rule IAM_POLICY_FULL_BUCKET_NAME_USED when %aws_iam_policies_no_full_access_for_s3 !empty {
let violationsString = Resources.*[
Type in [/AWS::IAM::Policy/, /AWS::IAM::ManagedPolicy/]
some Properties.PolicyDocument.Statement[*] {
some Resource[*] in [/^arn:aws:s3:::(.*?)(.*?)(\*)(.*?)\/$/]
}
]
let violationsSub = Resources.*[
Type in [/AWS::IAM::Policy/, /AWS::IAM::ManagedPolicy/]
some Properties.PolicyDocument.Statement[*] {
some Resource[*][keys == "Fn::Sub"] in [/^arn:aws:s3:::(.*?)(.*?)(\*)(.*?)\/$/]
}
]
%violationsString empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
%violationsSub empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
}

# Checks the full folder path is used with no wildcards before the second "/" in an IAM Policy

rule IAM_POLICY_FULL_FOLDER_PATH_USED when %aws_iam_policies_no_full_access_for_s3 !empty {
let violationsString = Resources.*[
Type in [/AWS::IAM::Policy/, /AWS::IAM::ManagedPolicy/]
some Properties.PolicyDocument.Statement[*] {
some Resource[*] in [/^arn:aws:s3:::llp(.*?)(\*)(.*?)\/(.*?)\/(.*?)/, /^arn:aws:s3:::llp(.*?)\/(.*?)(\*)(.*?)\/(.*)/]
}
]
let violationsSub = Resources.*[
Type in [/AWS::IAM::Policy/, /AWS::IAM::ManagedPolicy/]
some Properties.PolicyDocument.Statement[*] {
some Resource[*][keys == "Fn::Sub"] in [/^arn:aws:s3:::llp(.*?)(\*)(.*?)\/(.*?)\/(.*?)/, /^arn:aws:s3:::llp(.*?)\/(.*?)(\*)(.*?)\/(.*)/]
}
]
%violationsString empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
%violationsSub empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
}

let s3_no_full_permission = Resources.*[ Type == 'AWS::S3::BucketPolicy'
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "S3_NO_FULL_PERMISSION"
]

# Checks there is no wildcard in the bucket name in an IAM Policy

rule BUCKET_POLICY_FULL_BUCKET_NAME_USED when %s3_no_full_permission !empty {
let violationsString = Resources.*[
Type == 'AWS::S3::BucketPolicy'
some Properties.PolicyDocument.Statement[*] {
some Resource[*] in [/^arn:aws:s3:::(.*?)(.*?)(\*)(.*?)\/$/]
}
]
let violationsSub = Resources.*[
Type == 'AWS::S3::BucketPolicy'
some Properties.PolicyDocument.Statement[*] {
some Resource[*][keys == "Fn::Sub"] in [/^arn:aws:s3:::(.*?)(.*?)(\*)(.*?)\/$/]
}
]
%violationsString empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
%violationsSub empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
}

# Checks the full folder path is used with no wildcards before the second "/" in an IAM Policy

rule BUCKET_POLICY_FULL_FOLDER_PATH_USED when %s3_no_full_permission !empty {
let violationsString = Resources.*[
Type == 'AWS::S3::BucketPolicy'
some Properties.PolicyDocument.Statement[*] {
some Resource[*] in [/^arn:aws:s3:::llp(.*?)(\*)(.*?)\/(.*?)\/(.*?)/, /^arn:aws:s3:::llp(.*?)\/(.*?)(\*)(.*?)\/(.*)/]
}
]
let violationsSub = Resources.*[
Type == 'AWS::S3::BucketPolicy'
some Properties.PolicyDocument.Statement[*] {
some Resource[*][keys == "Fn::Sub"] in [/^arn:aws:s3:::llp(.*?)(\*)(.*?)\/(.*?)\/(.*?)/, /^arn:aws:s3:::llp(.*?)\/(.*?)(\*)(.*?)\/(.*)/]
}
]
%violationsString empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
%violationsSub empty
<<
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
>>
}

The commands you used to invoke the tool
OUTPUT=RUST_BACKTRACE=1 ./cfn-guard-v3-ubuntu-latest/cfn-guard validate --show-summary pass,fail --data "$TEMPLATE_FILE" --rules .github/folderlib/cfn-guard/rules/ 2>&1

The output of a -v log level if it's not related to cfn-guard-lambda, or the relevant CloudWatch log messages if it is related to the cfn-guard-lambda
s3_no_full_access.guard/IAM_ROLE_NO_FULL_ACCESS_FOR_S3 FAIL
---
Evaluating data template.yml against rules s3_no_full_access.guard
Number of non-compliant resources 1
Resource = rImmutaRdsLambdaRole {
Type = AWS::IAM::Role
Rule = IAM_ROLE_NO_FULL_ACCESS_FOR_S3 {
ALL {
Check = %violationsSub EMPTY {
ComparisonError {
Message {
Violation: * in S3 folder (prefix) access.
Fix: Avoid wildcard matching * in S3 folder (prefix) access
}
Error = Check was not compliant as property [/Resources/rImmutaRdsLambdaRole[L:1549,C:4]] was not empty.
PropertyPath = /Resources/rImmutaRdsLambdaRole[L:1549,C:4]
Operator = EMPTY
Code:
1547. Principal: secretsmanager.amazonaws.com
1548.
1549. rImmutaRdsLambdaRole:
1550. Type: "AWS::IAM::Role"
1551. Properties:
1552. RoleName: !Sub immuta-rds-invoke-lambda-role-

}
}
}
}
}
```
Expected behavior
A clear and concise description of what you expected to happen.

The test should skip

Operating System:
[eg, MacOS, Windows, Ubuntu, etc]

Linux

OS Version
[eg Catalina, 10, 18.04, etc]

Ubuntu latest

Contributor guide

Open the contributing guide

Research direction

Start with the rules under .github/folderlib/cfn-guard/rules/ and reproduce the report using the shown cfn-guard validate command against the supplied template. Trace why IAM_ROLE_NO_FULL_ACCESS_FOR_S3 evaluates the role's violationsSub check when it has no S3 permissions. Done means the validation skips that role and no longer reports the S3 wildcard violation.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, rust
Domain
cloud, security, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.