← All articles

How to Rotate AWS Access Keys Automatically

Key takeaways

  • AWS allows two active access keys per IAM user, so rotation is a four-phase sequence: create the new key, propagate it, verify usage, then deactivate and delete the old one.
  • A rotation script needs exactly five IAM actions: CreateAccessKey, UpdateAccessKey, DeleteAccessKey, ListAccessKeys, and GetAccessKeyLastUsed, scoped to the specific user.
  • Check GetAccessKeyLastUsed before deactivating an old key, and size the overlap window to the longest known usage interval of any consumer.
  • Schedule rotation with EventBridge Scheduler triggering Lambda, or cron on a bastion or CI runner, and log each state transition for audit.
  • Deactivate before deleting: an inactive key stops working but can be reactivated instantly, while deletion is irreversible.

Rotate AWS access keys automatically by scripting a four-phase sequence: create a second key, activate it, wait for a propagation window, then deactivate and delete the old key. AWS allows two active keys per IAM user, so the overlap window lets running workloads cut over without downtime. This guide covers the exact IAM actions and scheduling.

Why should AWS access keys be rotated automatically instead of manually?

Manual rotation fails because it depends on humans remembering a deadline. Reddit threads from AWS shops describe the pattern: keys created by hand, copied into Postman collections, and held past any 30/60/90 day rotation policy because nobody owns the reminder. The vault solves storage; it does not solve expiry.

Automation removes the human transport layer. AWS gives you the full lifecycle in its IAM API: ListAccessKeys, CreateAccessKey, UpdateAccessKey, and DeleteAccessKey, plus GetAccessKeyLastUsed to confirm nothing still calls the old key before you retire it. A script that runs these on a schedule rotates keys the same way every time, with an audit trail.

Automation still leaves a gap: knowing which keys exist, who owns them, and which deadline is next. That is an ownership problem, and assigning owners to API keys is where it starts.

Which IAM permissions does an automated rotation process require?

A rotation script needs exactly five IAM actions: iam:CreateAccessKey, iam:UpdateAccessKey, iam:DeleteAccessKey, iam:ListAccessKeys, and iam:GetAccessKeyLastUsed. Scope them to the specific user whose keys rotate, not to iam:* or all users. The rotation role holds these permissions; the rotated user does not.

Least-privilege policy JSON for the rotation role

Attach this to the role your scheduled job assumes:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "iam:CreateAccessKey",
      "iam:UpdateAccessKey",
      "iam:DeleteAccessKey",
      "iam:ListAccessKeys",
      "iam:GetAccessKeyLastUsed"
    ],
    "Resource": "arn:aws:iam::123456789012:user/deploy-bot"
  }]
}

AWS caps each user at two access keys, which is what makes the overlap window possible: create the second key while the first is still active. iam:ListAccessKeys lets the script detect a stuck rotation where an old key was never deleted and the limit blocks the next cycle.

Why GetAccessKeyLastUsed matters for safe deactivation

Before setting Status to Inactive on the old key, call iam:GetAccessKeyLastUsed and check the LastUsedDate. If the key was used minutes ago, something still depends on it and deactivating will break a workload. A common rule: wait one full rotation cycle (or your 30/60/90-day policy window) of zero usage before deleting. If you track expiry and ownership across AWS and SaaS providers like Stripe or GitHub in a coordination layer such as KeyGuardRail, you only need metadata like last-used dates, never the secret values themselves.

How do you rotate AWS access keys without breaking running workloads?

AWS allows two access keys per IAM user, so rotation is a four-phase sequence: create the new key, propagate it to consumers, verify it is in use, then deactivate and delete the old one. AWS documents this update-your-stored-keys-then-delete pattern in the IAM User Guide on rotating access keys. The overlap window is what prevents downtime: both keys stay valid while you cut workloads over.

Phase 1: create and activate the new key

