[BUG] S3 check failing on unrelated IAM Role
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:
# 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
-vlog 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
Hi @Aaron-Garrett it seems like the rule you are referring to isn't included here. Can you please update your example so we can either look further into this, or help you debug?
Thanks,
Hi, since we are unable to assist you given the information provided, I am going to close this issue out. Feel free to reopen it and provide us with what was asked above.
Sorry, been busy. The rule is there. That is the problem. It seems totally unrelated. All of those IAM s3 policy rules are the ones that are erroring out.
Sorry, been busy. The rule is there. That is the problem. It seems totally unrelated. All of those IAM s3 policy rules are the ones that are erroring out.
Hi @Aaron-Garrett, I think there's some confusion here. The output you provided here
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-
}
}
}
}
}
tells me a rule called IAM_ROLE_NO_FULL_ACCESS_FOR_S3 is the cause for the failure. The issue here is the snippet you provided of your guard rules does not define this rule anywhere. The only place it is mentioned is in this block
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"
]
but that still doesnt show me the definition, or where it's being evaluated. This leads me to believe you are possibly passing a list of rules, or a directory that contains multiple rules? This rule has to be coming from somewhere.