Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Netflix-Skunkworks/policyuniverse
Parse and Process AWS IAM Policies, Statements, ARNs, and wildcards.
https://github.com/Netflix-Skunkworks/policyuniverse
security
Last synced: 7 days ago
JSON representation
Parse and Process AWS IAM Policies, Statements, ARNs, and wildcards.
- Host: GitHub
- URL: https://github.com/Netflix-Skunkworks/policyuniverse
- Owner: Netflix-Skunkworks
- License: apache-2.0
- Created: 2017-05-15T17:51:11.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2024-01-06T05:39:26.000Z (10 months ago)
- Last Synced: 2024-04-14T06:01:47.196Z (7 months ago)
- Topics: security
- Language: Python
- Homepage:
- Size: 11.8 MB
- Stars: 414
- Watchers: 125
- Forks: 61
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-cloudops - PolicyUniverse - Skunkworks/policyuniverse?label=%E2%AD%90%EF%B8%8F&logo=github" alt="Stars"><br><img align="right" src="https://img.shields.io/github/issues-raw/Netflix-Skunkworks/policyuniverse" alt="Issues"><br><img align="right" src="https://img.shields.io/github/last-commit/Netflix-Skunkworks/policyuniverse">](https://github.com/Netflix-Skunkworks/policyuniverse) | <img align="right" src="https://img.shields.io/badge/-aws-orange" alt="AWS"> | This package provides classes to parse AWS IAM and Resource Policies. | This package provides classes to parse AWS IAM and Resource Policies. | (Tools)
- awesome-github-repos - Netflix-Skunkworks/policyuniverse - Parse and Process AWS IAM Policies, Statements, ARNs, and wildcards. (Python)
- awesome-cloud-security - PolicyUniverse
README
# PolicyUniverse
[![Version](http://img.shields.io/pypi/v/policyuniverse.svg?style=flat)](https://pypi.python.org/pypi/policyuniverse/)
[![Build Status](https://github.com/Netflix-Skunkworks/policyuniverse/workflows/Python%20package/badge.svg)](https://github.com/Netflix-Skunkworks/policyuniverse/actions)
[![Updater Status](https://github.com/Netflix-Skunkworks/policyuniverse/actions/workflows/updater.yml/badge.svg)](https://github.com/Netflix-Skunkworks/policyuniverse/actions/workflows/updater.yml)
[![Coverage Status](https://coveralls.io/repos/github/Netflix-Skunkworks/policyuniverse/badge.svg?branch=master&1)](https://coveralls.io/github/Netflix-Skunkworks/policyuniverse?branch=master)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/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](policyuniverse/data.json).
_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:
- [ARN class](#reading-arns)
- [Policy class](#iam-and-resource-policies)
- [Statement class](#statements)
- [Action Categories](#action-categories)
- [Expanding and Minification](#expanding-and-minification)## Reading ARNs
```python
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.comarn = 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
```python
# 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, PrincipalTuplepolicy = 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:
```python
# 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.
```python
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, PrincipalTuplestatement = Statement(statement12)
assert statement.effect == 'Allow'
assert statement.actions == set(['rds:*'])# rds:* expands out to ~88 individual permissions
assert len(statement.actions_expanded) == 88assert 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
```python
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
```python
from policyuniverse.expander_minimizer import expand_policy
from policyuniverse.expander_minimizer import minimize_policypolicy = {
"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"
}]
})
>>> Trueminimized_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: 131print(minimized_policy == policy)
>>> True
```