AWS IAM Policy Does Not Grant Network Admin Access


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.

Query · python

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"])

Analyst notes

Delete the unapproved network admin policy.

Raw source AWS IAM Policy Does Not Grant Network Admin Access · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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"])

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.