Policy Sentry - IAM Least Privilege Policy Generator
Tags: aws, security, tutorial, cloud
Published: 2022-06-07 14:48:46

<!-- wp:paragraph -->
<p>In our last blog post, we read about <a href="https://qainsights.com/cloudsplaining-aws-iam-security-assessment-tool/" target="_blank" rel="noreferrer noopener">Cloudsplaining</a> - AWS IAM Security Assessment Tool from Salesforce OSS. I have mentioned that Cloudsplaining is a reactive tool whereas Policy Sentry is a preventive tool to write secured least privileged IAM Policies in AWS. In this blog post, we are going to deep-dive into Policy Sentry.</p>
<!-- /wp:paragraph -->

<!-- wp:generateblocks/headline {"uniqueId":"43994e4d"} -->
<h2 class="gb-headline gb-headline-43994e4d gb-headline-text">Policy Sentry</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>Handcrafting IAM policies is cumbersome, especially from a security perspective. Enter Policy Sentry - a Python utility to generate the least privilege IAM policy for AWS.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>It is an <a href="https://github.com/salesforce/policy_sentry" target="_blank" rel="noreferrer noopener">open source initiative</a> from Salesforce. Using Policy Sentry, it is easy to automate the creation of IAM policies with little knowledge on security.</p>
<!-- /wp:paragraph -->

<!-- wp:generateblocks/headline {"uniqueId":"844d9c95"} -->
<h2 class="gb-headline gb-headline-844d9c95 gb-headline-text">Getting Started</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>The only prerequisite to installing Policy Sentry is to have the latest version of Python with pip3. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Enter the below command which will install Policy Sentry in Windows.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>pip3 install --user policy_sentry</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For MacOS, use:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>brew tap salesforce/policy_sentry https://github.com/salesforce/policy_sentry<br>brew install policy_sentry</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To validate the installation, enter:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>policy_sentry --version</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For bash, auto complete:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>eval "$(_POLICY_SENTRY_COMPLETE=source policy_sentry)"</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For zsh, auto complete:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>eval "$(_POLICY_SENTRY_COMPLETE=source_zsh policy_sentry)"</code></p>
<!-- /wp:paragraph -->

