AnalysisType: policy
Filename: aws_iam_policy_does_not_grant_network_admin_access.py
PolicyID: "AWS.IAM.Policy.DoesNotGrantNetworkAdminAccess"
DisplayName: "AWS IAM Policy Does Not Grant Network Admin Access"
Enabled: true
ResourceTypes:
- AWS.IAM.Policy
Tags:
- AWS
- PCI
- Privilege Escalation:Valid Accounts
Reports:
PCI:
- 1.1.5
MITRE ATT&CK:
- TA0004:T1078
Severity: Medium
Description: >
This policy validates that no IAM policies grant admin privileges on network resources. This should be used in conjunction with suppressions for the legitimate network admin policies in your account.
Runbook: >
Delete the unapproved network admin policy.
Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html
Tests:
- Name: IAM Policy Does Not Grant VPC Permissions
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": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:s3:::bucket-name\"\n ],\n \"Action\": [\n \"s3:PutObject\",\n \"s3:GetObject\",\n \"s3:GetObjectVersion\"\n ]\n }\n ]\n}",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "Example-Policy",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: IAM Policy Does Grant VPC Write Permissions
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": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:vpc:::vpc-name\"\n ],\n \"Action\": [\n \"ec2:PutNetworkACL\",\n \"ec2:DeleteSecurityGroup\",\n \"ec2:DescribeVpcs\"\n ]\n }\n ]\n}",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "Example-Policy",
"UpdateDate": "2019-01-01T00:00:00Z",
}
- Name: IAM Policy Grants Only VPC Read Permissions
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": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:vpc:::vpc-name\"\n ],\n \"Action\": [\n \"ec2:DescribeNetworkAcls\",\n \"ec2:DescribeSecurityGroups\",\n \"ec2:DescribeVpcs\"\n ]\n }\n ]\n}",
"PolicyId": "ABCDEFGHIJKLMNOP",
"PolicyName": "Example-Policy",
"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_network_admin_access.py ------
import json
from policyuniverse.action_categories import categories_for_actions
from policyuniverse.expander_minimizer import expand_policy
from policyuniverse.policy import Policy
# White listed policies (e.g. the approved network admin policy) can be specified here, or as an
# exception to this policy.
ADMIN_ACTIONS = {
"Tagging",
"Write",
}
NETWORK_RESOURCES = {
"vpc",
"securitygroup",
"networkacl",
"routetable",
}
def policy(resource):
iam_policy = Policy(expand_policy(json.loads(resource["PolicyDocument"])))
action_summary = iam_policy.action_summary()
#
# These first two checks can technically be skipped and this policy will still return correct
# results, but they prevent the more computationally expensive check the majority of the time.
#
# Check if the policy applies to EC2 resources
if "ec2" not in action_summary:
return True
# 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 administrative privileges
if not ADMIN_ACTIONS.intersection(action_summary["ec2"]):
return True
# Get the EC2 actions pertaining specifically to network resources
network_actions = set()
for statement in iam_policy.statements:
# Only check statements granting access
if statement.effect != "Allow":
continue
# Only check actions that are granted on network resources
for action in statement.actions:
if any(resource in action for resource in NETWORK_RESOURCES):
network_actions.add(action)
# For all actions that have been granted on network resources, ensure none grant admin access
network_actions_summary = categories_for_actions(network_actions)
return not any(action in ADMIN_ACTIONS for action in network_actions_summary["ec2"])