← All articles

AWS Access Key Rotation Policy: Design and Enforce One

Key takeaways

  • Set a maximum key age of 30, 60, or 90 days for every long-lived access key and enforce it with AWS Config's access-keys-rotated rule, not human memory.
  • IAM has no condition key for access key age, so enforce deadlines through AWS Config, scheduled Lambda checks, or SCPs that restrict who can create keys.
  • Rotate without downtime using the two-key overlap sequence: create the second key, confirm the workload uses it, then delete the first.
  • Delete root user access keys entirely and replace them with MFA and break-glass IAM roles; the correct number of root keys is zero.
  • Prefer IAM roles and STS temporary credentials for workloads, reserving long-lived keys for external SaaS providers and legacy tooling that cannot assume roles.

An AWS access key rotation policy sets a hard expiry, typically 30/60/90 days, for every long-lived access key, then enforces it with IAM policy conditions, SCP guardrails, and AWS Config audit rules instead of hoping humans remember. This guide shows the actual policies, plus root keys, service accounts, and incident-time rotation.

What is an AWS access key rotation policy and which AWS controls enforce it?

An AWS access key rotation policy answers three questions for every key: how old it can get (your 30/60/90 day rotation policy), who owns it, and what happens when it expires. Most teams have the vault but not the policy. Keys get created, humans move them around, and nobody owns the deadline.

Policy vs enforcement: the two layers you need

The policy is a document: max key age per key type, a named owner, and a deadline with consequences. Enforcement is the mechanism that makes expiry real instead of aspirational. You need both; a rotation policy nobody enforces is a wiki page.

Where AWS actually enforces key age

Four native enforcement points: IAM identity policies and SCPs using condition keys like aws:MultiFactorAuthAge and key-age conditions, the credential report for audit (AWS documents iam:AccessKeyLastRotated and the credential report fields here), and AWS Config rules for continuous checks. What none of them do is track who owns a key or chase the deadline across Stripe and GitHub. That coordination layer is the gap KeyGuardRail's deletion and data handling policy exists to fill, metadata only, never the secret value.

How do you check when an access key was last rotated and last used?

Two fields answer this: AccessKeyLastRotated and AccessKeyLastUsed. Both come from IAM, so no extra tooling is needed for a first pass.

The credential report and get-account-report

iam generate-credential-report plus iam get-credential-report returns a CSV covering every IAM user in the account. Each row includes access_key_1_last_rotated, access_key_2_last_rotated, and matching last_used timestamps. Filter for keys older than 90 days and you have your violation list in one command. The report is account-wide but point-in-time, so regenerate it on a schedule.

Scripting key age with iam:AccessKeyLastUsed

For live data, call ListAccessKeys per user, then GetAccessKeyLastUsed for each key. A short Python or AWS CLI script can loop the account, compute days since rotation, and flag anything past your 30/60/90 day rotation policy. The same key-age math applies to SaaS tokens, which is why we keep policy examples for API key expiration alongside the AWS checks.

How do you write an IAM policy or SCP that blocks old access keys?

Deny-by-age pattern and its limits

The policy you want is a deny statement keyed on key age. The problem: IAM has no condition key that returns an access key's age or creation date, so you cannot write Deny when aws:keyAge > 90 the way you would deny on MFA age. The workable pattern is to enforce rotation through tooling that checks key age (AWS Config, a scheduled Lambda calling GetAccessKeyLastUsed and ListAccessKeys, or KeyGuardRail for ownership and deadline tracking) and then attach a scoped-down policy or remove the key when it fails. AWS-native enforcement of the deadline itself lives in Config and event-driven remediation, covered later in this guide.

SCP guardrails for the whole org

SCPs narrow what condition keys you can even reference. Only a subset of global condition keys work in service control policies, and key-age is not among them, so an SCP cannot deny on age directly (AWS SCP documentation on condition keys supported in service control policies). What an SCP can do is deny iam:CreateAccessKey outside your automation role and restrict iam:UpdateAccessKey to your rotation principal, so humans cannot mint new long-lived keys while your age checks police the existing ones. Track each key's owner and rotation deadline in an inventory layer rather than hoping the console tells you; the automation notes cover wiring deadline checks into CI.

How should you rotate keys for service accounts and automation that can't tolerate downtime?

Two-key overlap: the zero-downtime sequence

AWS lets each IAM user hold two access keys, which is what makes rotation without downtime possible. The sequence is: create the second key, confirm the workload is using it, then delete the first. Never delete before you've verified the new key works in production, because a CI pipeline that fails on a bad credential takes your deploys down with it.

Run create-use-update-delete in that order. Check iam:KeyLastUsed after the update step to confirm the new key has recent activity before you retire the old one. If you're rotating during an active incident, do the same thing but skip the waiting period only if you can roll back, since the old key still exists until you delete it.

Getting the new key to the workload without a human copying it

The failure point in most rotation policies isn't the AWS side, it's the handoff. If a person pastes the new secret into a Postman collection or a Slack DM, you've traded an expiring key for a leaked one. Put the secret in Secrets Manager and have the workload pull it at runtime, so the transport layer is an API call, not a human.

That leaves the coordination problem: who owns the key, when is the deadline, and did the update actually happen. That's the gap KeyGuardRail covers, tracking ownership and rotation deadlines across AWS, Stripe, and GitHub without ever holding the secret value itself. See what changed in our September 2026 access changes brief.

What do you do with the AWS account root user access keys?

