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