Access Undenied parses AWS AccessDenied CloudTrail events, explains the reasons for them, and offers actionable remediation steps. Open-sourced by Ermetic.

Overview

Access Undenied on AWS

Access Undenied parses AWS AccessDenied CloudTrail events, explains the reasons for them, and offers actionable fixes.

Twitter

Gif demonstrating an example of using AccessUndenied

Overview

Access Undenied analyzes AWS CloudTrail AccessDenied events, scans the environment to identify and explain the reasons for them, and offers actionable least-privilege remediation suggestions.

Common use cases

Sometimes, the new and more detailed AccessDenied messages provided by AWS will be sufficient. However, that is not always the case.

  1. Some AccessDenied messages do not provide details. Among the services with (many or exclusively) undetailed messages are: S3, SSO, EFS, EKS, GuardDuty, Batch, SQS, and many more.
  2. When the reason for AccessDenied is an explicit deny, it can be difficult to track down and evaluate every relevant policy.
  3. Specifically when the reason is an explicit deny in a service control policy (SCP), one has to find and every single policy in the organization that applies to the account.
  4. When the problem is a missing Allow statement, AccessUndenied automatically offers a least-privilege policy based on the CloudTrail event.

Simple Startup

Install AccessUndenied:

pip install access-undenied-aws

Analyze a CloudTrail event file:

access-undenied-aws --file event_history.json

Installation

Installation from pip

python -m pip install access-undenied-aws 

Installation from source code (development)

To install from source code, you can set up a venv (optionally), and within that venv.

python -m pip install --editable .

Usage

Getting events

Access Undenied works by analyzing a CloudTrail event where access was denied and the error code is either AccessDenied or Client.UnauthorizedOperation, it works on an input of one or more CloudTrail events. You can get them from wherever you get events, they can be found in the event history in the console, or by the LookupEvents API, or through whatever system you use in order to filter and detect events: Athena, Splunk, others. You can either download the records file (the default format for multiple events) or just copy and paste a single event. For examples of how to do this:

Permissions

Access Undenied runs with the default permissions of the environment running the cli command, and accepts the --profile flag for using a different profile from .aws/credentials.

access-undenied-aws --profile my-profile analyze --events-file cloudtrail_events.json

(note that the location of the profile flag must be before the sub-command (which in this case is analyze).

The role running access-undenied-aws should be granted the appropriate permissions, to do so:

  1. Attach the SecurityAudit managed policy.
  2. If you would like to scan cross-account assets and analyze service control policies, attach the following inline policy. This policy allows AccessUndenied to assume roles in your other accounts:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AccessUndeniedAssumeRole",
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": [
        "arn:aws:iam::<management_account_id>:role/AccessUndeniedRole",
        "arn:aws:iam::<account_1_id>:role/AccessUndeniedRole",
        "arn:aws:iam::<account_2_id>:role/AccessUndeniedRole",
        "..."
      ]
    }
  ]
}

If you do not wish to attach SecurityAudit, you may instead attach the updating least-privilege AccessUndenied policy.

Same account assets only, no SCPs

When both the resource and the principal are in the same account as the credentials used to run AccessUndenied and Service Control Policies (SCPs) do not need to be considered, it is sufficient to just run AccessUndenied with default credentials or a profile, and you do not need to set up any additional profiles.

Cross-account assets and SCPs

To consider assets in multiple accounts and/or SCPs in the management account, we need to set up AWS cross-account roles with the same policy and the same name as each other (the default is AccessUndeniedRole)

