AnalysisType: policy
Filename: aws_iam_policy_does_not_grant_admin_access.py
PolicyID: "AWS.IAM.Policy.DoesNotGrantAdminAccess"
DisplayName: "AWS IAM Policy Does Not Grant Any Administrative Access"
Enabled: true
ResourceTypes:
- AWS.IAM.Policy
Tags:
- AWS
- PCI
- Security, Identity & Compliance
- Privilege Escalation:Valid Accounts
Reports:
PCI:
- 2.2.4
- 7.1.2
MITRE ATT&CK:
- TA0004:T1078
Severity: Medium
Description: >
This policy validates that no IAM policies grant admin access. This should be combined with suppressions on the legitimate IAM admin policies in your account so that it only fires when new and unexpected policies granting admin access are created.
Runbook: Delete the unapproved IAM admin policy.
Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html
Tests:
- Name: Policy Does Not Grant Administrative Privileges
ExpectedResult: true
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:iam::123456789012:policy/ExamplePolicy",
"AttachmentCount": 1,
"DefaultVersionId": "v1",
"Description": null,
"Entities":
{
"PolicyGroups": null,
"PolicyRoles": [{ "RoleId": "1111", "RoleName": "ExampleRole" }],
"PolicyUsers": null,
},
"Id": "AAAAA",
"IsAttachable": true,
"Name": "ExamplePolicy",
"Path": "/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": '{"Version":"2012-10-17","Statement":[{"Action":["kms:DescribeKey"],"Resource":"arn:aws:kms:us-west-2:123456789012:key/1","Effect":"Allow","Sid":"EncryptMessages"}]}',
"Region": "global",
"ResourceId": "arn:aws:iam::123456789012:policy/ExamplePolicy",
"ResourceType": "AWS.IAM.Policy",
"Tags": null,
"TimeCreated": "2019-01-01T00:00:00.000Z",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: Policy Does Grant Administrative Privileges
ExpectedResult: false
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:iam::123456789012:policy/ExamplePolicy",
"AttachmentCount": 1,
"DefaultVersionId": "v1",
"Description": null,
"Entities":
{
"PolicyGroups": null,
"PolicyRoles": [{ "RoleId": "1111", "RoleName": "ExampleRole" }],
"PolicyUsers": null,
},
"Id": "AAAAA",
"IsAttachable": true,
"Name": "ExamplePolicy",
"Path": "/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": '{"Version":"2012-10-17","Statement":[{"Action":["kms:PutKeyPolicy","kms:GenerateDataKey"],"Resource":"arn:aws:kms:us-west-2:123456789012:key/1","Effect":"Allow","Sid":"EncryptMessages"},{"Action":["sqs:SendMessage","sqs:SendMessageBatch"],"Resource":"arn:aws:sqs:us-west-2:123456789012:example-queue","Effect":"Allow","Sid":"SendSQSMessages"}]}',
"Region": "global",
"ResourceId": "arn:aws:iam::123456789012:policy/ExamplePolicy",
"ResourceType": "AWS.IAM.Policy",
"Tags": null,
"TimeCreated": "2019-01-01T00:00:00.000Z",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: AWS Service-Linked Policy Network Admin
ExpectedResult: true
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:iam::123456789012:policy/aws-service-role/AmazonGuardDutyServiceRolePolicy",
"AttachmentCount": 1,
"DefaultVersionId": "v6",
"Entities":
{
"PolicyGroups": null,
"PolicyRoles":
[
{
"RoleId": "AROOOOOOOOOOOOOOOOOOO",
"RoleName": "AWSServiceRoleForAmazonGuardDuty",
},
],
"PolicyUsers": null,
},
"Id": "ANPPPPPPPPPPPPPPPPPPP",
"IsAttachable": true,
"Name": "AmazonGuardDutyServiceRolePolicy",
"Path": "/aws-service-role/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": "{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"ec2:DescribeInstances\",\n\t\t\t\t\"ec2:DescribeImages\",\n\t\t\t\t\"ec2:DescribeVpcEndpoints\",\n\t\t\t\t\"ec2:DescribeSubnets\",\n\t\t\t\t\"ec2:DescribeVpcPeeringConnections\",\n\t\t\t\t\"ec2:DescribeTransitGatewayAttachments\",\n\t\t\t\t\"organizations:ListAccounts\",\n\t\t\t\t\"organizations:DescribeAccount\",\n\t\t\t\t\"s3:GetBucketPublicAccessBlock\",\n\t\t\t\t\"s3:GetEncryptionConfiguration\",\n\t\t\t\t\"s3:GetBucketTagging\",\n\t\t\t\t\"s3:GetAccountPublicAccessBlock\",\n\t\t\t\t\"s3:ListAllMyBuckets\",\n\t\t\t\t\"s3:GetBucketAcl\",\n\t\t\t\t\"s3:GetBucketPolicy\",\n\t\t\t\t\"s3:GetBucketPolicyStatus\",\n\t\t\t\t\"lambda:GetFunctionConfiguration\",\n\t\t\t\t\"lambda:ListTags\",\n\t\t\t\t\"eks:ListClusters\",\n\t\t\t\t\"eks:DescribeCluster\",\n\t\t\t\t\"ec2:DescribeVpcEndpointServices\",\n\t\t\t\t\"ec2:DescribeSecurityGroups\"\n\t\t\t],\n\t\t\t\"Resource\": \"*\"\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"iam:CreateServiceLinkedRole\",\n\t\t\t\"Resource\": \"*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"StringEquals\": {\n\t\t\t\t\t\"iam:AWSServiceName\": \"malware-protection.guardduty.amazonaws.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"ec2:CreateVpcEndpoint\",\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:vpc-endpoint/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"ForAnyValue:StringEquals\": {\n\t\t\t\t\t\"aws:TagKeys\": \"GuardDutyManaged\"\n\t\t\t\t},\n\t\t\t\t\"StringLike\": {\n\t\t\t\t\t\"ec2:VpceServiceName\": [\n\t\t\t\t\t\t\"com.amazonaws.*.guardduty-data\",\n\t\t\t\t\t\t\"com.amazonaws.*.guardduty-data-fips\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"ec2:ModifyVpcEndpoint\",\n\t\t\t\t\"ec2:DeleteVpcEndpoints\"\n\t\t\t],\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:vpc-endpoint/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"Null\": {\n\t\t\t\t\t\"aws:ResourceTag/GuardDutyManaged\": false\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"ec2:CreateVpcEndpoint\",\n\t\t\t\t\"ec2:ModifyVpcEndpoint\"\n\t\t\t],\n\t\t\t\"Resource\": [\n\t\t\t\t\"arn:aws:ec2:*:*:vpc/*\",\n\t\t\t\t\"arn:aws:ec2:*:*:security-group/*\",\n\t\t\t\t\"arn:aws:ec2:*:*:subnet/*\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"ec2:CreateTags\",\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:vpc-endpoint/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"StringEquals\": {\n\t\t\t\t\t\"ec2:CreateAction\": \"CreateVpcEndpoint\"\n\t\t\t\t},\n\t\t\t\t\"ForAnyValue:StringEquals\": {\n\t\t\t\t\t\"aws:TagKeys\": \"GuardDutyManaged\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"ec2:AuthorizeSecurityGroupIngress\",\n\t\t\t\t\"ec2:AuthorizeSecurityGroupEgress\",\n\t\t\t\t\"ec2:RevokeSecurityGroupIngress\",\n\t\t\t\t\"ec2:RevokeSecurityGroupEgress\",\n\t\t\t\t\"ec2:DeleteSecurityGroup\"\n\t\t\t],\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:security-group/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"Null\": {\n\t\t\t\t\t\"aws:ResourceTag/GuardDutyManaged\": false\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"ec2:CreateSecurityGroup\",\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:security-group/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"StringLike\": {\n\t\t\t\t\t\"aws:RequestTag/GuardDutyManaged\": \"*\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"ec2:CreateSecurityGroup\",\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:vpc/*\"\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"ec2:CreateTags\",\n\t\t\t\"Resource\": \"arn:aws:ec2:*:*:security-group/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"StringEquals\": {\n\t\t\t\t\t\"ec2:CreateAction\": \"CreateSecurityGroup\"\n\t\t\t\t},\n\t\t\t\t\"ForAnyValue:StringEquals\": {\n\t\t\t\t\t\"aws:TagKeys\": \"GuardDutyManaged\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"eks:CreateAddon\",\n\t\t\t\"Resource\": \"arn:aws:eks:*:*:cluster/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"ForAnyValue:StringEquals\": {\n\t\t\t\t\t\"aws:TagKeys\": \"GuardDutyManaged\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"eks:DeleteAddon\",\n\t\t\t\t\"eks:UpdateAddon\",\n\t\t\t\t\"eks:DescribeAddon\"\n\t\t\t],\n\t\t\t\"Resource\": \"arn:aws:eks:*:*:addon/*/aws-guardduty-agent/*\"\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": \"eks:TagResource\",\n\t\t\t\"Resource\": \"arn:aws:eks:*:*:cluster/*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"ForAnyValue:StringEquals\": {\n\t\t\t\t\t\"aws:TagKeys\": \"GuardDutyManaged\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t]\n}",
"Region": "global",
"ResourceId": "arn:aws:iam::123456789012:policy/aws-service-role/AmazonGuardDutyServiceRolePolicy",
"ResourceType": "AWS.IAM.Policy",
"TimeCreated": "2017-11-28T20:12:59Z",
"UpdateDate": "2023-03-05T19:19:19Z",
}
- Name: AWS Service Linked Role Policy Admin
ExpectedResult: true
Resource:
{
"AccountId": "123456789012",
"Arn": "arn:aws:iam::123456789012:policy/aws-service-role/AmazonElasticFileSystemServiceRolePolicy",
"AttachmentCount": 1,
"DefaultVersionId": "v4",
"Entities":
{
"PolicyGroups": null,
"PolicyRoles":
[
{
"RoleId": "AROOOOOOOOOOOOOOOOOOO",
"RoleName": "AWSServiceRoleForAmazonElasticFileSystem",
},
],
"PolicyUsers": null,
},
"Id": "ANPPPPPPPPPPPPPPPPPPP",
"IsAttachable": true,
"Name": "AmazonElasticFileSystemServiceRolePolicy",
"Path": "/aws-service-role/",
"PermissionsBoundaryUsageCount": 0,
"PolicyDocument": "{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"backup-storage:MountCapsule\",\n\t\t\t\t\"ec2:CreateNetworkInterface\",\n\t\t\t\t\"ec2:DeleteNetworkInterface\",\n\t\t\t\t\"ec2:DescribeSecurityGroups\",\n\t\t\t\t\"ec2:DescribeSubnets\",\n\t\t\t\t\"ec2:DescribeNetworkInterfaceAttribute\",\n\t\t\t\t\"ec2:ModifyNetworkInterfaceAttribute\",\n\t\t\t\t\"tag:GetResources\"\n\t\t\t],\n\t\t\t\"Resource\": \"*\"\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"kms:DescribeKey\"\n\t\t\t],\n\t\t\t\"Resource\": \"arn:aws:kms:*:*:key/*\"\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"backup:CreateBackupVault\",\n\t\t\t\t\"backup:PutBackupVaultAccessPolicy\"\n\t\t\t],\n\t\t\t\"Resource\": [\n\t\t\t\t\"arn:aws:backup:*:*:backup-vault:aws/efs/automatic-backup-vault\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"backup:CreateBackupPlan\",\n\t\t\t\t\"backup:CreateBackupSelection\"\n\t\t\t],\n\t\t\t\"Resource\": [\n\t\t\t\t\"arn:aws:backup:*:*:backup-plan:*\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"iam:CreateServiceLinkedRole\"\n\t\t\t],\n\t\t\t\"Resource\": \"*\",\n\t\t\t\"Condition\": {\n\t\t\t\t\"StringEquals\": {\n\t\t\t\t\t\"iam:AWSServiceName\": [\n\t\t\t\t\t\t\"backup.amazonaws.com\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"iam:PassRole\"\n\t\t\t],\n\t\t\t\"Resource\": [\n\t\t\t\t\"arn:aws:iam::*:role/aws-service-role/backup.amazonaws.com/AWSServiceRoleForBackup\"\n\t\t\t],\n\t\t\t\"Condition\": {\n\t\t\t\t\"StringLike\": {\n\t\t\t\t\t\"iam:PassedToService\": \"backup.amazonaws.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\n\t\t\t\t\"elasticfilesystem:DescribeFileSystems\",\n\t\t\t\t\"elasticfilesystem:CreateReplicationConfiguration\",\n\t\t\t\t\"elasticfilesystem:DescribeReplicationConfigurations\",\n\t\t\t\t\"elasticfilesystem:DeleteReplicationConfiguration\"\n\t\t\t],\n\t\t\t\"Resource\": \"*\"\n\t\t}\n\t]\n}",
"Region": "global",
"ResourceId": "arn:aws:iam::123456789012:policy/aws-service-role/AmazonElasticFileSystemServiceRolePolicy",
"ResourceType": "AWS.IAM.Policy",
"TimeCreated": "2019-11-05T16:52:41Z",
"UpdateDate": "2023-03-10T19:19:19Z",
}
# ------ paired body: aws_iam_policy_does_not_grant_admin_access.py ------
import json
from policyuniverse.expander_minimizer import expand_policy
from policyuniverse.policy import Policy
# White listed policies (e.g. the approved admin policies) can be specified here, or as an
# exception to this policy.
ADMIN_ACTIONS = {
"Permissions",
}
def policy(resource):
iam_policy = Policy(expand_policy(json.loads(resource["PolicyDocument"])))
action_summary = iam_policy.action_summary()
# Sometimes AWS Service Linked Roles+Policies violate the
# expectation as expressed in policyuniverse.
# service-linked roles have a path of /aws-service-role/
# service-linked roles and their policies are not editable
# service-role is editable, and so not included
if resource.get("Path", "") == "/aws-service-role/":
return True
# Check if the policy grants any administrative privileges
return not any(
ADMIN_ACTIONS.intersection(action_summary[service]) for service in action_summary
)