Skip to main content

Ensure IAM Inline Policies Do Not Allow Full CloudTrail Access

Overview

This check identifies IAM inline policies that grant unrestricted access to AWS CloudTrail using the cloudtrail:* wildcard action. CloudTrail is AWS's auditing service that records API activity across your account, making it a critical component of your security posture.

Risk

Granting full CloudTrail access (cloudtrail:*) creates serious security risks:

  • Audit tampering: Users could stop logging, modify trail configurations, or delete audit logs
  • Evidence destruction: Attackers could cover their tracks by deleting event history
  • Compliance violations: Many frameworks require immutable audit trails
  • Incident response impact: Security investigations become impossible without audit data

CloudTrail is one of the most sensitive services in AWS. Policies should follow the principle of least privilege, granting only the specific actions required.

Remediation Steps

Prerequisites

You need IAM permissions to view and modify inline policies attached to users, roles, or groups. Specifically, you need permissions like iam:GetUserPolicy, iam:PutUserPolicy, and similar for roles and groups.

AWS Console Method

  1. Open the IAM Console
  2. In the left navigation, click Users, Roles, or Groups (depending on where the policy is attached)
  3. Click on the entity name that has the problematic inline policy
  4. Expand the Inline policies section (under the Permissions tab)
  5. Find the policy that contains cloudtrail:* and click Edit
  6. Switch to the JSON editor if not already there
  7. Replace "Action": "cloudtrail:*" with specific actions your users actually need:
    • For read-only access: "cloudtrail:DescribeTrails", "cloudtrail:GetTrailStatus", "cloudtrail:LookupEvents"
    • For developers: "cloudtrail:LookupEvents" (to search events)
  8. Click Review policy, then Save changes

Tip: If you are unsure which specific actions are needed, start with read-only actions and add more as business requirements are identified.

AWS CLI (optional)

Find inline policies with CloudTrail wildcards

First, identify which users have inline policies:

# List all users
aws iam list-users --region us-east-1 --query 'Users[*].UserName' --output text

# For each user, list their inline policies
aws iam list-user-policies --user-name <username> --region us-east-1

For roles:

# List all roles
aws iam list-roles --region us-east-1 --query 'Roles[*].RoleName' --output text

# For each role, list inline policies
aws iam list-role-policies --role-name <role-name> --region us-east-1

View the policy content

# For a user policy
aws iam get-user-policy \
--user-name <username> \
--policy-name <policy-name> \
--region us-east-1

# For a role policy
aws iam get-role-policy \
--role-name <role-name> \
--policy-name <policy-name> \
--region us-east-1

Update the policy with least-privilege permissions

Create a new policy document (save as cloudtrail-readonly-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudtrail:DescribeTrails",
"cloudtrail:GetTrail",
"cloudtrail:GetTrailStatus",
"cloudtrail:ListTrails",
"cloudtrail:LookupEvents",
"cloudtrail:GetEventSelectors"
],
"Resource": "*"
}
]
}

Apply the updated policy:

# For a user
aws iam put-user-policy \
--user-name <username> \
--policy-name <policy-name> \
--policy-document file://cloudtrail-readonly-policy.json \
--region us-east-1

# For a role
aws iam put-role-policy \
--role-name <role-name> \
--policy-name <policy-name> \
--policy-document file://cloudtrail-readonly-policy.json \
--region us-east-1
CloudFormation (optional)

If you manage IAM policies through CloudFormation, update your template to use specific CloudTrail actions instead of wildcards.

Before (non-compliant):

Resources:
MyRole:
Type: AWS::IAM::Role
Properties:
RoleName: CloudTrailAccessRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CloudTrailFullAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: "cloudtrail:*" # NON-COMPLIANT
Resource: "*"

After (compliant):

Resources:
MyRole:
Type: AWS::IAM::Role
Properties:
RoleName: CloudTrailAccessRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CloudTrailReadOnly
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- cloudtrail:DescribeTrails
- cloudtrail:GetTrail
- cloudtrail:GetTrailStatus
- cloudtrail:ListTrails
- cloudtrail:LookupEvents
- cloudtrail:GetEventSelectors
Resource: "*"
Terraform (optional)

If you manage IAM policies through Terraform, update your configuration to specify individual CloudTrail actions.

Before (non-compliant):

resource "aws_iam_role_policy" "cloudtrail_policy" {
name = "cloudtrail-access"
role = aws_iam_role.example.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "cloudtrail:*" # NON-COMPLIANT
Resource = "*"
}
]
})
}

After (compliant):

resource "aws_iam_role_policy" "cloudtrail_policy" {
name = "cloudtrail-readonly"
role = aws_iam_role.example.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"cloudtrail:DescribeTrails",
"cloudtrail:GetTrail",
"cloudtrail:GetTrailStatus",
"cloudtrail:ListTrails",
"cloudtrail:LookupEvents",
"cloudtrail:GetEventSelectors"
]
Resource = "*"
}
]
})
}

Verification

After making changes, verify the fix:

  1. In the IAM console, navigate to the user, role, or group you modified
  2. Review the inline policy and confirm it no longer contains cloudtrail:*
  3. Test that the user or application can still perform their required CloudTrail operations
CLI verification

Re-run Prowler to confirm the check passes:

prowler aws --checks iam_inline_policy_no_full_access_to_cloudtrail --region us-east-1

Or verify manually:

# For a user
aws iam get-user-policy \
--user-name <username> \
--policy-name <policy-name> \
--region us-east-1 \
--query 'PolicyDocument'

Confirm the output does not contain "cloudtrail:*".

Additional Resources

Notes

  • Consider managed policies: Instead of inline policies, consider using AWS managed policies like AWSCloudTrailReadOnlyAccess or creating your own customer managed policy. Managed policies are easier to maintain and audit across multiple entities.

  • Administrative access: If someone truly needs to manage CloudTrail (create/delete trails, modify configurations), consider a separate role with strict controls, MFA requirements, and approval workflows rather than embedding these permissions in general-purpose policies.

  • Audit first: Before removing permissions, use CloudTrail itself or IAM Access Analyzer to understand which CloudTrail actions are actually being used. This helps ensure you do not break existing workflows.

  • This check applies to inline policies only: Managed policies (both AWS-managed and customer-managed) are evaluated by separate Prowler checks.