Script icon
Process icon
If icon
SlackIncomingWebhook icon
Log icon
Return icon
Schedule icon

AWS Access Key Last Rotated Age Sentinel

Audits AWS IAM user access keys to detect unrotated credentials, enforcing automated key rotation and CIS Benchmark compliance.

Categories
CloudInfrastructure

Long-lived AWS Identity and Access Management (IAM) access keys are a primary vector for credential theft, unauthorized API access, and cloud infrastructure exfiltration. Security standards such as the CIS AWS Foundations Benchmark, SOC2, and PCI-DSS require organizations to rotate active access keys at least every 90 days and deactivate unused credentials. This sentinel continuously inspects all IAM users and active access keys via the AWS IAM API, tracks key ages and last-used dates against rotation baselines, and alerts Cloud Security teams on Slack with exact deactivation commands.

How it works

  1. Scheduled triggering: Executes weekly every Monday at 08:00 UTC using a cron schedule trigger (0 8 * * 1) or triggers on-demand via manual execution.
  2. User and key enumeration: Interrogates AWS IAM APIs (list_users, list_access_keys) to discover all registered IAM accounts and active credentials.
  3. Age and usage analysis: Calculates active key lifespans and queries get_access_key_last_used to identify credentials exceeding max_key_age_days.
  4. Condition evaluation: An io.kestra.plugin.core.flow.If task evaluates whether stale_keys_count exceeds max_tolerated_stale_keys.
  5. Slack alert dispatch: Sends a high-priority incident payload via SlackIncomingWebhook listing usernames, key IDs, ages, and deactivation CLI commands.
  6. Audit trail logging and return: Emits operational execution logs and returns a structured compliance manifest for auditing.

Architecture diagram

flowchart TD
  A[weekly_iam_key_audit Schedule Trigger] --> B[scan_iam_access_keys Python Script]
  B --> C[check_stale_keys Flowable If]
  C -- Stale Keys Found --> D[notify_slack_cloudsec Webhook]
  C -- All Keys Compliant --> E[log_access_key_audit Log]
  D --> E
  E --> F[export_access_key_manifest Return]

Use cases

  • CIS AWS Foundations Benchmark compliance: Enforce CIS control 1.14 requiring credential rotation every 90 days across enterprise cloud accounts.
  • Abandoned contractor credential hygiene: Identify active access keys belonging to former team members or contractors that remain enabled months after project completion.
  • Leaked key exposure reduction: Minimize the effective operational window of inadvertently leaked credentials by enforcing regular rotation cycles.

Inputs

Name Type Default Description
aws_region STRING us-east-1 Primary AWS region used for IAM API initialization.
max_key_age_days INT 90 Maximum permissible age in days before an active IAM access key is flagged for rotation.
alert_on_stale_access_keys BOOL true Whether to dispatch alerts when unrotated IAM access keys exceed the maximum age threshold.
max_tolerated_stale_keys INT 0 Maximum permissible stale access key count before triggering an incident notification.

Expected outputs

  • {{ outputs.scan_iam_access_keys.vars.total_users_audited }}: Total number of IAM user accounts inspected.
  • {{ outputs.scan_iam_access_keys.vars.total_keys_audited }}: Consolidated count of access keys evaluated across all users.
  • {{ outputs.scan_iam_access_keys.vars.stale_keys_count }}: Number of active keys exceeding the rotation age threshold.
  • {{ outputs.scan_iam_access_keys.vars.stale_keys_details }}: Serialized JSON list of stale keys with ages and deactivation CLI commands.
  • {{ outputs.export_access_key_manifest.value }}: Structured dictionary containing the consolidated IAM credential compliance manifest.

Prerequisites

  • Outbound HTTPS network access from Kestra execution workers to AWS IAM API endpoints.
  • AWS IAM policy with iam:ListUsers, iam:ListAccessKeys, and iam:GetAccessKeyLastUsed permissions.
  • Incoming Slack Webhook configured for Cloud SecOps alerting.

Secrets

  • AWS_ACCESS_KEY_ID: AWS IAM access key ID authorized to audit account IAM credentials.
  • AWS_SECRET_ACCESS_KEY: AWS IAM secret access key.
  • SLACK_WEBHOOK_URL: Slack Incoming Webhook endpoint URL used for sending security alerts.

Quick start

  1. Define AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and SLACK_WEBHOOK_URL in your Kestra Secret storage.
  2. Deploy this flow under the company.security namespace.
  3. Configure max_key_age_days according to organizational security policy (e.g., 90 or 60).
  4. Run a manual execution to inspect IAM credentials and verify Slack alerting.

Common pitfalls and troubleshooting

  • Root account access keys: Root account keys should be deleted entirely rather than rotated; standard IAM user audits do not inspect root credentials.
  • Service account exemptions: Machine service accounts in CI/CD pipelines often require synchronized rotation in secret vaults (e.g., Vault or AWS Secrets Manager) before deactivating old keys.
  • IAM API pagination: Enterprise accounts with hundreds of users must ensure pagination traverses all user pages without truncating results.

How to extend

  • Automated key deactivation: Add a task that calls iam.update_access_key(Status='Inactive') on keys older than 180 days with no activity in 45 days.
  • Direct user notification: Send direct Slack messages to individual IAM user owners using email lookups.
  • AWS Organizations multi-account audit: Wrap the task inside an io.kestra.plugin.core.flow.ForEach loop iterating across AWS accounts via AssumeRole.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.