Package: aws-access-undenied
Access UndeniedAccess Undenied parses AWS AccessDenied CloudTrail events, explains the reasons for them, and offers actionable fixes.Access UndeniedOverviewCommon use casesSimple StartupInstallationInstallation from pipInstallation from source code (development)UsageGetting eventsPermissionsSame account assets only, no SCPsCross-account assets and SCPsCLI CommandsAnalyzeGet SCPsOutput FormatOutput FieldsAccessDeniedReason:ResultDetailsPoliciesToAddExplicitDenyPoliciesAcknowledgementsAppendicesSetting up a venvGetting Cloudtrail events from the AWS Console's event historyExample Cloudtrail eventLeast privilege AccessUndenied policyOverviewAccess 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 casesSometimes, thenew and more detailed AccessDenied messages
provided by AWSwill be sufficient. However, that is not always the case.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.When the reason for AccessDenied is an explicit deny, it can be difficult to track down
and evaluate every relevant policy.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.When the problem is a missingAllowstatement, AccessUndenied automatically offers a least-privilege
policy based on the CloudTrail event.Simple StartupInstall AccessUndeniedpip install aws-access-undeniedAnalyze a CloudTrail event file.aws-access-undenied --file event_history.jsonInstallationInstallation from pippython -m pip install aws-access-undeniedInstallation from source code (development)To install from source code, you canset up a venv(optionally), and within that venvpython -m pip install --editable .UsageGetting eventsAccess 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 an example of how to do
this:Getting Cloudtrail events from the AWS Console's event historyPermissionsAccess Undenied runs with the default permissions of the environment running the cli command, and accepts
the--profileflag for using a different profile from .aws/credentials. The role running aws-access-undenied should have
at be granted these permissions:Attach theSecurityAuditmanaged policyAttach this inline policy:AccessUndeniedAssumeRole{"Version":"2012-10-17","Statement":[{"Sid":"AccessUndenied-AssumeRole","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 attachSecurityAudit, you may instead attach the updatingleast-privilege
AccessUndenied policySame account assets only, no SCPsWhen 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 SCPsTo consider assets in multiple accounts and/or SCPs in the management account, we need to set up AWS cross-account roles
with thesame policyand the same name as each other (the default isAccessUndeniedRole)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":{}}]}Create an identity policy (inline or managed) with the following permissions:{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["iam:Get*","iam:List*","kms:GetKeyPolicy","organizations:DescribeOrganization","s3:GetBucketPolicy","secretsmanager:GetResourcePolicy","sts:DecodeAuthorizationMessage"],"Resource":"*"}]}CLI CommandsSimplest commandaws-access-undenied analyze --events-file cloudtrail_events.jsonAll 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 fileAnalyzeThis command is used to analyze AccessDenied events. It can be used either with themanagement-account-role-arnparameter to retrieve SCPs, or with thescp-fileparameter to use a policy data file created by theget_scpscommand.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:aws-access-undenied analyze --events-file events_file.jsonGet SCPsThis 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:aws-access-undenied get-scpsThen when running analyzing (from the same account or a different account)aws-access-undenied analyze --events-file events_file.json --scp-file scp_data.jsonOutput 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:120252999260:db:*"}]}}]}}This output for example, tells us that access was denied because of there is noAllowstatement in an identity-based policy.
To  remediate, we should attach to the IAM rolearn:aws:iam::123456789012:role/MyRolethe policy:{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"rds:DescribeDBInstances","Resource":"arn:aws:rds:ap-northeast-3:120252999260:db:*"}]}Output FieldsAccessDeniedReason:The reason why access was denied. Possible ValuesMissing allow in:Identity policyResource policy (in cross-account access)Both (in cases of cross-account access)Permissions boundaryService control policy (with allow-list SCP strategy)Explicit deny from:Identity policyResource policyPermissions boundaryService control policyInvalid 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 allowedUnsupported resource policy typeUnsupported policy type (VPC endpoint policy, session policy, etc.)Unsupported condition keyResultDetailsThese are the details of the result, explaining the remediation steps,
this section may contain eitherPoliciesToAddorExplicitDenyPolicies.PoliciesToAddThese 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 attachedPolicy: The content of the policy to be addedExplicitDenyPoliciesThese are the policies cause explicit deny, which need to be removed or
modified to facilitate access. AccessUndenied also gives the specific
statement causing theDenyoutcome.AttachmentTargetArn: the entity to which the policy causing explicit
deny is currently attachedPolicyArn: 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/S3BucketPolicyPolicyName: The policy name, if applicable. Resource policies
are represented by generic placeholder names such asS3BucketPolicyPolicyStatement: The specific statement in the aforementioned policy
causing explicit denyAcknowledgementsThis project makes use of Ian Mckay'siam-datasetBen
Kehoe'saws-error-utils.AppendicesSetting up a venvpython -m venv .venvPlatformShellCommand to activate virtual environmentPOSIXbash/zsh$ source .venv/bin/activatefish$ source .venv/bin/activate.fishcsh/tcsh$ source .venv/bin/activate.cshPowerShell Core$ .venv/bin/Activate.ps1Windowscmd.exeC:> .venv\Scripts\activate.batPowerShellPS C:> .venv\Scripts\Activate.ps1Getting Cloudtrail events from the AWS Console's event historyOpen the AWS consoleGo to "CloudTrail"In the sidebar on the left, click Event HistoryFind 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.Download the event:By clicking the event, copying the event record, and pasting it to a json file locally. or,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 thecli commandExample Cloudtrail eventOne 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":["iam:Get*","iam:List*","iam:SimulateCustomPolicy","kms:GetKeyPolicy","organizations:DescribeOrganization","s3:GetBucketPolicy","secretsmanager:GetResourcePolicy","sts:DecodeAuthorizationMessage"],"Resource":"*"}]}