AWS Root Account Access Keys


Description

Validates that no programmatic access keys exist for the AWS root account. Root access keys provide unrestricted access to all AWS resources and cannot have permissions limited. If compromised, these keys grant attackers complete account control including resource modification, data access, and billing changes.

Query · python

from panther_base_helpers import deep_get


def policy(resource):
    return not deep_get(resource, "CredentialReport", "AccessKey1Active") and not deep_get(
        resource, "CredentialReport", "AccessKey2Active"
    )

Analyst notes

  1. Query CloudTrail for all API calls where userIdentity.type equals "Root" in the past 90 days to identify if the root access keys are actively being used and document which applications or automation depend on them
  2. Create IAM users or roles with minimum required permissions, update all applications to use the new IAM credentials, then delete the root access keys via AWS Console Security Credentials page
  3. Enable CloudWatch Events rules to alert on future root account activity and consider implementing AWS Organizations SCPs to prevent root access key creation
Raw source AWS Root Account Access Keys · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: policy
Filename: aws_root_account_access_keys.py
PolicyID: "AWS.RootAccount.AccessKeys"
DisplayName: "AWS Root Account Access Keys"
Enabled: true
ResourceTypes:
  - AWS.IAM.RootUser
Tags:
  - AWS
  - Identity & Access Management
  - Persistence:Account Manipulation
Reports:
  CIS:
    - 1.12
  PCI:
    - 2.2.2
    - 7.1
    - 8.2
  MITRE ATT&CK:
    - TA0003:T1098
Severity: Critical
Description: >
  Validates that no programmatic access keys exist for the AWS root account. Root access keys provide unrestricted access to all AWS resources and cannot have permissions limited. If compromised, these keys grant attackers complete account control including resource modification, data access, and billing changes.
Runbook: |
  1. Query CloudTrail for all API calls where userIdentity.type equals "Root" in the past 90 days to identify if the root access keys are actively being used and document which applications or automation depend on them
  2. Create IAM users or roles with minimum required permissions, update all applications to use the new IAM credentials, then delete the root access keys via AWS Console Security Credentials page
  3. Enable CloudWatch Events rules to alert on future root account activity and consider implementing AWS Organizations SCPs to prevent root access key creation
Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html
Tests:
  - Name: Access Key 1 Active
    ExpectedResult: false
    Resource:
      {
        "ARN": "arn:aws:iam::123456789012:root",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:root",
            "AccessKey1Active": true,
            "AccessKey1LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedRegion": "N/A",
            "AccessKey1LastUsedService": "N/A",
            "AccessKey2Active": false,
            "AccessKey2LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedRegion": "N/A",
            "AccessKey2LastUsedService": "N/A",
            "Cert1Active": false,
            "Cert1LastRotated": "0001-01-01T00:00:00Z",
            "Cert2Active": false,
            "Cert2LastRotated": "0001-01-01T00:00:00Z",
            "MfaActive": true,
            "PasswordEnabled": false,
            "PasswordLastChanged": "0001-01-01T00:00:00Z",
            "PasswordLastUsed": "2019-01-01T00:00:00Z",
            "PasswordNextRotation": "0001-01-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "<root_account>",
          },
        "UserID": null,
        "UserName": "root",
        "VirtualMFA": null,
      }
  - Name: Access Key 2 Active
    ExpectedResult: false
    Resource:
      {
        "ARN": "arn:aws:iam::123456789012:root",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:root",
            "AccessKey1Active": false,
            "AccessKey1LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedRegion": "N/A",
            "AccessKey1LastUsedService": "N/A",
            "AccessKey2Active": true,
            "AccessKey2LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedRegion": "N/A",
            "AccessKey2LastUsedService": "N/A",
            "Cert1Active": false,
            "Cert1LastRotated": "0001-01-01T00:00:00Z",
            "Cert2Active": false,
            "Cert2LastRotated": "0001-01-01T00:00:00Z",
            "MfaActive": true,
            "PasswordEnabled": false,
            "PasswordLastChanged": "0001-01-01T00:00:00Z",
            "PasswordLastUsed": "2019-01-01T00:00:00Z",
            "PasswordNextRotation": "0001-01-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "<root_account>",
          },
        "UserID": null,
        "UserName": "root",
        "VirtualMFA": null,
      }
  - Name: Access Keys 1 and 2 Active
    ExpectedResult: false
    Resource:
      {
        "ARN": "arn:aws:iam::123456789012:root",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:root",
            "AccessKey1Active": true,
            "AccessKey1LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedRegion": "N/A",
            "AccessKey1LastUsedService": "N/A",
            "AccessKey2Active": true,
            "AccessKey2LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedRegion": "N/A",
            "AccessKey2LastUsedService": "N/A",
            "Cert1Active": false,
            "Cert1LastRotated": "0001-01-01T00:00:00Z",
            "Cert2Active": false,
            "Cert2LastRotated": "0001-01-01T00:00:00Z",
            "MfaActive": true,
            "PasswordEnabled": false,
            "PasswordLastChanged": "0001-01-01T00:00:00Z",
            "PasswordLastUsed": "2019-01-01T00:00:00Z",
            "PasswordNextRotation": "0001-01-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "<root_account>",
          },
        "UserID": null,
        "UserName": "root",
        "VirtualMFA": null,
      }
  - Name: No Access Keys Enabled
    ExpectedResult: true
    Resource:
      {
        "ARN": "arn:aws:iam::123456789012:root",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:root",
            "AccessKey1Active": false,
            "AccessKey1LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedRegion": "N/A",
            "AccessKey1LastUsedService": "N/A",
            "AccessKey2Active": false,
            "AccessKey2LastRotated": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey2LastUsedRegion": "N/A",
            "AccessKey2LastUsedService": "N/A",
            "Cert1Active": false,
            "Cert1LastRotated": "0001-01-01T00:00:00Z",
            "Cert2Active": false,
            "Cert2LastRotated": "0001-01-01T00:00:00Z",
            "MfaActive": true,
            "PasswordEnabled": false,
            "PasswordLastChanged": "0001-01-01T00:00:00Z",
            "PasswordLastUsed": "2019-01-01T00:00:00Z",
            "PasswordNextRotation": "0001-01-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "<root_account>",
          },
        "UserID": null,
        "UserName": "root",
        "VirtualMFA": null,
      }


# ------ paired body: aws_root_account_access_keys.py ------

from panther_base_helpers import deep_get


def policy(resource):
    return not deep_get(resource, "CredentialReport", "AccessKey1Active") and not deep_get(
        resource, "CredentialReport", "AccessKey2Active"
    )

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.