Skip to content

Commit

Permalink
Migrate AWS IAM resources to cfn-guard ruleset (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
ysdholak authored Mar 20, 2024
1 parent 6d23585 commit 41731c0
Show file tree
Hide file tree
Showing 37 changed files with 4,808 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#
#####################################
## Gherkin ##
#####################################
# Rule Identifier:
# IAM_MANAGEDPOLICY_NO_STATEMENTS_WITH_FULL_ACCESS
#
# Description:
# Checks if AWS Identity and Access Management (IAM) managed policies grant permissions to all actions on individual AWS resources.
#
# Reports on:
# AWS::IAM::ManagedPolicy
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# F5
#
# Scenarios:
# a) SKIP: when there are no IAM Managed Policies present
# b) PASS: when all IAM Managed Policies do not allow full access to at least 1 AWS service
# c) FAIL: when any IAM Managed Policy allows full access to at least 1 AWS service.
# d) SKIP: when metada has rule suppression for IAM_MANAGEDPOLICY_NO_STATEMENTS_WITH_FULL_ACCESS or F5

#
# Select all IAM Managed Policy resources from incoming template (payload)
#
let aws_iam_managed_policies = Resources.*[ Type == 'AWS::IAM::ManagedPolicy'
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "F5"
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_MANAGEDPOLICY_NO_STATEMENTS_WITH_FULL_ACCESS"
]

rule IAM_MANAGEDPOLICY_NO_STATEMENTS_WITH_FULL_ACCESS when %aws_iam_managed_policies !empty {
let violations = %aws_iam_managed_policies[
Type == 'AWS::IAM::ManagedPolicy'
some Properties.PolicyDocument.Statement[*] {
some Action[*] in ["*", /^[a-zA-Z0-9]*:\*$/]
Effect == "Allow"
}
]
%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": "*" ... }
>>
}
2 changes: 2 additions & 0 deletions rules/aws/iam/iam_no_inline_policy_check.guard
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ let aws_iam_entities_no_inline_policy = Resources.*[
Type in [ /AWS::IAM::User/,
/AWS::IAM::Role/,
/AWS::IAM::Group/ ]
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "F10"
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_NO_INLINE_POLICY_CHECK"
]
Expand Down
53 changes: 53 additions & 0 deletions rules/aws/iam/iam_no_policy_on_user.guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#
#####################################
## AWS Solutions ##
#####################################
# Rule Identifier:
# IAM_NO_POLICY_ON_USER
#
# Description:
# Checks that IAM Policies are not attached to IAM Users
#
# Reports on:
# AWS::IAM::Policy
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# F11, F12
#
# Scenarios:
# a) SKIP: when there are no IAM Policies present
# b) PASS: when no IAM Policies attach to Users
# c) FAIL: when any S3 BucketPolicies PolicyDocument statement has both Effect: Allow and NotPrincipal
# d) SKIP: when metadata has rule suppression for IAM_NO_POLICY_ON_USER or CFN_NAG F11, F12

let applicable_types = [
"AWS::IAM::Policy",
"AWS::IAM::ManagedPolicy"
]

let iam_no_policy_on_user = Resources.*[ Type in %applicable_types
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id !in [ "F11", "F12" ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_NO_POLICY_ON_USER"
]

rule IAM_NO_POLICY_ON_USER when %iam_no_policy_on_user !empty {
let violations = %iam_no_policy_on_user[
Type == 'AWS::IAM::Policy'
or
Type == 'AWS::IAM::ManagedPolicy'
Properties.Users !empty
]
%violations empty
<<
Violation: IAM policy/managedpolicy should not apply directly to users. Should be on group
Fix: Associate the IAM Policy/ManagedPolicy with a Group and make the IAM User a member of the group.
>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# a) SKIP: when there are no IAM Policies present
# b) PASS: when all IAM Policies do not grant permissions to all actions on all resources
# c) FAIL: when any IAM Policies grant permissions to all actions on all resources
# d) SKIP: when metada has rule suppression for IAM_POLICY_NO_STATEMENTS_WITH_ADMIN_ACCESS
# d) SKIP: when metadata has rule suppression for IAM_POLICY_NO_STATEMENTS_WITH_ADMIN_ACCESS

#
# Select all IAM Policy resources from incoming template (payload)
Expand Down
28 changes: 16 additions & 12 deletions rules/aws/iam/iam_policy_no_statements_with_full_access.guard
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,44 @@
# Checks if AWS Identity and Access Management (IAM) policies grant permissions to all actions on individual AWS resources.
#
# Reports on:
# AWS::IAM::ManagedPolicy
# AWS::IAM::Policy
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# F4
#
# Scenarios:
# a) SKIP: when there are no IAM Managed Policies present
# b) PASS: when all IAM Managed Policies do not allows full access to at least 1 AWS service
# c) FAIL: when any IAM Managed Policies allows full access to at least 1 AWS service.
# d) SKIP: when metada has rule suppression for IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS
# a) SKIP: when there are no IAM Policies present
# b) PASS: when all IAM Policies do not allow full access to at least 1 AWS service
# c) FAIL: when any IAM Policy allows full access to at least 1 AWS service.
# d) SKIP: when metadata has rule suppression for IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS or F4

#
# Select all IAM Managed Policy resources from incoming template (payload)
# Select all IAM Policy resources from incoming template (payload)
#
let aws_iam_managed_policies_no_statements_with_full_access = Resources.*[ Type == 'AWS::IAM::ManagedPolicy'
let aws_iam_policies = Resources.*[ Type == 'AWS::IAM::Policy'
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "F4"
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'
rule IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS when %aws_iam_policies !empty {
let violations = %aws_iam_policies[
Type == 'AWS::IAM::Policy'
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
Violation: One or more IAM 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": "*" ... }
>>
}
51 changes: 51 additions & 0 deletions rules/aws/iam/iam_policy_no_wildcard_resource_on_passrole.guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#
#####################################
## AWS Solutions ##
#####################################
# Rule Identifier:
# IAM_POLICY_NO_WILDCARD_RESOURCE_ON_PASSROLE
#
# Description:
# IAM policy should not allow * resource with PassRole action on its permissions policy
#
# Reports on:
# AWS::IAM::Policy
# AWS::IAM::ManagedPolicy
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# F39, F40
#
# Scenarios:
# a) SKIP: when there are no IAM Policies present
# b) PASS: when no IAM Policies use Resource *
# c) FAIL: when any IAM Policy allows unrestricted Resource *
# d) SKIP: when metada has rule suppression for IAM_POLICY_NO_WILDCARD_RESOURCE_ON_PASSROLE or CFN_NAG F39

let iam_policy_no_wildcard_resource_on_passrole = Resources.*[ Type in [ /AWS::IAM::Policy/, /AWS::IAM::ManagedPolicy/ ]
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id !in [ "F39", "F40" ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_POLICY_NO_WILDCARD_RESOURCE_ON_PASSROLE"
]

rule IAM_POLICY_NO_WILDCARD_RESOURCE_ON_PASSROLE when %iam_policy_no_wildcard_resource_on_passrole !empty {
let violations = %iam_policy_no_wildcard_resource_on_passrole[
some Properties.PolicyDocument.Statement[*] {
some Action[*] == 'iam:PassRole'
Resource == "*"
Effect == "Allow"
Condition not exists
}
]
%violations empty
<<
Violation: IAM policy should not allow * resource with PassRole action on its permissions policy
Fix: Limit the scope of the Resource for iam:PassRole as much as possible
>>
}
64 changes: 64 additions & 0 deletions rules/aws/iam/iam_policydocument_no_wildcard_resource.guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#
#####################################
## AWS Solutions ##
#####################################
# Rule Identifier:
# IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE
#
# Description:
# Checks that no IAM Role in-line policies use resource: "*"
#
# Reports on:
# AWS::IAM::Role
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# W10, W11, W12
#
# Scenarios:
# a) SKIP: when there are no IAM Roles, Policies, or ManagedPolicies present
# b) PASS: when all IAM Roles do not use resource: "*"
# c) FAIL: when any IAM Roles allow a wildcard for a resource
# d) SKIP: when metadata has rule suppression for IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE or W11, W12, or W13

let applicable_types = [
"AWS::IAM::Role",
"AWS::IAM::Policy",
"AWS::IAM::ManagedPolicy"
]

let iam_policydocument_no_wildcard_resource = Resources.*[ Type in %applicable_types
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id !in [ "W11", "W12", "W13" ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE"
]

rule IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE when %iam_policydocument_no_wildcard_resource not empty {
let violations = %iam_policydocument_no_wildcard_resource[
some Properties.Policies[*].PolicyDocument.Statement[*] {
some Resource[*] == "*"
Effect == "Allow"
}
or
some Properties.PolicyDocument.Statement[*] {
some Resource[*] == "*"
Effect == "Allow"
}
or
some Properties.PolicyDocument.Statement[*] {
some Resource[*] == "*"
Effect == "Allow"
}
]
%violations empty
<<
Violation: IAM Role inline policy should not allow resource: "*"
Fix: Limit resource as specifically as possible within your use case.
>>
}
50 changes: 50 additions & 0 deletions rules/aws/iam/iam_role_administrator_access_policy_rule.guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#
#####################################
## AWS Solutions ##
#####################################
# Rule Identifier:
# IAM_ROLE_ADMINISTRATOR_ACCESS_POLICY_RULE
#
# Description:
# IAM role should not have AdministratorAccess policy
#
# Reports on:
# AWS::IAM::Role
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# W43
#
# Scenarios:
# a) SKIP: when there are no IAM Roles present
# b) PASS: when no IAM Roles have AdministratorAccess policy
# c) FAIL: when any IAM Roles have AdministratorAccess policy
# d) SKIP: when metadata has rule suppression for IAM_ROLE_ADMINISTRATOR_ACCESS_POLICY_RULE or CFN_NAG W43

#
# Select all IAM Role resources from incoming template (payload)
#
let iam_role_administrator_access_policy_rule = Resources.*[ Type == 'AWS::IAM::Role'
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "W43"
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_ROLE_ADMINISTRATOR_ACCESS_POLICY_RULE"
]

rule IAM_ROLE_ADMINISTRATOR_ACCESS_POLICY_RULE when %iam_role_administrator_access_policy_rule !empty {
let violations = %iam_role_administrator_access_policy_rule[
Type == 'AWS::IAM::Role'
Properties.ManagedPolicyArns exists
some Properties.ManagedPolicyArns[*] == 'arn:aws:iam::aws:policy/AdministratorAccess'
]
%violations empty
<<
Violation: IAM role ManagedPolicyArns has AdministratorAccess policy access.
Fix: Remove AdministratorAccess policy access from ManagedPolicyArns in IAM Roles.
>>
}
Loading

0 comments on commit 41731c0

Please sign in to comment.