• Stars
    star
    986
  • Rank 45,311 (Top 1.0 %)
  • Language
    Python
  • License
    BSD 3-Clause "New...
  • Created almost 5 years ago
  • Updated 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

AWS IAM linting library

parliament is an AWS IAM linting library. It reviews policies looking for problems such as:

  • malformed json
  • missing required elements
  • incorrect prefix and action names
  • incorrect resources or conditions for the actions provided
  • type mismatches
  • bad policy patterns

This library duplicates (and adds to!) much of the functionality in the web console page when reviewing IAM policies in the browser. We wanted that functionality as a library.

demo

Installation

pip install parliament

Usage

cat > test.json << EOF
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action":["s3:GetObject"],
        "Resource": ["arn:aws:s3:::bucket1"]
    }
}
EOF

parliament --file test.json

This will output:

MEDIUM - No resources match for the given action -  - [{'action': 's3:GetObject', 'required_format': 'arn:*:s3:::*/*'}] - {'actions': ['s3:GetObject'], 'filepath': 'test.json'}

This example is showing that the action s3:GetObject requires a resource matching an object path (ie. it must have a "/" in it).

The different input types allowed include:

  • --file: Filename
  • --directory: A directory path, for exmaple: --directory . --include_policy_extension json --exclude_pattern ".*venv.*"
  • --aws-managed-policies: For use specifically with the repo https://github.com/z0ph/aws_managed_policies
  • --auth-details-file: For use with the file returned by "aws iam get-account-authorization-details"
  • --string: Provide a string such as '{"Version": "2012-10-17","Statement": {"Effect": "Allow","Action": ["s3:GetObject", "s3:PutBucketPolicy"],"Resource": ["arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2/*"]}}'

Using parliament as a library

Parliament was meant to be used a library in other projects. A basic example follows.

from parliament import analyze_policy_string

analyzed_policy = analyze_policy_string(policy_doc)
for f in analyzed_policy.findings:
  print(f)

Custom config file

You may decide you want to change the severity of a finding, the text associated with it, or that you want to ignore certain types of findings. To support this, you can provide an override config file. First, create a test.json file:

{
    "Version": "2012-10-17",
    "Id": "123",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": "s3:abc",
        "Resource": "*"
      },
      {
        "Effect": "Allow",
        "Action": ["s3:*", "ec2:*"],
        "Resource": "arn:aws:s3:::test/*"
      }
    ]
 }

This will have two findings:

  • LOW - Unknown action - - Unknown action s3:abc
  • MEDIUM - No resources match for the given action

The second finding will be very long, because every s3 and ec2 action are expanded and most are incorrect for the S3 object path resource that is provided.

Now create a file config_override.yaml with the following contents:

UNKNOWN_ACTION:
  severity: MEDIUM
  ignore_locations:
  - filepath:
    - testa.json
    - .*.py

RESOURCE_MISMATCH:
  ignore_locations:
  - actions: ".*s3.*"

Now run: parliament --file test.json --config config_override.yaml You will have only one output: MEDIUM - Unknown action - - Unknown action s3:abc

Notice that the severity of that finding has been changed from a LOW to a MEDIUM. Also, note that the other finding is gone, because the previous RESOURCE_MISMATCH finding contained an actions element of ["s3:*", "ec2:*"]. The ignore logic converts the value you provide, and the finding value to lowercase, and then uses your string as a regex. This means that we are checking if s3 is in str(["s3:*", "ec2:*"])

Now rename test.json to testa.json and rerun the command. You will no longer have any output, because we are filtering based on the filepath for UNKNOWN_ACTION and filtering for any filepaths that contain testa.json or .py.

You can also check the exit status with echo $? and see the exit status is 0 when there are no findings. The exit status will be non-zero when there are findings.

You can have multiple elements in ignore_locations. For example,

- filepath: "test.json"
  action: "s3:GetObject"
  resource: 
  - "a"
  - "b"
- resource: "c.*"

Assuming the finding has these types of values in the location element, this will ignore any finding that matches the filepath to "test.json" AND action to "s3:GetObject" AND the resource to "a" OR "b". It will also ignore a resource that matches "c.*".

Custom auditors

Private Auditors

This section will show how to create your own private auditor to look for any policies that grant access to either of the sensitive buckets secretbucket and othersecretbucket.

