{"id":13445068,"url":"https://github.com/Netflix-Skunkworks/policyuniverse","last_synced_at":"2025-03-20T19:31:31.691Z","repository":{"id":37743050,"uuid":"91367525","full_name":"Netflix-Skunkworks/policyuniverse","owner":"Netflix-Skunkworks","description":"Parse and Process AWS IAM Policies, Statements, ARNs, and wildcards.","archived":false,"fork":false,"pushed_at":"2024-01-06T05:39:26.000Z","size":12338,"stargazers_count":414,"open_issues_count":16,"forks_count":61,"subscribers_count":125,"default_branch":"master","last_synced_at":"2024-04-14T06:01:47.196Z","etag":null,"topics":["security"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Netflix-Skunkworks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-15T17:51:11.000Z","updated_at":"2024-05-07T12:46:37.579Z","dependencies_parsed_at":"2023-09-27T16:16:22.319Z","dependency_job_id":"137969cc-9b4c-4f2e-90b6-b7597cf53dbf","html_url":"https://github.com/Netflix-Skunkworks/policyuniverse","commit_stats":{"total_commits":177,"total_committers":22,"mean_commits":8.045454545454545,"dds":0.6101694915254237,"last_synced_commit":"8628271d1afad8920ffafebb67c0900c01e74303"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix-Skunkworks%2Fpolicyuniverse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix-Skunkworks%2Fpolicyuniverse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix-Skunkworks%2Fpolicyuniverse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix-Skunkworks%2Fpolicyuniverse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Netflix-Skunkworks","download_url":"https://codeload.github.com/Netflix-Skunkworks/policyuniverse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244676455,"owners_count":20491829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["security"],"created_at":"2024-07-31T04:00:53.229Z","updated_at":"2025-03-20T19:31:31.221Z","avatar_url":"https://github.com/Netflix-Skunkworks.png","language":"Python","funding_links":[],"categories":["Parsers","Projects","Python","Tools"],"sub_categories":["Identity and Access Management"],"readme":"# PolicyUniverse\n\n[![Version](http://img.shields.io/pypi/v/policyuniverse.svg?style=flat)](https://pypi.python.org/pypi/policyuniverse/)\n\n[![Build Status](https://github.com/Netflix-Skunkworks/policyuniverse/workflows/Python%20package/badge.svg)](https://github.com/Netflix-Skunkworks/policyuniverse/actions)\n\n[![Updater Status](https://github.com/Netflix-Skunkworks/policyuniverse/actions/workflows/updater.yml/badge.svg)](https://github.com/Netflix-Skunkworks/policyuniverse/actions/workflows/updater.yml)\n\n[![Coverage Status](https://coveralls.io/repos/github/Netflix-Skunkworks/policyuniverse/badge.svg?branch=master\u00261)](https://coveralls.io/github/Netflix-Skunkworks/policyuniverse?branch=master)\n\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)\n\nThis package provides classes to parse AWS IAM and Resource Policies.\n\nAdditionally, this package can expand wildcards in AWS Policies using permissions obtained from the AWS Policy Generator.\n\nSee the [Service and Permissions data](policyuniverse/data.json).\n\n_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._ 💩\n\n# Install:\n\n`pip install policyuniverse`\n\n# Usage:\n\n- [ARN class](#reading-arns)\n- [Policy class](#iam-and-resource-policies)\n- [Statement class](#statements)\n- [Action Categories](#action-categories)\n- [Expanding and Minification](#expanding-and-minification)\n\n## Reading ARNs\n\n```python\nfrom policyuniverse.arn import ARN\narn = ARN('arn:aws:iam::012345678910:role/SomeTestRoleForTesting')\nassert arn.error == False\nassert arn.tech == 'iam'\nassert arn.region == ''  # IAM is universal/global\nassert arn.account_number == '012345678910'\nassert arn.name == 'role/SomeTestRoleForTesting'\nassert arn.partition == 'aws'\nassert arn.root == False  # Not the root ARN\nassert arn.service == False  # Not an AWS service like lambda.amazonaws.com\n\narn = ARN('012345678910')\nassert arn.account_number == '012345678910'\n\narn = ARN('lambda.amazonaws.com')\nassert arn.service == True\nassert arn.tech == 'lambda'\n```\n\n## IAM and Resource Policies\n\n### Policy with multiple statements\n```python\n# Two statements, both with conditions\npolicy05 = dict(\n    Version='2010-08-14',\n    Statement=[\n        dict(\n            Effect='Allow',\n            Principal='arn:aws:iam::012345678910:root',\n            Action=['s3:*'],\n            Resource='*',\n            Condition={\n                'IpAddress': {\n                    'AWS:SourceIP': ['0.0.0.0/0']\n                }}),\n        dict(\n            Effect='Allow',\n            Principal='arn:aws:iam::*:role/Hello',\n            Action=['ec2:*'],\n            Resource='*',\n            Condition={\n                'StringLike': {\n                    'AWS:SourceOwner': '012345678910'\n                }})\n        ])\n\nfrom policyuniverse.policy import Policy\nfrom policyuniverse.statement import ConditionTuple, PrincipalTuple\n\npolicy = Policy(policy05)\nassert policy.whos_allowed() == set([\n    PrincipalTuple(category='principal', value='arn:aws:iam::*:role/Hello'),\n    PrincipalTuple(category='principal', value='arn:aws:iam::012345678910:root'),\n    ConditionTuple(category='cidr', value='0.0.0.0/0'),\n    ConditionTuple(category='account', value='012345678910')\n])\n\n# The given policy is not internet accessible.\n# The first statement is limited by the principal, and the condition is basically a no-op.\n# The second statement has a wildcard principal, but uses the condition to lock it down.\nassert policy.is_internet_accessible() == False\n```\n\n### Internet Accessible Policy:\n\n```python\n# An internet accessible policy:\npolicy01 = dict(\n    Version='2012-10-08',\n    Statement=dict(\n        Effect='Allow',\n        Principal='*',\n        Action=['rds:*'],\n        Resource='*',\n        Condition={\n            'IpAddress': {\n                'AWS:SourceIP': ['0.0.0.0/0']\n            }\n        }))\n\npolicy = Policy(policy01)\nassert policy.is_internet_accessible() == True\nassert policy.internet_accessible_actions() == set(['rds:*'])\n```\n\n## Statements\n\nA policy is simply a collection of statements.\n\n```python\nstatement12 = dict(\n    Effect='Allow',\n    Principal='*',\n    Action=['rds:*'],\n    Resource='*',\n    Condition={\n        'StringEquals': {\n            'AWS:SourceVPC': 'vpc-111111',\n            'AWS:Sourcevpce': 'vpce-111111',\n            'AWS:SourceOwner': '012345678910',\n            'AWS:SourceAccount': '012345678910'\n        },\n        'StringLike': {\n            'AWS:userid': 'AROAI1111111111111111:*'\n        },\n        'ARNLike': {\n            'AWS:SourceArn': 'arn:aws:iam::012345678910:role/Admin'\n        },\n        'IpAddressIfExists': {\n            'AWS:SourceIP': [\n                '123.45.67.89',\n                '10.0.7.0/24',\n                '172.16.0.0/16']\n        }\n    })\n\nfrom policyuniverse.statement import Statement\nfrom policyuniverse.statement import ConditionTuple, PrincipalTuple\n\nstatement = Statement(statement12)\nassert statement.effect == 'Allow'\nassert statement.actions == set(['rds:*'])\n\n# rds:* expands out to ~88 individual permissions\nassert len(statement.actions_expanded) == 88\n\nassert statement.uses_not_principal() == False\nassert statement.principals == set(['*'])\nassert statement.condition_arns == set(['arn:aws:iam::012345678910:role/Admin'])\nassert statement.condition_accounts == set(['012345678910'])\nassert statement.condition_userids == set(['AROAI1111111111111111:*'])\nassert statement.condition_cidrs == set(['10.0.7.0/24', '172.16.0.0/16', '123.45.67.89'])\nassert statement.condition_vpcs == set(['vpc-111111'])\nassert statement.condition_vpces == set(['vpce-111111'])\nassert statement.is_internet_accessible() == False\nassert statement.whos_allowed() == set([\n    PrincipalTuple(category='principal', value='*'),\n    ConditionTuple(category='cidr', value='123.45.67.89'),\n    ConditionTuple(category='account', value='012345678910'),\n    ConditionTuple(category='userid', value='AROAI1111111111111111:*'),\n    ConditionTuple(category='vpc', value='vpc-111111'),\n    ConditionTuple(category='arn', value='arn:aws:iam::012345678910:role/Admin'),\n    ConditionTuple(category='cidr', value='172.16.0.0/16'),\n    ConditionTuple(category='vpce', value='vpce-111111'),\n    ConditionTuple(category='cidr', value='10.0.7.0/24')])\n\n```\n\n\n## Action Categories\n```python\npolicy = {\n        \"Statement\": [{\n            \"Action\": [\"s3:put*\", \"sqs:get*\", \"sns:*\"],\n            \"Resource\": \"*\",\n            \"Effect\": \"Allow\"\n          }]\n      }\n\nfrom policyuniverse.policy import Policy\np = Policy(policy)\nfor k, v in p.action_summary().items():\n    print(k,v)\n\u003e\u003e\u003e ('s3', set([u'Write', u'Permissions', u'Tagging']))\n\u003e\u003e\u003e ('sqs', set([u'List']))\n\u003e\u003e\u003e ('sns', set([u'List', u'Read', u'Write', u'Permissions']))\n```\nPossible categories are `Permissions`, `Write`, `Read`, `Tagging`, and `List`.  This data can be used to summarize statements and policies and to look for sensitive permissions.\n\n## Expanding and Minification\n```python\nfrom policyuniverse.expander_minimizer import expand_policy\nfrom policyuniverse.expander_minimizer import minimize_policy\n\npolicy = {\n        \"Statement\": [{\n            \"Action\": [\"swf:res*\"],\n            \"Resource\": \"*\",\n            \"Effect\": \"Allow\"\n          }]\n      }\n\nexpanded_policy = expand_policy(policy=policy)\n\u003e\u003e\u003e Start size: 131. End size: 286\nprint(expanded_policy == {\n        \"Statement\": [{\n            \"Action\": [\n              \"swf:respondactivitytaskcanceled\",\n              \"swf:respondactivitytaskcompleted\",\n              \"swf:respondactivitytaskfailed\",\n              \"swf:responddecisiontaskcompleted\"\n            ],\n            \"Resource\": \"*\",\n            \"Effect\": \"Allow\"\n          }]\n      })\n\u003e\u003e\u003e True\n\nminimized_policy = minimize_policy(policy=expanded_policy, minchars=3)\n\u003e\u003e\u003e Skipping prefix r because length of 1\n\u003e\u003e\u003e Skipping prefix re because length of 2\n\u003e\u003e\u003e Skipping prefix r because length of 1\n\u003e\u003e\u003e Skipping prefix re because length of 2\n\u003e\u003e\u003e Skipping prefix r because length of 1\n\u003e\u003e\u003e Skipping prefix re because length of 2\n\u003e\u003e\u003e Skipping prefix r because length of 1\n\u003e\u003e\u003e Skipping prefix re because length of 2\n\u003e\u003e\u003e Start size: 286. End size: 131\n\nprint(minimized_policy == policy)\n\u003e\u003e\u003e True\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNetflix-Skunkworks%2Fpolicyuniverse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNetflix-Skunkworks%2Fpolicyuniverse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNetflix-Skunkworks%2Fpolicyuniverse/lists"}