Run aws iam create-access-key for the user. The new key is active immediately, and the user now holds two active keys. Record the AccessKeyId and SecretAccessKey output somewhere safe, ideally straight into your secrets store rather than a shell history file. Tag or otherwise label the new key so you can tell the two apart in later phases.

Phase 2: propagate the new secret to consumers

Update every consumer of the old key: environment variables in ECS task definitions, Lambda config, GitHub Actions secrets, CI runners, and any .env files or Postman collections that picked it up. This is the phase that fails in practice, because secret values are copied by humans into places nobody tracks. Metadata-only tracking of where the key lives, who owns it, and when it is due for rotation, as covered in managing API keys across multiple cloud providers, keeps this list from living in one person's head.

Phase 3: verify usage on the new key

Before touching the old key, confirm the new one is actually being used. Check CloudTrail for GetCallerIdentity or service calls authenticated with the new AccessKeyId, or inspect IAM last used data. If nothing has used the new key after one full workload cycle, a consumer was missed.

Phase 4: deactivate and delete the old key

Set the old key to inactive with aws iam update-access-key --status Inactive, wait through your rollback buffer (24–48 hours is a common illustrative window), then delete it. Deactivating first, rather than deleting, gives you an instant recovery path if a straggler surfaces.

PhaseActionSafe to roll back?
1Create new keyYes, no impact
2Propagate to consumersYes, old key still valid
3Verify new key usageYes, old key still valid
4Deactivate, then delete old keyOnly until deletion

What is the two-key overlap window and how do you script around it?

AWS allows a maximum of two active access keys per IAM user. That limit exists specifically so you can create a replacement key before deactivating the old one, giving running workloads time to pick up the new credential without downtime. The overlap window is the period where both keys are valid: the script creates key #2, distributes it, waits, then deletes key #1.

Choosing an overlap duration based on last-used data

Don't guess the window. Query aws iam get-access-key-last-used for the old key before rotating. If the key was last used 20 minutes ago, a 24-hour overlap is a reasonable floor; if it drives a batch job that runs weekly, a daily rotation script will deactivate a key that job still needs. For keys with sparse usage, either lengthen the overlap to cover the longest known run interval or exclude that key from scripted rotation entirely.

The script should enforce the gap mechanically, not by convention. After creating the new key, write its age to DynamoDB or SSM Parameter Store, and have the deactivation step refuse to run until the recorded overlap has elapsed. A cron restart mid-rotation then resumes correctly instead of deactivating early. Log each state transition (created, distributed, overlap confirmed, deactivated) so an auditor can reconstruct the sequence. Ownership matters here too: every key should have a named owner and a rotation deadline attached to its metadata, which is exactly the gap between Secrets Manager and a lifecycle layer like KeyGuardRail. If your rotation cadence is shifting under AWS's September 2026 access key changes, see https://keyguardrail.com/brief/access-changes-september-2026.

Handling consumers that cache credentials at startup

Some consumers read the key once at boot and never again: a Postman collection, a long-running EC2 instance with a baked-in environment variable, a CI runner configured by hand. The overlap window protects them only until they restart into an old AMI or config. For these, the fix isn't a longer window, it's removing the human transport layer: pull the credential from Secrets Manager at startup, or attach an IAM role instead of a static key. Track which consumers still cache, and treat each one as a rotation blocker with an owner and a deadline.

How do you schedule AWS key rotation with EventBridge or cron?

Two scheduling options work: a Lambda function triggered by EventBridge Scheduler, or a cron job on infrastructure you already run. Both run the rotation script from the previous section on a fixed cadence. AWS's own guidance prefers short-term credentials over long-lived access keys, so treat this schedule as a stopgap while you migrate workloads to IAM roles (AWS IAM best practices).

EventBridge Scheduler to Lambda

Put the rotation logic in a Lambda function with the IAM permissions from section 2, then create an EventBridge Scheduler rule with a rate expression like rate(30 days). Lambda suits teams with no always-on infrastructure: no server to patch, and CloudWatch Logs gives you an audit trail of each rotation run for free.