Create a file test.json with contents:

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::secretbucket/*"
    }
}

This is an example of the policy we want to alert on. That policy will normally not generate any findings.

Create the file config_override.yaml with contents:

SENSITIVE_BUCKET_ACCESS:
  title: Sensitive bucket access
  description: Allows read access to an important S3 bucket
  severity: MEDIUM
  group: CUSTOM

In the parliament directory (that contains iam_definition.json), create the directory private_auditors and the file parliament/private_auditors/sensitive_bucket_access.py

from parliament import is_arn_match, expand_action

def audit(policy):
    action_resources = {}
    for action in expand_action("s3:*"):
        # Iterates through a list of containing elements such as
        # {'service': 's3', 'action': 'GetObject'}
        action_name = "{}:{}".format(action["service"], action["action"])
        action_resources[action_name] = policy.get_allowed_resources(action["service"], action["action"])
    
    for action_name in action_resources:
        resources = action_resources[action_name]
        for r in resources:
            if is_arn_match("object", "arn:aws:s3:::secretbucket*", r) or is_arn_match("object", "arn:aws:s3:::othersecretbucket*", r):
                policy.add_finding("SENSITIVE_BUCKET_ACCESS", location={"action": action_name, "resource": r})

This will look for any s3 access to the buckets of interest, including not only object access such as s3:GetObject access, but also things like s3:PutBucketAcl.

Running against our test file, we'll get the following output:

./bin/parliament --file test.json --config config_override.yaml --json

{"issue": "SENSITIVE_BUCKET_ACCESS", "title": "Sensitive bucket access", "severity": "MEDIUM", "description": "Allows read access to an important S3 bucket", "detail": "", "location": {"action": "s3:GetObject", "resource": "arn:aws:s3:::secretbucket/*", "filepath": "test.json"}}

You can now decide if this specific situation is ok for you, and choose to ignore it by modifying the config_override.yaml to include:

ignore_locations:
  - filepath: "test.json"
    action: "s3:GetObject"
    resource: "arn:aws:s3:::secretbucket/\\*"

Notice that I had to double-escape the escape asterisk. If another policy is created, say in test2.json that you'd like to ignore, you can just append those values to the list:

ignore_locations:
  - filepath: "test.json"
    action: "s3:GetObject"
    resource: "arn:aws:s3:::secretbucket/\\*"
  - filepath: "test2.json"
    action: "s3:GetObject"
    resource: "arn:aws:s3:::secretbucket/\\*"

Or you could do:

ignore_locations:
  - filepath:
    - "test.json"
    - "test2.json"
    action: "s3:GetObject"
    resource: "arn:aws:s3:::secretbucket/\\*"

Unit tests for private auditors

To create unit tests for our new private auditor, create the directory ./parliament/private_auditors/tests/ and create the file test_sensitive_bucket_access.py there with the contents:

from parliament import analyze_policy_string

class TestCustom():
    """Test class for custom auditor"""

    def test_my_auditor(self):
        policy = analyze_policy_string(
            """{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::secretbucket/*"}}""",
        )
        assert_equal(len(policy.findings), 1)

That test ensures that for the given policy (which is granting read access to our secret bucket) one finding will be created.

Now when you run ./tests/scripts/unit_tests.sh there should be one additional test run.

Community auditors

  • The process for community auditors is the same as private auditors, except that:
  • The community auditors are located in the parliament/community_auditors folder instead of the parliament/private_auditors
  • The community auditors are bundled with the package and users can include them in their testing by specifying --include-community-auditors flag.

Development

Setup a testing environment

python3 -m venv ./venv && source venv/bin/activate
pip3 install -r requirements.txt

Run unit tests with:

make test

Run locally as:

bin/parliament

Updating the privilege info

The IAM data is obtained from scraping the docs here and parsing this information with beautifulsoup using ./utils/update_iam_data.py.

Projects that use Parliament

  • CloudMapper: Has functionality to audit AWS environments and will audit the IAM policies as part of that.
  • tf-parliament: Runs Parliament against terraform files
  • iam-lint: Github action for linting AWS IAM policy documents
  • Paco: Cloud orchestration tool that integrates Parliament as a library to verify a project's IAM Policies and warns about findings.
  • ConsoleMe: Web service that makes administering and using multiple AWS accounts easier, that uses Parliament for linting IAM Policies
  • iamlive: Generates IAM Policies from observing AWS calls through client-side monitoring

More Repositories

1

cloudmapper

CloudMapper helps you analyze your Amazon Web Services (AWS) environments.
JavaScript
5,845
star
2

webauthn

WebAuthn (FIDO2) server library written in Go
Go
1,023
star
3

cloudtracker

CloudTracker helps you find over-privileged IAM users and roles by comparing CloudTrail logs with current IAM policies.
Python
871
star
4

py_webauthn

Pythonic WebAuthn
Python
801
star
5

webauthn.io

The source code for webauthn.io, a demonstration of WebAuthn.
Python
619
star
6

EFIgy

A small client application that uses the Duo Labs EFIgy API to inform you about the state of your Mac EFI firmware
Python
508
star
7

dlint

Dlint is a tool for encouraging best coding practices and helping ensure we're writing secure Python code.
Python
331
star
8

markdown-to-confluence

Syncs Markdown files to Confluence
Python
294
star
9

isthislegit

Dashboard to collect, analyze, and respond to reported phishing emails.
Python
284
star
10

idapython

A collection of IDAPython modules made with πŸ’š by Duo Labs
Python
274
star
11

chrome-extension-boilerplate

Boilerplate code for a Chrome extension using TypeScript, React, and Webpack.
TypeScript
208
star
12

secret-bridge

Monitors Github for leaked secrets
Python
184
star
13

apple-t2-xpc

Tools to explore the XPC interface of Apple's T2 chip
Python
152
star
14

twitterbots

The code used in the "Don't @ Me: Hunting Twitter Bots at Scale" Black Hat presentation
Python
152
star
15

cloudtrail-partitioner

Python
147
star
16

phish-collect

Python script to hunt phishing kits
Python
136
star
17

phinn

A toolkit to generate an offline Chrome extension to detect phishing attacks using a bespoke convolutional neural network.
JavaScript
129
star
18

xray

X-Ray allows you to scan your Android device for security vulnerabilities that put your device at risk.
Java
122
star
19

android-webauthn-authenticator

A WebAuthn Authenticator for Android leveraging hardware-backed key storage and biometric user verification.
Java
110
star
20

appsec-education

Presentations, training modules, and other education materials from Duo Security's Application Security team.
JavaScript
67
star
21

mysslstrip

CVE-2015-3152 PoC
Python
43
star
22

EFIgy-GUI

A Mac app that uses the Duo Labs EFIgy API to inform you about the state of your EFI firmware.
Objective-C
39
star
23

lookalike-domains

generate lookalike domains using a few simple techniques (homoglyphs, alt TLDs, prefix/suffix)
Python
30
star
24

journal

The boilerplate for a new Journal site
21
star
25

srtgen

Automatic '.srt' subtitle generator
Python
21
star
26

apk2java

Automatically decompile APK's using Docker
Dockerfile
21
star
27

neustar2mmdb

Tool to convert Neustar's GeoPoint data to Maxmind's GeoIP database format for ease of use.
Python
19
star
28

markflow

Make your Markdown sparkle!
Python
18
star
29

narrow

Low-effort reachability analysis for third-party code vulnerabilities.
Python
18
star
30

tutorials

Python
15
star
31

duo-blog-going-passwordless-with-py-webauthn

Python
14
star
32

datasci-ctf

A capture-the-flag exercise based on data analysis challenges
Jupyter Notebook
14
star
33

chain-of-fools

A set of tools that allow researchers to experiment with certificate chain validation issues
Python
13
star
34

sharedsignals

Python tools for using OpenID's Shared Signals Framework (including CAEP)
12
star
35

journal-cli

The command-line client for Journal
Jupyter Notebook
12
star
36

unmasking_data_leaks

The code from the talk "Unmasking Data Leaks: A Guide to Finding, Fixing, and Prevention" given at BSides SATX 2019.
Python
7
star
37

journal-theme

The Hugo theme that powers Journal
HTML
7
star
38

golang-workshop

Source files for a Golang Workshop
Go
5
star
39

journal-docs

The documentation for Journal
2
star
40

dlint-plugin-example

An example plugin for dlint
Python
2
star
41

vimes

A local DNS proxy based on CoreDNS.
Python
2
star
42

twitterbots-wallpapers

Wallpapers created from the crawlers in our "Don't @ Me" technical research paper
1
star
43

holidayhack-2019

Scripts and artifacts used to solve the 2019 SANS Holiday Hack Challenge
Python
1
star