when setting up these roles, remember to set up the appropriate trust policy (trusting the credentials in the source account, the one you're running AccessUndenied in):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<source_account>:role/AccessUndeniedRole"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}

Attach SecurityAudit managed policy to the identity , or the updating least-privilege AccessUndenied policy

CLI Commands

Simplest command

access-undenied-aws analyze --events-file cloudtrail_events.json

All options:

Options:
  -v, --verbosity LVL  Either CRITICAL, ERROR, WARNING, INFO or DEBUG
  --profile TEXT       the AWS profile to use (default is default profile)
  --help               Show this message and exit.

Commands:
  analyze   Analyzes AWS CloudTrail events and explains the reasons for...
  get-scps  Writes the organization's SCPs and organizational tree to a file

Analyze

This command is used to analyze AccessDenied events. It can be used either with the management-account-role-arn parameter to retrieve SCPs, or with the scp-file parameter to use a policy data file created by the get_scps command.

Options:
  --events-file FILENAME          input file of CloudTrail events  [required]
  --scp-file TEXT                 Service control policy data file generated
                                  by the get_scps command.
  --management-account-role-arn TEXT
                                  a cross-account role in the management
                                  account of the organization, which must be
                                  assumable by your credentials.
  --cross-account-role-name TEXT  The name of the cross-account role for
                                  AccessUndenied to assume. default:
                                  AccessUndeniedRole
  --output-file TEXT              output file for results (default: no output
                                  to file)
  --suppress-output / --no-suppress-output
                                  should output to stdout be suppressed
                                  (default: not suppressed)
  --help                          Show this message and exit.

Example:

access-undenied-aws analyze --events-file events_file.json

Get SCPs

This command is used to writes the organization's SCPs and organizational tree to an organizational policy data file. This command should be run from the management account.

Options:
  --output-file TEXT  output file for scp data (default: scp_data.json)
  --help              Show this message and exit.

Example:

access-undenied-aws get-scps

Then when running analyzing (from the same account or a different account)

access-undenied-aws analyze --events-file events_file.json --scp-file scp_data.json

Output Format

{
  "EventId": "55555555-12ad-4f70-9140-d44428038119",
  "AssessmentResult": "Missing allow in an identity-based policy",
  "ResultDetails": {
    "PoliciesToAdd": [
      {
        "AttachmentTargetArn": "arn:aws:iam::123456789012:role/MyRole",
        "Policy": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": "rds:DescribeDBInstances",
              "Resource": "arn:aws:rds:ap-northeast-3:123456789012:db:*"
            }
          ]
        }
      }
    ]
  }
}

This output for example, tells us that access was denied because of there is no Allow statement in an identity-based policy. To remediate, we should attach to the IAM role arn:aws:iam::123456789012:role/MyRole the policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "rds:DescribeDBInstances",
      "Resource": "arn:aws:rds:ap-northeast-3:123456789012:db:*"
    }
  ]
}

Output Fields

AccessDeniedReason:

The reason why access was denied. Possible Values

Missing allow in:

  • Identity policy
  • Resource policy (in cross-account access)
  • Both (in cases of cross-account access)
  • Permissions boundary
  • Service control policy (with allow-list SCP strategy)

Explicit deny from:

  • Identity policy
  • Resource policy
  • Permissions boundary
  • Service control policy

Invalid action:

  • a principal or action that cannot be simulated by access undenied.

"Allowed" An "Allowed" result means that access undenied couldn't find the reason for AccessDenied, this could be for a variety of reasons:

  • Policies, resources and/or identities have changed since the CloudTrail event and access now actually allowed
  • Unsupported resource policy type
  • Unsupported policy type (VPC endpoint policy, session policy, etc.)
  • Unsupported condition key

ResultDetails

These are the details of the result, explaining the remediation steps, this section may contain either PoliciesToAdd or ExplicitDenyPolicies.

PoliciesToAdd

These are the policies which need to be added to enable least-privilege access. Each policy contains:

  • AttachmentTargetArn: the entity to which the new policy should be attached
  • Policy: The content of the policy to be added
ExplicitDenyPolicies

These are the policies cause explicit deny, which need to be removed or modified to facilitate access. AccessUndenied also gives the specific statement causing the Deny outcome.

  • AttachmentTargetArn: the entity to which the policy causing explicit deny is currently attached
  • PolicyArn: The arn (if applicable) of the policy causing explicit deny. For the sake of convenience, resource policies are represented by generic placeholder arns such as: arn:aws:s3:::my-bucket/S3BucketPolicy
  • PolicyName: The policy name, if applicable. Resource policies are represented by generic placeholder names such as S3BucketPolicy
  • PolicyStatement: The specific statement in the aforementioned policy causing explicit deny

Acknowledgements

This project makes use of Ian Mckay's iam-dataset Ben Kehoe's aws-error-utils.

Appendices

Running AccessUndenied from a Lambda function

Full README here

Setting up a venv