<!-- wp:generateblocks/headline {"uniqueId":"82a421df"} -->
<h2 class="gb-headline gb-headline-82a421df gb-headline-text">Hello S3 Policy</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>Let us begin creating a new IAM policy to read the S3 buckets using Policy Sentry. The first step is to generate a template.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>There are two types of templates available in Policy Sentry:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>actions</li><li>CRUD</li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Enter the below command to create a template using crud type.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>policy_sentry create-template --template-type crud --output-file readonlyS3.yaml</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Open the <code>readonlyS3.yaml</code> in your favorite editor and add the ARN as shown below.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a S3 bucket e.g. <code>policy-sentry-demo-bucket</code> and add some dummy files for testing purpose. </p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>mode: crud
name: 'readonlyS3'
# Specify resource ARNs
read:
- 'arn:aws:s3:::policy-sentry-demo-bucket'
list:
- 'arn:aws:s3:::policy-sentry-demo-bucket'
# If this policy needs to include an AssumeRole action
sts:
  assume-role:
    - 'arn:aws:iam::1234567890:role/policy_sentry_demo_role'</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The next step is to generate an IAM policy using this template. Issue the below command to generate the IAM policy.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>policy_sentry write-policy --input-file readonlyS3.yaml &gt; readonlyS3_policy.json</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you print the contents of <code>readonlyS3_policy.json</code>, it will display as shown below.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>{
    "Version": "2012-10-17",
    "Statement": &#91;
        {
            "Sid": "S3ReadBucket",
            "Effect": "Allow",
            "Action": &#91;
                "s3:GetAccelerateConfiguration",
                "s3:GetAnalyticsConfiguration",
                "s3:GetBucketAcl",
                "s3:GetBucketCORS",
                "s3:GetBucketLocation",
                "s3:GetBucketLogging",
                "s3:GetBucketNotification",
                "s3:GetBucketObjectLockConfiguration",
                "s3:GetBucketOwnershipControls",
                "s3:GetBucketPolicy",
                "s3:GetBucketPolicyStatus",
                "s3:GetBucketPublicAccessBlock",
                "s3:GetBucketRequestPayment",
                "s3:GetBucketTagging",
                "s3:GetBucketVersioning",
                "s3:GetBucketWebsite",
                "s3:GetEncryptionConfiguration",
                "s3:GetIntelligentTieringConfiguration",
                "s3:GetInventoryConfiguration",
                "s3:GetLifecycleConfiguration",
                "s3:GetMetricsConfiguration",
                "s3:GetReplicationConfiguration"
            ],
            "Resource": &#91;
                "arn:aws:s3:::policy-sentry-demo-bucket"
            ]
        },
        {
            "Sid": "S3ListBucket",
            "Effect": "Allow",
            "Action": &#91;
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:ListBucketVersions"
            ],
            "Resource": &#91;
                "arn:aws:s3:::policy-sentry-demo-bucket"
            ]
        },
        {
            "Sid": "AssumeRole",
            "Effect": "Allow",
            "Action": &#91;
                "sts:AssumeRole"
            ],
            "Resource": &#91;
                "arn:aws:iam::1234567890:role/policy_sentry_demo_role"
            ]
        }
    ]
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The next step is to generate a policy. Assuming you have the AWS CLI configured with valid privileges.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>aws iam create-policy --policy-name policysentry_demo_s3 --policy-document file://readonlyS3_policy.json</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Copy the ARN from the output. The next step is to create an IAM role.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To create an IAM Role, we need a trust document. The below command will create a <code>trust.json</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>cat &lt;&lt; 'EOF' &gt; trust.json
{
  "Version": "2012-10-17",
  "Statement": &#91;
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::1234567890:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>After creating <code>trust.json</code>, enter the below command which will create a role.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>aws iam create-role --role-name policy_sentry_demo_role --assume-role-policy-document file://trust.json</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Copy the role ARN which we will need it for testing.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The next step is to attach the created policy <code>policysentry_demo_s3</code> using the below command.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>aws iam attach-role-policy --role-name policy_sentry_demo_role --policy-arn arn:aws:iam::1234567890:policy/policysentry_demo_s3</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Congratulations! You just created least privileged IAM policy using Policy Sentry. Let us put this into action.</p>
<!-- /wp:paragraph -->

<!-- wp:generateblocks/headline {"uniqueId":"3d6146d3"} -->
<h2 class="gb-headline gb-headline-3d6146d3 gb-headline-text">Testing the IAM Policy</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>Enter the below command to get the temp credentials:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>aws sts assume-role --role-arn arn:aws:iam::1234567890:role/policy_sentry_demo_role --role-session-name policy_sentry_demo</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Copy the access key, secret access, and the token and create the below environment variables in *nx OS, in case of Windows, use <code>set</code> command.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>export AWS_ACCESS_KEY_ID=ASIAS6WEREROPETNGKNLOIEF</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>export AWS_SECRET_ACCESS_KEY=Isdff3rtdfg344fdgh31123ghjyjkiuolGQzxTN7znDwTEdfgdfgX4</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjENL//////////wEaCXVzLWVhc3QtMiJHMEUCIQD6AFLxIVfsoX7OH0Ta5xb6snPAAJWDFvLFu2BodaoCEgIgCugSJ0Th19QZPhK7FFIRqyGzCXGoq2GKLJNrjgR9AePbAURrLalHEoDnhv/sHWXPE3/Z0piRFH/IK73nk8vNA=</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, issue the aws s3 list command, you will get the below error.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9485,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/06/image-8.png"><img src="https://qainsights.com/wp-content/uploads/2022/06/image-8.png" alt="ListBuckets error" class="wp-image-9485"/></a><figcaption>ListBuckets error</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>But if you list the exact bucket name, it will work as shown below.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9486,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/06/image-9.png"><img src="https://qainsights.com/wp-content/uploads/2022/06/image-9.png" alt="s3 access" class="wp-image-9486"/></a><figcaption>s3 access</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>If you are not able to list the bucket or getting any other error, this video will be <a href="https://youtu.be/-uogKFE1r60" target="_blank" rel="noreferrer noopener nofollow">helpful</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:generateblocks/headline {"uniqueId":"2246f367"} -->
<h2 class="gb-headline gb-headline-2246f367 gb-headline-text">Helpful Commands</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>Below are the commands that will be helpful to learn. It is a shameless copy from the repo.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code># Create templates first!!! This way you can just paste the values you need rather than remembering the YAML format
# CRUD mode
policy_sentry create-template --output-file tmp.yml --template-type crud
# Actions mode
policy_sentry create-template --output-file tmp.yml --template-type actions

# Write policy based on resource-specific access levels
policy_sentry write-policy --input-file examples/yml/crud.yml

# Write policy based on a list of actions
policy_sentry write-policy --input-file examples/yml/actions.yml


###############
# Actions Table
###############
# NOTE: Use --fmt yaml or --fmt json to change the output format. Defaults to json for querying

# Get a list of actions that do not support resource constraints
policy_sentry query action-table --service s3 --resource-type "*" --fmt yaml

# Get a list of actions at the "Write" level in S3 that do not support resource constraints
policy_sentry query action-table --service s3 --access-level write --resource-type "*" --fmt yaml

# Get a list of all IAM actions across ALL services that have "Permissions management" access
policy_sentry query action-table --service all --access-level permissions-management

# Get a list of all IAM Actions available to the RAM service
policy_sentry query action-table --service ram

# Get details about the `ram:TagResource` IAM Action
policy_sentry query action-table --service ram --name tagresource

# Get a list of all IAM actions under the RAM service that have the Permissions management access level.
policy_sentry query action-table --service ram --access-level permissions-management

# Get a list of all IAM actions under the SES service that support the `ses:FeedbackAddress` condition key.
policy_sentry query action-table --service ses --condition ses:FeedbackAddress

###########
# ARN Table
###########

# Get a list of all RAW ARN formats available through the SSM service.
policy_sentry query arn-table --service ssm

# Get the raw ARN format for the `cloud9` ARN with the short name `environment`
policy_sentry query arn-table --service cloud9 --name environment

# Get key/value pairs of all RAW ARN formats plus their short names
policy_sentry query arn-table --service cloud9 --list-arn-types

######################
# Condition Keys Table
######################

# Get a list of all condition keys available to the Cloud9 service
policy_sentry query condition-table --service cloud9

# Get details on the condition key titled `cloud9:Permissions`
policy_sentry query condition-table --service cloud9 --name cloud9:Permissions

# Initialize the policy_sentry config folder and create the IAM database tables.
policy_sentry initialize

# Fetch the most recent version of the AWS documentation so you can experiment with new services.
policy_sentry initialize --fetch

# Override the Access Levels by specifying your own Access Levels (example:, correcting Permissions management levels)
policy_sentry initialize --access-level-overrides-file ~/.policy_sentry/overrides-resource-policies.yml

policy_sentry initialize --access-level-overrides-file ~/.policy_sentry/access-level-overrides.yml</code></pre>
<!-- /wp:code -->

<!-- wp:generateblocks/headline {"uniqueId":"4d1f8e4e"} -->
<h2 class="gb-headline gb-headline-4d1f8e4e gb-headline-text">Other Features</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>If you are a fan of Terraform, please check this <a href="https://github.com/kmcquade/terraform-aws-policy-sentry" target="_blank" rel="noreferrer noopener">repo</a>. If you are into Docker, use <code>docker build -t kmcquade/policy_sentry .</code> to get started.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Policy Sentry comes with a querying feature where you can query the IAM database (action, ARN, and condition table), refer to the above commands. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To fetch the latest IAM database info, start with (optional steps):</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>policy_sentry initialize</code></p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9488,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/06/image-10.png"><img src="https://qainsights.com/wp-content/uploads/2022/06/image-10.png" alt="Policy Sentry Initialize" class="wp-image-9488"/></a><figcaption>Policy Sentry Initialize</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><code>policy_sentry initialize --fetch</code> command will fetch all the latest AWS services if you want to play around.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9489,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/06/image-11.png"><img src="https://qainsights.com/wp-content/uploads/2022/06/image-11.png" alt="Policy Sentry Fetch" class="wp-image-9489"/></a><figcaption>Policy Sentry Fetch</figcaption></figure>
<!-- /wp:image -->

<!-- wp:generateblocks/headline {"uniqueId":"845eb831"} -->
<h2 class="gb-headline gb-headline-845eb831 gb-headline-text">Final Thoughts</h2>
<!-- /wp:generateblocks/headline -->

<!-- wp:paragraph -->
<p>Policy Sentry is a great utility to automate and manage IAM entities. It helps to mitigate security mishaps as it allows us to grant fine-grained access. The Policy Sentry library helps if you want to develop your custom scripts. If you face any issues or request a new feature, please check the GitHub <a href="https://github.com/salesforce/policy_sentry/" target="_blank" rel="noreferrer noopener nofollow">repo</a>.</p>
<!-- /wp:paragraph -->