The correct number of root access keys is zero. Root credentials bypass every SCP, every IAM policy, and every permission boundary, so no rotation policy you write applies to them. Delete them: sign in as root, go to IAM, Account, and remove any keys under "Access keys for the AWS account root user". If an integration somewhere is quietly using one, [iam:KeyLastUsed] will show it before you delete.

Replace root access with MFA on the root user (hardware key preferred) and break-glass IAM roles held by named humans. AWS Config's managed rules access-keys-rotated and root-account-mfa-enabled give you the audit signal that root keys stay gone and MFA stays on. The same ownership-tracking gap applies to any break-glass role: log who holds it and when it was last exercised, or it becomes the next orphaned credential.

How does AWS Config audit compliance with your rotation policy?

The managed rules that matter

Two AWS Config managed rules cover most of your policy. access-keys-rotated flags IAM user keys older than your threshold, so set maxAccessKeyAge to 90 days to match a 30/60/90 rotation policy. root-account-keys fires when the root user has active access keys at all, since the correct count is zero. Both rules evaluate continuously and mark resources noncompliant without touching the secret value, which keeps Config out of your vault's threat model.

Conformance packs and alert routing

A conformance pack bundles both rules plus your SCP checks into one deployable YAML template, so every account in your organization runs the same audit. Add REQUIRED_TAGS rules to confirm each key-bearing user carries an owner tag like Platform engineering or Payments platform.

For alerting, point Config at an EventBridge rule matching ConfigRulesEvaluationStarted or compliance-change events, then route to SNS and a Lambda that posts to Slack or creates a PagerDuty incident. Route root-key findings to PagerDuty and key-age drift to Slack, so the severity matches the risk.

How does rotation differ from switching to IAM Roles or short-lived STS credentials?

What roles actually remove from your plate

Rotation is a cleanup for a problem you created: a credential with no expiry date. IAM roles and STS-issued temporary credentials remove that problem for most workloads. An EC2 instance profile, an EKS IRSA role, or a Lambda execution role gets credentials that AWS issues and expires on a schedule, so there is no key age to police, no IAM condition to write, and no Config rule to fail. AWS's own guidance is to prefer roles over long-lived access keys: IAM best practices recommend deleting root user access keys and using roles for AWS access wherever possible.

The keys you cannot retire yet

Three cases keep long-lived keys alive. First, external SaaS providers like Stripe or GitHub authenticate to your AWS account with a static key, because they cannot assume your roles. Second, a third-party AWS account outside your organization cannot be granted a role unless its owners cooperate. Third, legacy tooling hard-coded to static keys resists refactoring. For those residuals, the rotation policy from earlier sections still applies, and an ownership and expiry record matters most where automation cannot reach.

How do you track ownership and deadlines across AWS and your SaaS providers?

IAM conditions and Config rules cover AWS only. They cannot tell you who owns the Stripe API key, when the GitHub PAT expires, or whether the "Payments platform" team knows a rotation deadline is next week. That gap is where secrets sprawl lives: the vault holds values, but nothing tracks ownership and expiry as metadata across providers.

Comparing options on lifecycle, not custody

ToolHolds secret values?Tracks owner/expiry across AWS + SaaS?Rotation?
AWS Secrets ManagerYesAWS onlyNative rotation lambdas
DopplerYesPartial, vault-centricVault-managed
HashiCorp VaultYesVault-centricVault-managed
InfisicalYesVault-centricVault-managed
KeyGuardRailNoYes, metadata onlyNone

KeyGuardRail's honest limits: it never sees a secret value and rotates nothing. You keep your vault and your 30/60/90 day rotation policy; KeyGuardRail tracks which key, whose owner, which deadline, and what happens next. If you want a tool to move values for you, pick Doppler, HashiCorp Vault, or Infisical instead.

FAQ

How often should AWS access keys be rotated?

Pick one of 30, 60, or 90 days as your maximum key age and apply it consistently across every long-lived key. Shorter is safer but raises operational load, so 90 days is a common starting point for teams without full automation. Enforce your threshold with AWS Config's access-keys-rotated rule and delete root user keys entirely rather than rotating them.

Does AWS automatically rotate IAM access keys for me?

No. IAM access keys are long-lived credentials that stay valid until you create and delete them manually. AWS issues short-lived, auto-expiring credentials only through IAM roles and STS, which is why migrating workloads to instance profiles, IRSA, or Lambda execution roles removes the rotation problem entirely. For keys that must remain, the two-key overlap sequence handles rotation without downtime.

What happens if I rotate a key that a running service is using?

If you follow the two-key overlap sequence, nothing breaks: create the second key, confirm the workload has pulled it and shows recent activity under iam:KeyLastUsed, then delete the first. If you delete the active key before the workload has the new one, every request it signs fails, which for a CI pipeline means failed deploys until the credential is fixed.

How do I find who owns an access key in my AWS account?

AWS gives you the key's age and last-used data through the credential report and GetAccessKeyLastUsed, but no native field records who owns a key or which team depends on it. Your options are an owner tag on each key-bearing IAM user checked by a REQUIRED_TAGS Config rule, or an external inventory tracking ownership and deadlines as metadata across AWS and SaaS providers.

Can I enforce key rotation with AWS Config only, without IAM policy changes?

Config audits but does not enforce. The access-keys-rotated and root-account-keys rules flag noncompliant keys continuously, and you can route findings through EventBridge to Slack or PagerDuty, but nothing stops an old key from working. Enforcement needs a remediation step, such as a scheduled Lambda that disables or deletes keys past your threshold, or SCPs restricting who can create keys.