python -m venv .venv
Platform Shell Command to activate virtual environment
POSIX bash/zsh $ source .venv/bin/activate
fish $ source .venv/bin/activate.fish
csh/tcsh $ source .venv/bin/activate.csh
PowerShell Core $ .venv/bin/Activate.ps1
Windows cmd.exe C:> .venv\Scripts\activate.bat
PowerShell PS C:> .venv\Scripts\Activate.ps1

Getting CloudTrail events via the LookupEvents API with the CLI

This section is directly based on this AWS support page. It has been adapted so that the command outputs raw events rather than an ascii table.

  1. Run the following AWS CLI command:
aws cloudtrail lookup-events --start-time "yyyy-mm-ddThh:mm:ss+0000" --end-time "yyyy-mm-ddThh:mm:ss+0000" \
  --query "Events[*].CloudTrailEvent" --output text | jq -r ". | \
  select(.userIdentity.arn == \"arn:aws:sts::123456789012:assumed-role/role-name/role-session-name\" \
  and .eventType == \"AwsApiCall\" and .errorCode != null \
  and (.errorCode | ascii_downcase | (contains(\"accessdenied\") or contains(\"unauthorized\"))))" | \
  jq -s '{Records:.}' > lookup_events_output.json

Note: The rate of lookup requests to CloudTrail is limited to one request per second per account. If you exceed this limit, then a throttling error occurs.

You can get errors for all users by removing this line:

.userIdentity.arn == \"arn:aws:sts::123456789012:assumed-role/role-name/role-session-name\" and

The command outputs errors to lookup_events_output.json, which can be analyzed by Access Undenied (using additional parameters as needed).

access-undenied-aws analyze --events-file lookup_events_output.json

Getting CloudTrail events from the AWS Console's event history

  1. Open the AWS console
  2. Go to "CloudTrail"
  3. In the sidebar on the left, click Event History
  4. Find the event you're interested in checking. Unfortunately, the console doesn't let you filter by ErrorCode, so you'll have to filter some other way, e.g. by username or event name.
  5. Download the event:
    1. By clicking the event, copying the event record, and pasting it to a json file locally. or,
    2. By clicking download events -> download as JSON in the top-right corner. (Access Undenied will handle all events where the ErrorCode is AccessDenied or Client.UnauthorizedOperation)

With the event saved locally, you may use the cli command

Example Cloudtrail event

One event in file:

{
  "awsRegion": "us-east-2",
  "eventID": "5ac7912b-fd5d-436a-b60c-8a4ec1f61cdc",
  "eventName": "ListFunctions20150331",
  "eventSource": "lambda.amazonaws.com",
  "eventTime": "2021-09-09T14:01:22Z",
  "eventType": "AwsApiCall",
  "userIdentity": {
    "accessKeyId": "ASIARXXXXXXXXXXXXXXXX",
    "accountId": "123456789012",
    "arn": "arn:aws:sts::123456789012:assumed-role/RscScpDisallow/1631196079303620000",
    "principalId": "AROARXXXXXXXXXXXXXXXX:1631196079303620000",
    "sessionContext": {
      "attributes": {
        "creationDate": "2021-09-09T14:01:20Z",
        "mfaAuthenticated": "false"
      },
      "sessionIssuer": {
        "accountId": "123456789012",
        "arn": "arn:aws:iam::123456789012:role/RscScpDisallow",
        "principalId": "AROARXXXXXXXXXXXXXXXX",
        "type": "Role",
        "userName": "RscScpDisallow"
      },
      "webIdFederationData": {}
    },
    "type": "AssumedRole"
  },
  "errorCode": "AccessDenied",
  "errorMessage": "User: arn:aws:sts::123456789012:assumed-role/RscScpDisallow/1631196079303620000 is not authorized to perform: lambda:ListFunctions on resource: * with an explicit deny",
  "sourceIPAddress": "xxx.xxx.xxx.xxx",
  "readOnly": true,
  "eventVersion": "1.08",
  "userAgent": "aws-cli/2.2.16 Python/3.8.8 Linux/4.19.128-microsoft-standard exe/x86_64.ubuntu.20 prompt/off command/lambda.list-functions",
  "requestID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx",
  "managementEvent": true,
  "recipientAccountId": "123456789012",
  "eventCategory": "Management"
}

Multiple events in file:

{
  "Records": [
    {
      "awsRegion": "us-east-1",
      "eventID": "xxxxxxxx-xxxx-xxxx-xxxx-8234c1555c12"
      //... rest of cloudtrail_event ...
    },
    {
      //... another cloudtrail_event ...
    }
    // more events...
  ]
}

Least privilege AccessUndenied policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AccessUndeniedLeastPrivilegePolicy",
      "Effect": "Allow",
      "Action": [
        "ecr:GetRepositoryPolicy",
        "iam:Get*",
        "iam:List*",
        "iam:SimulateCustomPolicy",
        "kms:GetKeyPolicy",
        "lambda:GetPolicy",
        "organizations:List*",
        "organizations:Describe*",
        "s3:GetBucketPolicy",
        "secretsmanager:GetResourcePolicy",
        "sts:DecodeAuthorizationMessage"
      ],
      "Resource": "*"
    }
  ]
}
Comments
  • Add CLI LookupEvents API example

    Add CLI LookupEvents API example

    Based on this AWS Support page: https://aws.amazon.com/premiumsupport/knowledge-center/troubleshoot-iam-permission-errors/ Resolves issue #9 . h/t Jon Holman

    opened by noamsdahan 0
  • Add support for deploying with IaC

    Add support for deploying with IaC

    Add the ability to deploy the roles and permissions that access undenied needs with infrastructure as code (CloudFormation/Terraform/Pulumi/AWS CDK)

    • Deploy role in management account with custom policies
    • Deploy roles in managed account trusting managed account

    Optional follow-up issue: deploy lambda.

    opened by noamsdahan 3
  • Add example of CLI event retrieval to README using LookupEvents

    Add example of CLI event retrieval to README using LookupEvents

    https://docs.aws.amazon.com/cli/latest/reference/cloudtrail/lookup-events.html This can be used as a base: https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_access-denied.html The CLI call here returns a table with columns, we just want the events.

    opened by noamsdahan 0
  • VPC Endpoint policies

    VPC Endpoint policies

    Add support for VPC Endpoint policies. The appropriate way to consider them would be to gather them during the iam_policy_data stage, and add them to the list of guardrail policies.

    opened by noamsdahan 0
  • Add support for additional resource policies

    Add support for additional resource policies

    Add support for additional resource policies. Consult the list of services which support resource-based policies. Currently, aws-access-undenied supports resource policies for KMS Keys, Secret Manager secrets, S3 buckets, ECR repositories and Lambda Functions.

    To add resource policy support.

    • Add the function _get_<service>_<resource>_resource_policy to resource_policy_utils.py
    • Call the function in the appropriate circumstances from get_resource_policy
    good first issue 
    opened by noamsdahan 0
  • Add support for additional condition keys

    Add support for additional condition keys

    Adding support for additional condition keys, such as AWS global context keys or service-specific condition keys (KMS, IAM).

    To add support for a condition key (that isn't multi-part, i.e. doesn't have / in it):

    • Add a function to simulate_custom_policy_generator.py def _get_aws_username(self) -> Optional[ContextEntryTypeDef] The function should return ContextEntryTypeDef or None if not applicable. If more information is needed from the event, add parsing that information to event.py.
    • Add a reference to that function to KEY_FUNCTION_DICT "aws:username": _get_aws_username,
    good first issue 
    opened by noamsdahan 0
Releases(v0.1.5)
  • v0.1.5(Mar 21, 2022)

  • v0.1.1(Mar 20, 2022)

    What's Changed

    • Renamed to access-undenied-aws
    • Separate analysis function from output by @noamsdahan in https://github.com/ermetic/access-undenied-aws/pull/4
    • Uploaded to PyPi: https://pypi.org/project/access-undenied-aws/

    Full Changelog: https://github.com/ermetic/access-undenied-aws/compare/v0.1.0...v0.1.1

    Source code(tar.gz)
    Source code(zip)
Owner
Ermetic
Ermetic
Battle.net and PlayStation title watcher that reports updates via Discord.

Renovate Renovate is a Battle.net and PlayStation title watcher that reports updates via Discord. Usage Open config_example.json and provide the confi

Ethan 1 Nov 23, 2022
A bot for the [email protected] Discord server.

