Skip to main content

IAM AWS-Managed Policies Should Not Grant Administrative Privileges

Overview

This check identifies AWS-managed IAM policies that grant full administrative access (*:* permissions) and are attached to users, groups, or roles. Policies like AdministratorAccess allow unrestricted access to all AWS services and resources, which violates the principle of least privilege.

Risk

Full administrative access (*:*) creates critical security exposure:

  • Data theft: Attackers can read and exfiltrate sensitive data from any service
  • Data tampering: Unauthorized modifications to databases, files, and configurations
  • Service disruption: Ability to delete or shut down critical resources
  • Audit evasion: Disabling CloudTrail, logs, and security monitoring
  • Persistence: Creating backdoor IAM users or roles for continued access
  • Lateral movement: Compromised credentials can access any resource in the account

Severity: Critical

Remediation Steps

Prerequisites

  • AWS Console access with IAM permissions (or an administrator who can help)
  • Knowledge of which users/roles need access and what they actually need to do

AWS Console Method

  1. Open the IAM Console

  2. Find the Flagged Policy

    • Search for AdministratorAccess (or the specific policy from Prowler)
    • Click the policy name to open its details
  3. View Attached Entities

    • Click the Entities attached tab
    • Note all users, groups, and roles using this policy
  4. Detach the Policy

    • For each entity listed:
      • Select the checkbox next to the entity name
      • Click Detach
      • Confirm the detachment
  5. Assign Appropriate Permissions

    • For each entity, determine what access they actually need
    • Attach more specific AWS-managed policies (e.g., ReadOnlyAccess, PowerUserAccess) or create custom policies
    • See the "Creating Least-Privilege Policies" section below for guidance
AWS CLI Method

Step 1: Identify Attached Entities

List all users, groups, and roles attached to the AdministratorAccess policy:

aws iam list-entities-for-policy \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--region us-east-1

Example output:

{
"PolicyGroups": [
{"GroupName": "Admins", "GroupId": "AGPACKCEVSQ6C2EXAMPLE"}
],
"PolicyUsers": [
{"UserName": "alice", "UserId": "AIDACKCEVSQ6C2EXAMPLE"}
],
"PolicyRoles": [
{"RoleName": "AdminRole", "RoleId": "AROADBQP57FF2AEXAMPLE"}
]
}

Step 2: Detach from Users

aws iam detach-user-policy \
--user-name <username> \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--region us-east-1

Step 3: Detach from Groups

aws iam detach-group-policy \
--group-name <group-name> \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--region us-east-1

Step 4: Detach from Roles

aws iam detach-role-policy \
--role-name <role-name> \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--region us-east-1

Step 5: Attach Replacement Policies

Attach more specific policies based on actual needs:

# Example: Attach PowerUserAccess instead (no IAM management)
aws iam attach-user-policy \
--user-name <username> \
--policy-arn arn:aws:iam::aws:policy/PowerUserAccess \
--region us-east-1
CloudFormation Example

When defining IAM roles in CloudFormation, avoid AdministratorAccess and use specific policies instead.

Avoid this (overly permissive):

Resources:
AdminRole:
Type: AWS::IAM::Role
Properties:
RoleName: MyRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
# DO NOT USE - grants full admin access
- arn:aws:iam::aws:policy/AdministratorAccess

Use this instead (scoped permissions):

AWSTemplateFormatVersion: '2012-10-17'
Description: IAM role with least-privilege permissions

Resources:
ScopedRole:
Type: AWS::IAM::Role
Properties:
RoleName: MyAppRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
# Use specific AWS-managed policies
- arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
- arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess

CustomPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: MyAppCustomPolicy
Roles:
- !Ref ScopedRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:DeleteObject
Resource: arn:aws:s3:::my-specific-bucket/*
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:UpdateItem
Resource: arn:aws:dynamodb:us-east-1:*:table/MyTable
Terraform Example

When defining IAM roles in Terraform, use specific policies rather than AdministratorAccess.

Avoid this (overly permissive):

# DO NOT USE - grants full admin access
resource "aws_iam_role_policy_attachment" "admin" {
role = aws_iam_role.example.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

Use this instead (scoped permissions):

# Define the role
resource "aws_iam_role" "app_role" {
name = "my-app-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}
]
})
}

# Attach specific AWS-managed policies
resource "aws_iam_role_policy_attachment" "s3_read" {
role = aws_iam_role.app_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}

resource "aws_iam_role_policy_attachment" "dynamodb_read" {
role = aws_iam_role.app_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess"
}

# Create a custom policy for specific write permissions
resource "aws_iam_policy" "app_write_policy" {
name = "my-app-write-policy"
description = "Limited write access for my application"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:PutObject",
"s3:DeleteObject"
]
Resource = "arn:aws:s3:::my-specific-bucket/*"
},
{
Effect = "Allow"
Action = [
"dynamodb:PutItem",
"dynamodb:UpdateItem"
]
Resource = "arn:aws:dynamodb:us-east-1:*:table/MyTable"
}
]
})
}

resource "aws_iam_role_policy_attachment" "app_write" {
role = aws_iam_role.app_role.name
policy_arn = aws_iam_policy.app_write_policy.arn
}
Creating Least-Privilege Policies

Strategy for Replacing Administrative Access

  1. Audit current usage: Use IAM Access Analyzer or CloudTrail to see what actions are actually being performed

  2. Start with AWS-managed policies: AWS provides many job-function policies:

    • ViewOnlyAccess - Read-only access to most services
    • ReadOnlyAccess - Read-only access to all services
    • PowerUserAccess - Full access except IAM management
    • Service-specific policies (e.g., AmazonEC2FullAccess, AmazonS3FullAccess)
  3. Create custom policies: For fine-grained control, create customer-managed policies with only the required permissions

  4. Use conditions: Add conditions to further restrict access:

    {
    "Effect": "Allow",
    "Action": "s3:*",
    "Resource": "*",
    "Condition": {
    "StringEquals": {
    "aws:RequestedRegion": "us-east-1"
    }
    }
    }
  5. Implement permissions boundaries: Set maximum permissions that can be granted to principals

Emergency Access Pattern

For emergency/break-glass scenarios where admin access may be needed:

  1. Create a separate "break-glass" role with AdministratorAccess
  2. Require MFA to assume the role
  3. Set a short session duration (1 hour)
  4. Enable detailed CloudTrail logging for the role
  5. Set up alerts when the role is assumed

Verification

After remediation, verify the fix:

  1. In the AWS Console:

    • Go to IAM > Policies > AdministratorAccess
    • Click "Entities attached" tab
    • Confirm no users, groups, or roles are listed
  2. Re-run Prowler:

    prowler aws -c iam_aws_attached_policy_no_administrative_privileges --region us-east-1
CLI Verification Commands
# Verify no entities are attached to AdministratorAccess
aws iam list-entities-for-policy \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--region us-east-1

# Expected output (no attachments):
# {
# "PolicyGroups": [],
# "PolicyUsers": [],
# "PolicyRoles": []
# }

Additional Resources

Notes

  • Do not remove admin access without a plan: Ensure you have alternative access methods in place before detaching administrative policies. Locking yourself out of an account is difficult to recover from.

  • Service-linked roles: Some AWS services create roles that may have broad permissions. These are managed by AWS and may not be modifiable.

  • Root account: This check applies to IAM identities, not the root account. Root account access should be secured separately with MFA and rarely used.

  • Break-glass procedures: Consider maintaining a documented emergency access procedure for situations requiring temporary administrative access, with proper controls and auditing.

  • Gradual rollout: For large organizations, consider a phased approach - start with non-critical environments, monitor for access issues, then apply to production.