AnalysisType: policy
Filename: aws_iam_user_not_in_conflicting_groups.py
PolicyID: "AWS.IAM.User.NotInConflictingGroups"
DisplayName: "AWS IAM User Not In Conflicting Groups"
Enabled: false
ResourceTypes:
- AWS.IAM.User
Tags:
- AWS
- Configuration Required
- Security, Identity & Compliance
- PCI
- Privilege Escalation:Valid Accounts
Reports:
PCI:
- 7.2.2
MITRE ATT&CK:
- TA0004:T1078
Severity: Medium
Description: >
This policy validates that IAM users are not in IAM groups that are considered mutually exclusive. For example, in some workflows developers are responsible for dev environments and sysadmins are responsible for prod environments. In this situation no (or very few) users should be in both sysadmin and developer groups. This is in following with the principle of least privilege.
Runbook: Remove the IAM user from one of the conflicting groups.
Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html
Tests:
- Name: User In Conflicting Groups
ExpectedResult: false
Resource:
{
"Arn": "arn:aws:iam::123456789012:user/Bobert",
"CreateDate": "2019-05-10T21:49:56Z",
"CredentialReport":
{
"ARN": "arn:aws:iam::123456789012:user/Bobert",
"AccessKey1Active": true,
"AccessKey1LastRotated": "2019-05-10T21:49:57Z",
"AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
"AccessKey1LastUsedRegion": "N/A",
"AccessKey1LastUsedService": "N/A",
"AccessKey2Active": false,
"AccessKey2LastRotated": "0001-01-01T00:00:00Z",
"AccessKey2LastUsedDate": "0001-01-01T00:00:00Z",
"AccessKey2LastUsedRegion": "N/A",
"AccessKey2LastUsedService": "N/A",
"Cert1Active": false,
"Cert1LastRotated": "0001-01-01T00:00:00Z",
"Cert2Active": false,
"Cert2LastRotated": "0001-01-01T00:00:00Z",
"MfaActive": false,
"PasswordEnabled": false,
"PasswordLastChanged": "2019-05-21T22:10:11Z",
"PasswordLastUsed": "0001-01-01T00:00:00Z",
"PasswordNextRotation": "2019-08-14T22:10:11Z",
"UserCreationTime": "2019-05-10T21:49:56Z",
"UserName": "Bobert",
},
"Groups":
[
{
"Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
"CreateDate": "2019-01-01T00:00:00Z",
"GroupId": "ABCDEFGHIJKLMNOP",
"GroupName": "PROD_ADMIN",
"Path": "/",
},
{
"Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
"CreateDate": "2019-01-01T00:00:00Z",
"GroupId": "ABCDEFGHIJKLMNOP",
"GroupName": "DEV",
"Path": "/",
},
],
"InlinePolicyNames": null,
"ManagedPolicyNames": ["IAMUserChangePassword"],
"PasswordLastUsed": null,
"Path": "/",
"PermissionsBoundary": null,
"Tags": null,
"UserId": "ASDFASDFASDFASDF",
"UserName": "Bobert",
"VirtualMFA": null,
}
- Name: User Not In Conflicting Groups
ExpectedResult: true
Resource:
{
"Arn": "arn:aws:iam::123456789012:user/Bobert",
"CreateDate": "2019-05-10T21:49:56Z",
"CredentialReport":
{
"ARN": "arn:aws:iam::123456789012:user/Bobert",
"AccessKey1Active": true,
"AccessKey1LastRotated": "2019-05-10T21:49:57Z",
"AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
"AccessKey1LastUsedRegion": "N/A",
"AccessKey1LastUsedService": "N/A",
"AccessKey2Active": false,
"AccessKey2LastRotated": "0001-01-01T00:00:00Z",
"AccessKey2LastUsedDate": "0001-01-01T00:00:00Z",
"AccessKey2LastUsedRegion": "N/A",
"AccessKey2LastUsedService": "N/A",
"Cert1Active": false,
"Cert1LastRotated": "0001-01-01T00:00:00Z",
"Cert2Active": false,
"Cert2LastRotated": "0001-01-01T00:00:00Z",
"MfaActive": true,
"PasswordEnabled": true,
"PasswordLastChanged": "2019-05-21T22:10:11Z",
"PasswordLastUsed": "0001-01-01T00:00:00Z",
"PasswordNextRotation": "2019-08-14T22:10:11Z",
"UserCreationTime": "2019-05-10T21:49:56Z",
"UserName": "Bobert",
},
"Groups":
[
{
"Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
"CreateDate": "2019-01-01T00:00:00Z",
"GroupId": "ABCDEFGHIJKLMNOP",
"GroupName": "ExampleGroup",
"Path": "/",
},
],
"InlinePolicyNames": null,
"ManagedPolicyNames": ["IAMUserChangePassword"],
"PasswordLastUsed": null,
"Path": "/",
"PermissionsBoundary": null,
"Tags": null,
"UserId": "ASDFASDFASDFASDF",
"UserName": "Bobert",
"VirtualMFA": null,
}
# ------ paired body: aws_iam_user_not_in_conflicting_groups.py ------
# This policy ensures that users do not belong to groups that should be exclusive.
# A common example would be the Developer group and the Production admin group, as in tightly
# controlled environments developers should not be able to deploy to production directly and
# sysadmins should not have access to developmental source code.
#
# GROUP_CONFLICTS is formatted as a list of sets. Each inner set contains mutually exclusive groups.
GROUP_CONFLICTS = [
{"PROD_ADMIN", "DEV"},
]
def policy(resource):
group_names = {group["GroupName"] for group in resource["Groups"] or []}
# If the user is in more than one group in a mutually exclusive set, return False
for conflict_set in GROUP_CONFLICTS:
if len(group_names.intersection(conflict_set)) > 1:
return False
return True