KittyBot - a sentient Discord bot! Key Notes An open-source, community-powered bot for the [email 

Ollie 11 Dec 06, 2022
It is a temporary project to study discord interactions. You can set permissions conveniently when you invite a particular disk code bot.

Permission Bot 디스코드 내에 있는 message-components 를 연구하기 위하여 제작된 봇입니다. Setup /config/config_example.ini 파일을 /config/config.ini으로 변환합니다. config 파일의 기본 양식은 아

gunyu1019 4 Mar 07, 2022
Tickergram is a Telegram bot to look up quotes, charts, general market sentiment and more.

Tickergram is a Telegram bot to look up quotes, charts, general market sentiment and more.

Alberto Ortega 25 Nov 26, 2022
Python lib for Embedly

embedly-python Python library for interacting with Embedly's API. To get started sign up for a key at embed.ly/signup. Install Install with Pip (recom

Embedly 80 Oct 05, 2022
Easy to use Google Pub/Sub

Relé makes integration with Google PubSub straightforward and easy. Motivation and Features The Publish-Subscribe pattern and specifically the Google

Mercadona 188 Jan 06, 2023
SimpleDCABot is a simple bot that buys crypto with a dollar-cost averaging strategy.

Simple Open Dollar Cost Averaging (DCA) Bot SimpleDCABot is a simple bot that buys crypto on a selected exchange at regular intervals for a prescribed

4 Mar 28, 2022
(@Tablada32BOT is my bot in twitter) This is a simple bot, its main and only function is to reply to tweets where they mention their bot with their @

Remember If you are going to host your twitter bot on a page where they can read your code, I recommend that you create an .env file and put your twit

3 Jun 04, 2021
Video Stream is a telegram bot project that's allow you to play video on telegram group video chat

Video Stream is a telegram bot project that's allow you to play video on telegram group video chat 🚀 Get SESSION_NAME from below: Pyrogram ## ✨ Featu

1 Nov 10, 2021
SongBot2.0 With Python

SongBot2.0 Host 👨‍💻 Heroku 🚀 Manditary Vars BOT_TOKEN : Get It from @Botfather Special Feature Downloads Songs fastly and less errors as well as 0

Mr.Tanaji 5 Nov 19, 2021
This is an implementation example of a bot that periodically sends predictions to the alphasea-agent.

alphasea-example-model alphasea-example-modelは、 alphasea-agent に対して毎ラウンド、予測を投稿するプログラムです。 Numeraiのexample modelに相当します。 準備 alphasea-example-modelの動作には、

AlphaSea 11 Jul 28, 2022
Cool Discord bot for you

BountyBot Баунти – современный бот созданный с целью сделать ваш сервер лучше! В кратце В нем присутствует множество основных и интересных функций, та

Leestarb Original 1 Nov 22, 2021
Python bot for send videos of a Youtube channel to a telegram group , channel or chat

py_youtube_to_telegram Usage: If you want to install ytt and use it, run this command: sudo sh -c "$(curl -fsSL https://raw.githubusercontent.com/nima

Nima Fanniasl 8 Nov 22, 2022
A quick and dirty script to scan the network, find default credentials on services and post a message to a Slack channel with the results.

A quick and dirty script to scan the network, find default credentials on services and post a message to a Slack channel with the results.

Security Weekly 11 Jun 03, 2022
This is simple maker for level card in discord bot.

mariocard This is simple maker for level card in discord bot in discord.py or pycord. Installing Python 3.8 or higher is required # Linux/macOS pip3 i

3 Jan 29, 2022
Ethereum transactions and wallet information for people you follow on Twitter.

ethFollowing Ethereum transactions and wallet information for people you follow on Twitter. Set up Setup python environment (requires python 3.8): vir

Brian Donohue 2 Dec 28, 2021
This bot automaticaly access to giveaway ! You can won free NFT !

This bot automaticaly access to giveaway ! You can won free NFT !

2s.py 28 Oct 20, 2022
This script will detect changes in your session using Discords built in Gateway.

Detect Session Gateway This script will detect changes in your session using Discords built in Gateway. What does this log? Discord build version Oper

Omega 5 Dec 18, 2021
Mushahid Ali 1 Dec 31, 2021
Discord nuke bot with python

Discord-nuke-bot 🇷🇺 🇷🇺 🇷🇺 🇷🇺 🇷🇺 TODO: Добавить команду: Удаления всех ролей Спама каналами Спама во все каналы @everyone Удаления всего aka

Nikita Maykov 10 Oct 14, 2022