Compliance Frameworks
BETA// Beta Mapping Disclaimer
Framework mappings are currently in beta. These references are generated based on technical specifications and common industry alignments. Mappings may be incomplete or inaccurate; always consult with a qualified auditor for official compliance validation.
Overview
Ensure no active programmatic access keys exist for the root user in any AWS account, and prevent their creation organization-wide via SCP.
The root user bypasses all IAM permission boundaries and SCPs, making a compromised root access key the highest-severity credential exposure possible in AWS. This control operates at two layers: a preventative SCP applied at the organization root that denies iam:CreateAccessKey when the caller is the root principal, and detective checks via the IAM credential report and the AccountAccessKeysPresent account summary metric. The SCP targets only access key creation - it does not restrict root console sign-in or other root-only emergency operations such as restoring an IAM policy that locks out all users.
Root access keys are long-lived credentials with no permission boundary and no MFA enforcement at the API level. Any programmatic action should be performed through IAM roles, which support least-privilege scoping, session duration limits, and full CloudTrail attribution. There is no legitimate operational use case for root access keys in a well-configured landing zone.
Remediation Strategy
Delete any existing root access keys via the AWS Console (root keys cannot be deleted via CLI). Apply the SCP from enforcement_reference at the organization root to prevent recreation.
Sign in to the AWS Console as root for each non-compliant account.
Navigate to IAM → My Security Credentials → Access keys and delete all listed keys.
Apply the DenyRootAccessKeyCreation SCP to the organization root from the Management account.
# Identifies root user access key creation events in CloudTrail
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=CreateAccessKey \
--query 'Events[*].{Time:EventTime,Operator:Username,EventData:CloudTrailEvent}' \
--output json | jq '.[] | {
Time: .Time,
Creator: .Operator,
TargetUser: (.EventData | fromjson | .requestParameters.userName),
AccessKeyId: (.EventData | fromjson | .responseElements.accessKey.accessKeyId)
}'
# Safely loops through users, catching hidden pagination parameters
for user in $(aws iam list-users --query "Users[].UserName" --output text); do
keys=$(aws iam list-access-keys \
--user-name "$user" \
--query "AccessKeyMetadata[?Status==\`Active\`].{ID:AccessKeyId,Created:CreateDate}" \
--output json)
if [ "$keys" != "[]" ] && [ ! -z "$keys" ]; then
echo "USER: $user has active keys:"
echo "$keys" | jq .
fi
doneEnforcement Logic
Two checks cover this control. The fast check queries AccountAccessKeysPresent from the IAM account summary - a non-zero value immediately flags the account as non-compliant without needing to generate a credential report. The authoritative check generates the IAM credential report and inspects the access_key_1_active and access_key_2_active columns for the root user row. AWS Security Hub control IAM.1 automates this check across all accounts when Security Hub is enabled organization-wide.
# Fast check: non-zero means a root key exists
aws iam get-account-summary \
--query "SummaryMap.AccountAccessKeysPresent" \
--output text
# Authoritative check via credential report
aws iam generate-credential-report
aws iam get-credential-report \
--query "Content" \
--output text | \
base64 --decode | \
python3 -c "
import sys, csv
for row in csv.DictReader(sys.stdin):
if row['user'] == '<root_account>':
print('key_1_active:', row['access_key_1_active'])
print('key_2_active:', row['access_key_2_active'])
"Root access keys cannot be deleted via the AWS CLI or any API - Console sign-in as root is required. The credential report is eventually consistent and may take time to reflect a newly deleted key; use get-account-summary for an immediate count. The SCP condition aws:PrincipalArn with a wildcard account segment (arn:aws:iam::*:root) correctly matches the root principal in any member account without needing to enumerate account IDs. SCPs apply exclusively to member accounts and do not evaluate or restrict policies within the root account.