Cron on a bastion or CI runner

If the script needs network access to SaaS providers like Stripe or GitHub alongside AWS, run it from a bastion or a scheduled CI pipeline instead. A cron entry such as 0 3 * * 1 /usr/local/bin/rotate-keys.sh is enough. The tradeoff: you now own the runner's uptime, and a missed cron run silently skips a rotation deadline.

Either way, scheduling the run is not the same as tracking it. Ownership and expiry metadata across AWS and SaaS keys still needs a home; that is the gap KeyGuardRail's guide to tracking API key expiry covers, and where a lifecycle layer complements the scheduler you just built.

How do you verify that old keys were deactivated after rotation?

A rotation script that exits 0 proves nothing. Three checks close the loop.

First, confirm state with the CLI: aws iam list-access-keys --user-name deploy-bot should show the new key Active and the old one Inactive or gone. Second, pull CloudTrail for CreateKey and UpdateAccessKey events on the user, so you have an audit trail of who or what made the change and when. Third, alert on key age: a scheduled Lambda via EventBridge Scheduler can list access keys daily and fire a warning when any key crosses your 30/60/90 day rotation policy.

The same age check applies to SaaS keys (Stripe, GitHub) that your vault stores but cannot rotate for you. KeyGuardRail tracks expiry and ownership for those without holding the secret value, so a stale key gets an owner and a deadline instead of a surprise.

What should you do with keys that cannot be rotated automatically?

Stripe restricted keys, GitHub PATs tied to a human account, and anything touching the root user resist scripting. Treat them as metadata problems: assign a named owner ("Payments platform", not "someone on the team"), record an expiry date, and enforce a 30/60/90 day rotation deadline the way you would for IAM keys.

You do not need to hold the secret value to monitor its age. A record of what exists, who owns it, and when it expires is enough to answer "who owns this key" at 2am without pasting credentials into a ticket.

That is the gap KeyGuardRail covers: credential lifecycle monitoring across AWS and SaaS providers, metadata only, no secret custody. Vaults like HashiCorp Vault or Infisical store and rotate values; KeyGuardRail tracks ownership, expiry, and audit trail so nothing expires unnoticed. Self-serve signup, Starter plan.

FAQ

How often should AWS access keys be rotated?

A common policy is 30, 60, or 90 days, enforced by a scheduled script rather than a calendar reminder. The right cadence depends on usage: query GetAccessKeyLastUsed first, because a key driving a weekly batch job needs an overlap window covering that interval. Keys with sparse usage are often safer excluded from scripted rotation entirely.

Can I rotate AWS access keys with Terraform?

Not cleanly. Terraform manages infrastructure as desired state, but key rotation is a four-phase sequence with a propagation window between creating the new key and deleting the old one. Forcing that through Terraform means replacing the resource, which deletes the old key immediately and breaks running workloads. A scheduled script using the IAM API is the better fit.

What happens if I delete an access key that is still in use?

Every consumer authenticating with that key starts failing immediately, with no recovery path, because deletion is irreversible. That is why the safe sequence deactivates first: an inactive key stops working but can be reactivated instantly if a straggler surfaces. Check GetAccessKeyLastUsed before deactivating, and only delete after a buffer with zero usage.

Does AWS Secrets Manager rotate IAM access keys for me?

No. Secrets Manager rotates secrets it stores, such as database credentials, through Lambda rotation functions, but IAM access keys for your own users are not in that scope. You script the four-phase sequence yourself using the IAM API, scheduled via EventBridge or cron, and AWS's own best-practice guidance prefers migrating to IAM roles over long-lived keys.

How do I find out who owns an AWS access key before rotating it?

IAM gives you the key's ID and last-used data, but not an owner, so ownership has to live in your own metadata. Record a named owner and team per key when it is created, stored alongside expiry and rotation deadlines. Without that record, who depends on this key is answered by asking around, which is where rotations stall.