aws-guard-rules-registry
aws-guard-rules-registry copied to clipboard
(IAM): IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS Suppression Ignored with Multiple Managed Policies
What is the problem?
I'm using iam_policy_no_statements_with_full_access.guard to validate my CloudFormation template. I'm trying to suppress the rule for one of my managed policies, but it seems to get ignored and still fails the test.
Reproduction Steps
The following is a reproducible snippet of my CloudFormation template (named repro.yaml):
AWSTemplateFormatVersion: "2010-09-09"
Resources:
GitHubRemainingPolicy:
Type: AWS::IAM::ManagedPolicy
Metadata:
guard:
SuppressedRules:
- IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: AWSCloudFormationFullAccess
Effect: Allow
Action:
- "cloudformation:*"
Resource: "*"
- Sid: AmazonSNSFullAccess
Effect: Allow
Action:
- "sns:*"
Resource: "*"
- Sid: AmazonS3FullAccess
Effect: Allow
Action:
- "s3:*"
- "s3-object-lambda:*"
Resource: "*"
- Sid: AmazonAPIGatewayAdministrator
Effect: Allow
Action:
- "apigateway:*"
Resource: "arn:aws:apigateway:*::/*"
CodeBuildPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: CodeBuildAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: CloudWatchLogsPolicy
Effect: Allow
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Resource: "*"
- Sid: S3ObjectPolicy
Effect: Allow
Action:
- "s3:DeleteObject"
- "s3:GetObject"
- "s3:ListBucket"
- "s3:PutObject"
Resource:
- !GetAtt ReactAppBucket.Arn
- !Sub "${ReactAppBucket.Arn}/*"
I ran cfn-guard validate --show-summary fail --output-format single-line-summary --data repro.yaml --rules iam_policy_no_statements_with_full_access.guard
to validate this template.
What did you expect to happen?
Since I added the Metadata block to suppress IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS
, the cfn-guard validate
command shouldn't show any failures.
What actually happened?
The validate command failed with the following output:
repro.yaml Status = FAIL
FAILED rules
iam_policy_no_statements_with_full_access.guard/IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS FAIL
---
Evaluating data repro.yaml against rules iam_policy_no_statements_with_full_access.guard
Number of non-compliant resources 1
Resource = GitHubRemainingPolicy {
Type = AWS::IAM::ManagedPolicy
Rule = IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS {
ALL {
Check = %violations EMPTY {
ComparisonError {
Message {
Violation: One or more IAM Managed Policies allow full access to at least 1 AWS service
Fix: Remove policy statements that match {"Effect": "Allow", "Action": "<service-name>:*" ... } or {"Effect": "Allow", "Action": "*" ... }
}
Error = Check was not compliant as property [/Resources/GitHubRemainingPolicy[L:3,C:4]] was not empty.
PropertyPath = /Resources/GitHubRemainingPolicy[L:3,C:4]
Operator = EMPTY
Code:
1.AWSTemplateFormatVersion: "2010-09-09"
2.Resources:
3. GitHubRemainingPolicy:
4. Type: AWS::IAM::ManagedPolicy
5. Metadata:
6. guard:
}
}
}
}
}
CloudFormation Guard Version
cfn-guard 3.0.0
OS
Ubuntu (running Windows Subsystem for Linux on Windows 11)
OS Version
Ubuntu 20.04.6 LTS
Other information
After debugging for hours, I realized the issue may be due to the guard rule when multiple managed policies are defined in the CloudFormation template. Looking at iam_policy_no_statements_with_full_access.guard
:
let aws_iam_managed_policies_no_statements_with_full_access = Resources.*[ Type == 'AWS::IAM::ManagedPolicy'
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS"
]
rule IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS when %aws_iam_managed_policies_no_statements_with_full_access !empty {
let violations = Resources.*[
Type == 'AWS::IAM::ManagedPolicy'
some Properties.PolicyDocument.Statement[*] {
some Action[*] in ["*", /^[a-zA-Z0-9]*:\*$/]
Effect == "Allow"
some Resource in ["*"]
}
]
%violations empty
<<
Violation: One or more IAM Managed Policies allow full access to at least 1 AWS service
Fix: Remove policy statements that match {"Effect": "Allow", "Action": "<service-name>:*" ... } or {"Effect": "Allow", "Action": "*" ... }
>>
}
From my understanding:
-
aws_iam_managed_policies_no_statements_with_full_access
is looking at all the managed policies without any suppression metadata. This will get theCodeBuildPolicy
since it's a managed policy and no rules are suppressed there. - The
IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS
rule will kick in sinceaws_iam_managed_policies_no_statements_with_full_access
is not empty, based on step 1. -
violations
will check the Action, Effect, and Resource values in all the managed policy documents. - Since
GitHubRemainingPolicy
contains policies allowing all actions for all resources (such as "cloudformation:*"),violations
is non-empty, causing the rule to fail.
I think the bug is due to step 3. Even though the rule was originally executed for CodeBuildPolicy
, it's checking GitHubRemainingPolicy
as well, effectively ignoring the suppression earlier. I've noticed most of the other guard rules, such as IAM_NO_INLINE_POLICY_CHECK, reference the let variable inside the rule block:
let aws_iam_entities_no_inline_policy = Resources.*[
Type in [ /AWS::IAM::User/,
/AWS::IAM::Role/,
/AWS::IAM::Group/ ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_NO_INLINE_POLICY_CHECK"
]
rule IAM_NO_INLINE_POLICY_CHECK when %aws_iam_entities_no_inline_policy !empty {
%aws_iam_entities_no_inline_policy.Properties.Policies empty
<<
Violation: Inline policies are not allowed on IAM Users, Roles, or Groups.
Fix: Remove the Policies list property from any IAM Users, Roles, or Groups.
>>
}
which only applies the check to all the resources that satisfy the filters defined in the let variable.
Workaround: If I remove CodeBuildPolicy
or add the suppression metadata in that policy as well, the cfn-guard validate
command succeeds, because aws_iam_managed_policies_no_statements_with_full_access
is now empty, causing the rule to be skipped. However, I would have to apply this fix to any other managed policies I add to the CloudFormation template, so it's not an ideal solution.
I've also noticed that IAM_POLICY_NO_STATEMENTS_WITH_ADMIN_ACCESS and RESTRICTED_INCOMING_TRAFFIC follow a similar violations
pattern without referencing the let variable, so this bug might extend to those rules as well.