Skip to main content

Parse and Process AWS IAM Policies, Statements, ARNs, and wildcards.

Project description

PolicyUniverse

Version

Build Status

Coverage Status

Code style: black

This package provides classes to parse AWS IAM and Resource Policies.

Additionally, this package can expand wildcards in AWS Policies using permissions obtained from the AWS Policy Generator.

See the Service and Permissions data.

This package can also minify an AWS policy to help you stay under policy size limits. Avoid doing this if possible, as it creates ugly policies. 💩

Install:

pip install policyuniverse

Usage:

Reading ARNs

from policyuniverse.arn import ARN
arn = ARN('arn:aws:iam::012345678910:role/SomeTestRoleForTesting')
assert arn.error == False
assert arn.tech == 'iam'
assert arn.region == ''  # IAM is universal/global
assert arn.account_number == '012345678910'
assert arn.name == 'role/SomeTestRoleForTesting'
assert arn.partition == 'aws'
assert arn.root == False  # Not the root ARN
assert arn.service == False  # Not an AWS service like lambda.amazonaws.com

arn = ARN('012345678910')
assert arn.account_number == '012345678910'

arn = ARN('lambda.amazonaws.com')
assert arn.service == True
assert arn.tech == 'lambda'

IAM and Resource Policies

Policy with multiple statements

# Two statements, both with conditions
policy05 = dict(
    Version='2010-08-14',
    Statement=[
        dict(
            Effect='Allow',
            Principal='arn:aws:iam::012345678910:root',
            Action=['s3:*'],
            Resource='*',
            Condition={
                'IpAddress': {
                    'AWS:SourceIP': ['0.0.0.0/0']
                }}),
        dict(
            Effect='Allow',
            Principal='arn:aws:iam::*:role/Hello',
            Action=['ec2:*'],
            Resource='*',
            Condition={
                'StringLike': {
                    'AWS:SourceOwner': '012345678910'
                }})
        ])

from policyuniverse.policy import Policy
from policyuniverse.statement import ConditionTuple, PrincipalTuple

policy = Policy(policy05)
assert policy.whos_allowed() == set([
    PrincipalTuple(category='principal', value='arn:aws:iam::*:role/Hello'),
    PrincipalTuple(category='principal', value='arn:aws:iam::012345678910:root'),
    ConditionTuple(category='cidr', value='0.0.0.0/0'),
    ConditionTuple(category='account', value='012345678910')
])

# The given policy is not internet accessible.
# The first statement is limited by the principal, and the condition is basically a no-op.
# The second statement has a wildcard principal, but uses the condition to lock it down.
assert policy.is_internet_accessible() == False

Internet Accessible Policy:

# An internet accessible policy:
policy01 = dict(
    Version='2012-10-08',
    Statement=dict(
        Effect='Allow',
        Principal='*',
        Action=['rds:*'],
        Resource='*',
        Condition={
            'IpAddress': {
                'AWS:SourceIP': ['0.0.0.0/0']
            }
        }))

policy = Policy(policy01)
assert policy.is_internet_accessible() == True
assert policy.internet_accessible_actions() == set(['rds:*'])

Statements

A policy is simply a collection of statements.

statement12 = dict(
    Effect='Allow',
    Principal='*',
    Action=['rds:*'],
    Resource='*',
    Condition={
        'StringEquals': {
            'AWS:SourceVPC': 'vpc-111111',
            'AWS:Sourcevpce': 'vpce-111111',
            'AWS:SourceOwner': '012345678910',
            'AWS:SourceAccount': '012345678910'
        },
        'StringLike': {
            'AWS:userid': 'AROAI1111111111111111:*'
        },
        'ARNLike': {
            'AWS:SourceArn': 'arn:aws:iam::012345678910:role/Admin'
        },
        'IpAddressIfExists': {
            'AWS:SourceIP': [
                '123.45.67.89',
                '10.0.7.0/24',
                '172.16.0.0/16']
        }
    })

from policyuniverse.statement import Statement
from policyuniverse.statement import ConditionTuple, PrincipalTuple

statement = Statement(statement12)
assert statement.effect == 'Allow'
assert statement.actions == set(['rds:*'])

# rds:* expands out to ~88 individual permissions
assert len(statement.actions_expanded) == 88

