# IAM Role With AdministratorAccess Policy

> ZopNight flags an IAM role when the AWS-managed AdministratorAccess policy is attached, derived from iam:ListAttachedRolePolicies at discovery time. Roles AWS provisions with admin by design (2 reserved path prefixes plus Control Tower, Identity Center, QuickSetup and StackSets name prefixes) are deliberately excluded, so only customer-created admin roles surface.

Source: https://zop.dev/integrations/aws/recommendations/iam-role-with-administratoraccess-policy
Updated: 2026-08-19

---

## How admin access is derived, not assumed

At discovery time ZopNight lists each role's attached managed policies and looks for the
AWS-managed policy ARN `arn:aws:iam::aws:policy/AdministratorAccess`. The result is stamped
onto the role in both polarities (has admin, or does not), so the rule always works from an
observed policy attachment, never from a naming convention or a guess. If that policy
listing fails for a role, no verdict is stamped and the rule abstains for it: a
high-severity least-privilege finding must not fire on missing evidence.

An operator-applied tag of `has_admin_access` set to true is honoured as a last-resort
fallback, so a team can deliberately mark a role they know is over-privileged even before
discovery re-runs.

## The roles AWS built to be admin

Not every AdministratorAccess attachment is a mistake. Two IAM path prefixes are reserved
for roles AWS itself provisions and manages: `/aws-service-role/` (service-linked roles)
and `/aws-reserved/` (IAM Identity Center). Several name prefixes also mark landing-zone
automation that ships with admin by design: `AWSControlTower`, `aws-controltower-`,
`AWS-QuickSetup-`, `AWSReservedSSO_` and `stacksets-exec-`.

The rule abstains on all of these. Detaching admin from a Control Tower execution role or
an Identity Center permission-set role does not harden anything. It breaks the AWS service
that owns the role. The path check runs first because it is provider-authoritative; the
name-prefix check covers older discovery data that lacks the role path.

## Enumerating AdministratorAccess holders

```bash
aws iam list-entities-for-policy \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
  --entity-filter Role --query 'PolicyRoles[].RoleName' --output table
```

One call answers the whole account: every role currently holding the managed admin policy,
which you can then sieve through the allowlist above by eye.

## Swapping AdministratorAccess for scoped policies

The finding is high severity because an admin role is a blast-radius multiplier: any
workload or person who can assume it holds the entire account. The path down is
incremental: work out which services the role genuinely calls, let IAM Access Analyzer
generate a least-privilege policy from its CloudTrail activity, attach that, and only then
detach the admin ARN. Doing the detach first is how outage tickets get opened.
