AnalysisType: policy
Filename: aws_iam_policy_role_mapping.py
PolicyID: "AWS.IAM.Policy.RoleMapping"
DisplayName: "AWS IAM Policy Role Mapping"
Enabled: false
ResourceTypes:
- AWS.IAM.Policy
Tags:
- AWS
- Configuration Required
- Identity & Access Management
Severity: High
Description: >
This policy validates that policies that have been explicitly configured to be set to certain roles are still attached to those roles.
Runbook: >
https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-iam-policy-role-mapping-is-respected
Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html
Tests:
- Name: Policy Applied To Required Roles
ExpectedResult: true
Resource:
{
"Arn": "arn:aws:iam::123456789012:policy/service-role/example-policy",
"AttachmentCount": 2,
"CreateDate": "2019-01-01T00:00:00Z",
"DefaultVersionId": "v1",
"Description": null,
"Entities":
{
"PolicyGroups": null,
"PolicyRoles":
[
{ "RoleId": "ABCDEFGHIJKLMNOP1", "RoleName": "TestRole1" },
{ "RoleId": "ABCDEFGHIJKLMNOP2", "RoleName": "TestRole2" },
],
"PolicyUsers":
[{ "UserId": "ABCDEFGHIJKLMNOP", "UserName": "Bobert" }],
},
"IsAttachable": true,
"Path": "/service-role/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": "JSON policy document see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html for details",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "TestPolicyName",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: Policy Does Not Have Role Mappings
ExpectedResult: true
Resource:
{
"Arn": "arn:aws:iam::123456789012:policy/service-role/example-policy",
"AttachmentCount": 2,
"CreateDate": "2019-01-01T00:00:00Z",
"DefaultVersionId": "v1",
"Description": null,
"Entities":
{
"PolicyGroups": null,
"PolicyRoles":
[{ "RoleId": "ABCDEFGHIJKLMNOP", "RoleName": "Example-Role" }],
"PolicyUsers":
[{ "UserId": "ABCDEFGHIJKLMNOP", "UserName": "Bobert" }],
},
"IsAttachable": true,
"Path": "/service-role/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": "JSON policy document see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html for details",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "Example-Policy",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: Policy Not Applied To Required Roles
ExpectedResult: false
Resource:
{
"Arn": "arn:aws:iam::123456789012:policy/service-role/example-policy",
"AttachmentCount": 2,
"CreateDate": "2019-01-01T00:00:00Z",
"DefaultVersionId": "v1",
"Description": null,
"Entities":
{
"PolicyGroups": null,
"PolicyRoles":
[{ "RoleId": "ABCDEFGHIJKLMNOP", "RoleName": "Example-Role" }],
"PolicyUsers":
[{ "UserId": "ABCDEFGHIJKLMNOP", "UserName": "Bobert" }],
},
"IsAttachable": true,
"Path": "/service-role/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": "JSON policy document see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html for details",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "TestPolicyName",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: Policy Not Applied to Anything
ExpectedResult: true
Resource:
{
"Arn": "arn:aws:iam::123456789012:policy/service-role/example-policy",
"AttachmentCount": 2,
"CreateDate": "2019-01-01T00:00:00Z",
"DefaultVersionId": "v1",
"Description": null,
"Entities": null,
"IsAttachable": true,
"Path": "/service-role/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": "JSON policy document see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html for details",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "Example-Policy",
"UpdateDate": "2019-01-01T00:00:00Z",
}
# ------ paired body: aws_iam_policy_role_mapping.py ------
from panther_base_helpers import deep_get
# This is a mapping of what policies must be attached to what roles in the account.
# The mapping is keyed by string policy names to tuples of role names. Ordering doesn't matter.
# Example:
# POLICY_ROLE_MAPPINGS = {
# 'ExamplePolicyName1': ('ExampleRoleName1', 'ExampleRoleName2', 'ExampleRoleName3'),
# 'ExamplePolicyName2': ('ExampleRoleName1', 'ExampleRoleName3', 'ExampleRoleName4'),
# }
POLICY_ROLE_MAPPINGS = {
"TestPolicyName": ("TestRole1", "TestRole2"),
}
def policy(resource):
# Check if there are any required roles for this policy to be attached to
if resource["PolicyName"] not in POLICY_ROLE_MAPPINGS:
return True
# Check if this policy is attached to any roles
if deep_get(resource, "Entities", "PolicyRoles") is None:
return False
# Build the list of role names this policy is actually attached to
roles_attached = [
role["RoleName"] for role in deep_get(resource, "Entities", "PolicyRoles", default=[])
]
# For each required role, ensure that role has the policy attached
for role_needed in POLICY_ROLE_MAPPINGS[resource["PolicyName"]]:
if role_needed not in roles_attached:
return False
return True