AWS Access Key Rotation


Description

This policy validates that AWS IAM account access keys are rotated every 90 days. Rotating access keys will reduce the window of opportunity for an access key that is associated with a compromised or terminated account to be used.

Query · python

import datetime

from panther_base_helpers import resolve_timestamp_string

TIMEOUT_DAYS = datetime.timedelta(days=90)


def aged_out(timestamp):
    if not timestamp:
        return False
    datetime_ts = resolve_timestamp_string(timestamp)
    if not datetime_ts:
        return False
    return (datetime.datetime.now() - datetime_ts) > TIMEOUT_DAYS


def policy(resource):
    # If a user is less than 4 hours old, it may not have a credential report generated yet.
    # It will be re-scanned periodically until a credential report is found, at which point this
    # policy will be properly evaluated.
    report = resource.get("CredentialReport")
    if not report:
        return True

    if report.get("AccessKey1Active"):
        if aged_out(report.get("AccessKey1LastRotated")):
            return False
    if report.get("AccessKey2Active"):
        if aged_out(report.get("AccessKey2LastRotated")):
            return False

    return True

Analyst notes

https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-access-keys-rotated-every-90-days

Raw source AWS Access Key Rotation · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: policy
Filename: aws_access_key_rotation.py
PolicyID: "AWS.AccessKey.Rotation"
DisplayName: "AWS Access Key Rotation"
Enabled: true
ResourceTypes:
  - AWS.IAM.RootUser
  - AWS.IAM.User
Tags:
  - AWS
  - Identity & Access Management
  - Credential Access:Unsecured Credentials
Reports:
  CIS:
    - 1.4
  MITRE ATT&CK:
    - TA0006:T1552
Severity: Medium
Description: >
  This policy validates that AWS IAM account access keys are rotated every 90 days.
  Rotating access keys will reduce the window of opportunity for an access key that
  is associated with a compromised or terminated account to be used.
Runbook: >
  https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-access-keys-rotated-every-90-days
Reference: >
  https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html