assert statement.uses_not_principal() == False
assert statement.principals == set(['*'])
assert statement.condition_arns == set(['arn:aws:iam::012345678910:role/Admin'])
assert statement.condition_accounts == set(['012345678910'])
assert statement.condition_userids == set(['AROAI1111111111111111:*'])
assert statement.condition_cidrs == set(['10.0.7.0/24', '172.16.0.0/16', '123.45.67.89'])
assert statement.condition_vpcs == set(['vpc-111111'])
assert statement.condition_vpces == set(['vpce-111111'])
assert statement.is_internet_accessible() == False
assert statement.whos_allowed() == set([
    PrincipalTuple(category='principal', value='*'),
    ConditionTuple(category='cidr', value='123.45.67.89'),
    ConditionTuple(category='account', value='012345678910'),
    ConditionTuple(category='userid', value='AROAI1111111111111111:*'),
    ConditionTuple(category='vpc', value='vpc-111111'),
    ConditionTuple(category='arn', value='arn:aws:iam::012345678910:role/Admin'),
    ConditionTuple(category='cidr', value='172.16.0.0/16'),
    ConditionTuple(category='vpce', value='vpce-111111'),
    ConditionTuple(category='cidr', value='10.0.7.0/24')])

Action Categories

policy = {
        "Statement": [{
            "Action": ["s3:put*", "sqs:get*", "sns:*"],
            "Resource": "*",
            "Effect": "Allow"
          }]
      }

from policyuniverse.policy import Policy
p = Policy(policy)
for k, v in p.action_summary().items():
    print(k,v)
>>> ('s3', set([u'Write', u'Permissions', u'Tagging']))
>>> ('sqs', set([u'List']))
>>> ('sns', set([u'List', u'Read', u'Write', u'Permissions']))

Possible categories are Permissions, Write, Read, Tagging, and List. This data can be used to summarize statements and policies and to look for sensitive permissions.

Expanding and Minification

from policyuniverse.expander_minimizer import expand_policy
from policyuniverse.expander_minimizer import minimize_policy

policy = {
        "Statement": [{
            "Action": ["swf:res*"],
            "Resource": "*",
            "Effect": "Allow"
          }]
      }

expanded_policy = expand_policy(policy=policy)
>>> Start size: 131. End size: 286
print(expanded_policy == {
        "Statement": [{
            "Action": [
              "swf:respondactivitytaskcanceled",
              "swf:respondactivitytaskcompleted",
              "swf:respondactivitytaskfailed",
              "swf:responddecisiontaskcompleted"
            ],
            "Resource": "*",
            "Effect": "Allow"
          }]
      })
>>> True

minimized_policy = minimize_policy(policy=expanded_policy, minchars=3)
>>> Skipping prefix r because length of 1
>>> Skipping prefix re because length of 2
>>> Skipping prefix r because length of 1
>>> Skipping prefix re because length of 2
>>> Skipping prefix r because length of 1
>>> Skipping prefix re because length of 2
>>> Skipping prefix r because length of 1
>>> Skipping prefix re because length of 2
>>> Start size: 286. End size: 131

print(minimized_policy == policy)
>>> True

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

policyuniverse-1.3.3.20210114.tar.gz (303.5 kB view details)

Uploaded Source

Built Distribution

policyuniverse-1.3.3.20210114-py2.py3-none-any.whl (311.4 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file policyuniverse-1.3.3.20210114.tar.gz.

File metadata

  • Download URL: policyuniverse-1.3.3.20210114.tar.gz
  • Upload date:
  • Size: 303.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.9.1

File hashes

Hashes for policyuniverse-1.3.3.20210114.tar.gz
Algorithm Hash digest
SHA256 fa59b9413fb69e7131c238578d7325d8fdc2642caed1ca2a4795305e0d849c3e
MD5 54d5b8d03661b16b7b78a736ce705fc6
BLAKE2b-256 0b5d4f9444006d85522861b7739885f48c1b6eed46f6bb993cd60d4a9e324b9c

See more details on using hashes here.

File details

Details for the file policyuniverse-1.3.3.20210114-py2.py3-none-any.whl.

File metadata

  • Download URL: policyuniverse-1.3.3.20210114-py2.py3-none-any.whl
  • Upload date:
  • Size: 311.4 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.9.1

File hashes

Hashes for policyuniverse-1.3.3.20210114-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 4a4fcafd07549f4e0b89cdd34d2b0ae77a0356f311de87c5ca38baa26896f0b6
MD5 d4c385b3835786688acefc9d1186ecc3
BLAKE2b-256 eb9b44654bf79baa6d4305f13afec66549870b83377bd0b84d0cae29258b08b1

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page