Tests:
  - Name: Root User Access Key 1 Rotated Over 90 Days Ago
    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": "2000-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: Root User Access Key 2 Rotated Less Than 90 Days Ago
    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": true,
            "AccessKey2LastRotated": "3000-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: User Access Key 1 Rotated Less Than 90 Days Ago
    ExpectedResult: true
    Resource:
      {
        "Arn": "arn:aws:iam::123456789012:user/Bobert",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:user/Bobert",
            "AccessKey1Active": true,
            "AccessKey1LastRotated": "3000-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": false,
            "PasswordEnabled": true,
            "PasswordLastChanged": "2019-01-01T00:00:00Z",
            "PasswordLastUsed": "0001-01-01T00:00:00Z",
            "PasswordNextRotation": "2019-04-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "Bobert",
          },
        "Groups":
          [
            {
              "Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
              "CreateDate": "2019-01-01T00:00:00Z",
              "GroupId": "ABCDEFGHIJKLMNOP",
              "GroupName": "ExampleGroup",
              "Path": "/",
            },
          ],
        "InlinePolicyNames": null,
        "ManagedPolicyNames": ["IAMUserChangePassword"],
        "PasswordLastUsed": null,
        "Path": "/",
        "PermissionsBoundary": null,
        "Tags": null,
        "UserId": "ASDFASDFASDFASDF",
        "UserName": "Bobert",
        "VirtualMFA": null,
      }
  - Name: User Access Key 1 Rotated Over 90 Days Ago
    ExpectedResult: false
    Resource:
      {
        "Arn": "arn:aws:iam::123456789012:user/Bobert",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:user/Bobert",
            "AccessKey1Active": true,
            "AccessKey1LastRotated": "2000-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": false,
            "PasswordEnabled": true,
            "PasswordLastChanged": "2019-01-01T00:00:00Z",
            "PasswordLastUsed": "0001-01-01T00:00:00Z",
            "PasswordNextRotation": "2019-04-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "Bobert",
          },
        "Groups":
          [
            {
              "Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
              "CreateDate": "2019-01-01T00:00:00Z",
              "GroupId": "ABCDEFGHIJKLMNOP",
              "GroupName": "ExampleGroup",
              "Path": "/",
            },
          ],
        "InlinePolicyNames": null,
        "ManagedPolicyNames": ["IAMUserChangePassword"],
        "PasswordLastUsed": null,
        "Path": "/",
        "PermissionsBoundary": null,
        "Tags": null,
        "UserId": "ASDFASDFASDFASDF",
        "UserName": "Bobert",
        "VirtualMFA": null,
      }
  - Name: User Access Key 2 Rotated Less Than 90 Days Ago
    ExpectedResult: true
    Resource:
      {
        "Arn": "arn:aws:iam::123456789012:user/Bobert",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:user/Bobert",
            "AccessKey1Active": false,
            "AccessKey1LastRotated": "2019-01-01T00:00:00Z",
            "AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedRegion": "N/A",
            "AccessKey1LastUsedService": "N/A",
            "AccessKey2Active": true,
            "AccessKey2LastRotated": "3000-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": false,
            "PasswordEnabled": true,
            "PasswordLastChanged": "2019-01-01T00:00:00Z",
            "PasswordLastUsed": "0001-01-01T00:00:00Z",
            "PasswordNextRotation": "2019-04-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "Bobert",
          },
        "Groups":
          [
            {
              "Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
              "CreateDate": "2019-01-01T00:00:00Z",
              "GroupId": "ABCDEFGHIJKLMNOP",
              "GroupName": "ExampleGroup",
              "Path": "/",
            },
          ],
        "InlinePolicyNames": null,
        "ManagedPolicyNames": ["IAMUserChangePassword"],
        "PasswordLastUsed": null,
        "Path": "/",
        "PermissionsBoundary": null,
        "Tags": null,
        "UserId": "ASDFASDFASDFASDF",
        "UserName": "Bobert",
        "VirtualMFA": null,
      }
  - Name: User Access Key 2 Rotated Over 90 Days Ago
    ExpectedResult: false
    Resource:
      {
        "Arn": "arn:aws:iam::123456789012:user/Bobert",
        "CreateDate": "2019-01-01T00:00:00Z",
        "CredentialReport":
          {
            "ARN": "arn:aws:iam::123456789012:user/Bobert",
            "AccessKey1Active": false,
            "AccessKey1LastRotated": "2019-01-01T00:00:00Z",
            "AccessKey1LastUsedDate": "0001-01-01T00:00:00Z",
            "AccessKey1LastUsedRegion": "N/A",
            "AccessKey1LastUsedService": "N/A",
            "AccessKey2Active": true,
            "AccessKey2LastRotated": "2000-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": false,
            "PasswordEnabled": true,
            "PasswordLastChanged": "2019-01-01T00:00:00Z",
            "PasswordLastUsed": "0001-01-01T00:00:00Z",
            "PasswordNextRotation": "2019-04-01T00:00:00Z",
            "UserCreationTime": "2019-01-01T00:00:00Z",
            "UserName": "Bobert",
          },
        "Groups":
          [
            {
              "Arn": "arn:aws:iam::123456789012:group/ExampleGroup",
              "CreateDate": "2019-01-01T00:00:00Z",
              "GroupId": "ABCDEFGHIJKLMNOP",
              "GroupName": "ExampleGroup",
              "Path": "/",
            },
          ],
        "InlinePolicyNames": null,
        "ManagedPolicyNames": ["IAMUserChangePassword"],
        "PasswordLastUsed": null,
        "Path": "/",
        "PermissionsBoundary": null,
        "Tags": null,
        "UserId": "ASDFASDFASDFASDF",
        "UserName": "Bobert",
        "VirtualMFA": null,
      }


# ------ paired body: aws_access_key_rotation.py ------

import datetime

from panther_base_helpers import resolve_timestamp_string

TIMEOUT_DAYS = datetime.timedelta(days=90)


def aged_out(timestamp):
    if not timestamp:
        return False
    datetime_ts = resolve_timestamp_string(timestamp)
    if not datetime_ts:
        return False
    return (datetime.datetime.now() - datetime_ts) > TIMEOUT_DAYS


def policy(resource):
    # If a user is less than 4 hours old, it may not have a credential report generated yet.
    # It will be re-scanned periodically until a credential report is found, at which point this
    # policy will be properly evaluated.
    report = resource.get("CredentialReport")
    if not report:
        return True

    if report.get("AccessKey1Active"):
        if aged_out(report.get("AccessKey1LastRotated")):
            return False
    if report.get("AccessKey2Active"):
        if aged_out(report.get("AccessKey2LastRotated")):
            return False

    return True

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.