Join our Newsletter — 33% off our NHI Course
Home› Guides› How to find unrotated secrets in AWS Secrets…
Guide Secrets Management

How to find unrotated secrets in AWS Secrets Manager: Find stale secrets, failed rotations and fix them

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 11 November 2026 13 min read
On this page

A secret stored in AWS Secrets Manager is not a rotated secret: many accounts hold database passwords and API keys that have sat unchanged for years because rotation was never turned on, was turned on and keeps failing, or was replaced by someone pasting new values by hand. This runbook shows how to find all three cases with the data AWS already exposes: the ListSecrets fields, the three AWS Config managed rules for rotation, the matching Security Hub controls and the rotation events in CloudTrail. It then covers how to triage what you find, fix rotation safely and keep the problem from returning. It is written for cloud security and platform engineers working in one account or across an AWS Organization. For how rotation itself is designed and how the access model works, see the AWS Secrets Manager guide; this page is the discovery task.

This is an independent guide from NHI Mgmt Group, based on AWS's public documentation as of November 2026. It is not sponsored or reviewed by AWS. Product features change, so confirm settings against AWS's current documentation.

Key takeaways

  • There are three kinds of unrotated secret. Rotation off (RotationEnabled false), rotation on but failing (no RotationSucceeded for longer than the schedule), and rotation never completed (LastRotatedDate null). Each needs a different fix.
  • ListSecrets gives you the whole picture for free. One paginated call per Region returns RotationEnabled, LastRotatedDate, NextRotationDate, LastChangedDate, LastAccessedDate and OwningService for every secret.
  • AWS Config covers it continuously. secretsmanager-rotation-enabled-check, secretsmanager-scheduled-rotation-success-check and secretsmanager-secret-periodic-rotation map to Security Hub controls SecretsManager.1, .2 and .4.
  • Failing rotation is the dangerous case. It looks compliant in a "rotation enabled" report while the value stays the same, and a stuck AWSPENDING label blocks the next attempt.
  • Test before you schedule. rotate-secret --no-rotate-immediately runs only the test step, so you can prove a fixed rotation function works before any application sees a new value.

When you need this

  • Audit or compliance finding: Security Hub reports failed SecretsManager.1 or SecretsManager.4 findings, or an auditor asks for the age of every stored credential under NIST SP 800-53 IA-5.
  • After a leak or a supplier breach: you need to know which secrets would still work for an attacker who copied them months ago. The Internet Archive breach shows how keys left unrotated after a first exposure became the route to a second compromise.
  • Migration into Secrets Manager: teams often move a secret in, tick the project done and never configure rotation.
  • Before tightening policy: enforcing a 90 day maximum age is easier once you know how many secrets fail it today.

Before you start

SourceWhat it tells youCost and permissionLimit to know
ListSecrets / DescribeSecretRotation flag, schedule, last and next rotation, last change, last access, owning service, rotation function ARNsecretsmanager:ListSecrets, secretsmanager:DescribeSecret; standard API pricingPer Region; ListSecrets can lag about five minutes; secrets scheduled for deletion are excluded unless IncludePlannedDeletion is set
Config rule secretsmanager-rotation-enabled-checkSecret not scheduled for rotation, or schedule longer than maximumAllowedRotationFrequencyAWS Config recorder and rule evaluations are chargedConfiguration change trigger; re-evaluating within 4 hours has no effect
Config rule secretsmanager-scheduled-rotation-success-checkThe calculated rotation date passed without a successful rotationAs aboveResults can lag up to 2 days; NOT_APPLICABLE for secrets without rotation
Config rule secretsmanager-secret-periodic-rotationSecret not rotated for more than maxDaysSinceRotation (default 90)As abovePeriodic trigger
CloudTrail rotation eventsRotationStarted, RotationSucceeded, RotationFailed, RotationAbandonedEvent history free for 90 days; a trail for longerEvent history is per Region
Rotation function logsWhich of the four steps failed and whyCloudWatch Logs read accessOnly for Lambda based rotation

Run discovery from a read-only role. ListSecrets and DescribeSecret return metadata, not values, so the discovery role needs no GetSecretValue and no kms:Decrypt; keep it that way. Agree the age threshold first. Ninety days is the default for both the Config rule and SecretsManager.4, and Security Hub accepts 1 to 180 days. Pick a lower number for high-impact credentials such as database administrator passwords.

Step-by-step

Steps 1 to 5 are read-only. Step 6 changes configuration but is tested first. Step 7 rotates values and can affect applications.

  1. Export the inventory, Region by Region. The CLI paginates automatically:
    aws secretsmanager list-secrets --region eu-west-2 --include-planned-deletion \
      --query "SecretList[].{Name:Name,Enabled:RotationEnabled,LastRotated:LastRotatedDate,Next:NextRotationDate,Changed:LastChangedDate,Accessed:LastAccessedDate,Owner:OwningService,Fn:RotationLambdaARN}" \
      --output json > secrets-eu-west-2.json
    Repeat for every enabled Region, and in every account through a read-only role. Keep the files: they are your baseline and your evidence.
  2. Bucket every secret. Classify each row with the fields AWS documents:
    BucketSignalMeaning
    A. Never set upRotationEnabled false or absent; NextRotationDate nullRotation is not configured or was cancelled
    B. Never succeededRotation enabled, LastRotatedDate nullAWS sets this field only when rotation completes successfully
    C. OverdueRotation enabled, LastRotatedDate older than the schedule plus a marginRotation has been failing since that date
    D. Too slowRotation enabled and working, but AutomaticallyAfterDays or the schedule exceeds your maximumCompliant in AWS's eyes, not in yours
    E. Changed by handLastChangedDate recent but LastRotatedDate old or nullLikely manual PutSecretValue or UpdateSecret; confirm in CloudTrail before assuming
    A quick filter for bucket A in one Region:
    aws secretsmanager list-secrets --query "SecretList[?RotationEnabled!=\`true\`].Name" --output text
  3. Separate managed secrets. Secrets created by another AWS service carry the service ID in the name (ServiceID!MySecret, for example rds!) and in OwningService. You can list them with the owning-service filter key:
    aws secretsmanager list-secrets --filters Key=owning-service,Values=rds
    Some managed secrets use managed rotation with no Lambda function, and the managing service may restrict updates. Fix these through the owning service's settings, not by attaching your own rotation function.
  4. Turn on the Config rules for continuous findings. Deploy secretsmanager-rotation-enabled-check (set maximumAllowedRotationFrequency to your maximum in days), secretsmanager-scheduled-rotation-success-check and secretsmanager-secret-periodic-rotation (set maxDaysSinceRotation). If Security Hub is enabled, the same checks appear as SecretsManager.1, .2 and .4; set their parameters to the same values so the two views agree. In an organisation, use a delegated administrator and an aggregator so one team sees every account. See the AWS Config Guide and the AWS Security Hub Guide.
  5. Find failing rotations in CloudTrail. For buckets B and C, confirm the failure and its date:
    aws cloudtrail lookup-events --region eu-west-2 \
      --lookup-attributes AttributeKey=EventName,AttributeValue=RotationFailed
    Then open the rotation function's CloudWatch log group and find which of the four steps (createSecret, setSecret, testSecret, finishSecret) stopped. Check the staging labels with aws secretsmanager describe-secret --secret-id <name>: an AWSPENDING label on a different version from AWSCURRENT means a rotation stopped part way, and AWS documents that a new RotateSecret call will return an error until that label is removed.
  6. Fix, then test without rotating. Correct the cause (see the table below), then run only the test step:
    aws secretsmanager rotate-secret --secret-id <name> --no-rotate-immediately
    AWS states that with RotateImmediately false, Secrets Manager runs the function's testSecret step, creating an AWSPENDING version and then removing it. Watch for TestRotationSucceeded or TestRotationFailed in CloudTrail. For bucket A, configure rotation with the same flag and a cron() schedule, which AWS recommends over rate() when you change an existing schedule, because a previously scheduled rotation might still run.
  7. Rotate. When the test passes and the application owner agrees a window, run aws secretsmanager rotate-secret --secret-id <name> (the default rotates immediately) and confirm RotationSucceeded. Rotate high-impact secrets in a change window with the owning team watching their error rates.

Where identity fits

Every secret in this inventory is the credential of a non-human identity: a database account, a service user in a SaaS platform, an API client. Rotating the value in Secrets Manager is only half the job. For each secret in buckets A to C, record which system account it authenticates as, which IAM roles can call GetSecretValue on it, and whether a credential-free option exists (IAM database authentication, workload identity federation, a managed integration). A secret you can remove entirely is better than one you rotate well. The How to Map service account dependencies before rotation guide covers finding every consumer before you change a value, which is the step that prevents most rotation outages.

Why rotations fail

Log symptomLikely cause (per AWS)Fix
Nothing after "Found credentials in environment variables"The function cannot reach the Secrets Manager endpointInterface VPC endpoint or NAT route
Nothing after "createSecret"Network ACLs, endpoint policy or security groups block HTTPS; timeout too short; database API unreachableFix network path, raise the timeout
"Access to KMS is not allowed"The function lacks decrypt on the customer managed keyUpdate the key policy; see the AWS KMS Security Guide
"Key is missing from secret JSON"Secret structure does not match what the function expectsRestore the documented JSON structure
"setSecret: Unable to log into database"The stored credential is already wrong, or a network or TLS issueVerify the current credential works; check security groups both ways
"Unable to import module 'lambda_function'"Function runtime upgraded from Python 3.7Upgrade the function code to a supported runtime
RotationFailed, pending version "not created by Lambda"Cross-account or assumed-role rotation without RotationTokenPass RotationToken to PutSecretValue

Prioritise the work

Rank by what the secret unlocks, not by age alone. Put first any secret in bucket B or C that grants administrator or write access to a production database or a third-party API, then anything with a recent LastAccessedDate (in use, so worth an attacker's effort), then bucket A secrets for production. Secrets with no LastAccessedDate at all have never been retrieved in that Region: they may be candidates for deletion rather than rotation (Security Hub SecretsManager.3 flags unused secrets, default 90 days).

Verify it worked

  • Per secret: describe-secret shows LastRotatedDate updated, NextRotationDate set and AWSPENDING gone.
  • Events: a RotationSucceeded event for each fixed secret, and an EventBridge "Secret Label Updated" event with labelUpdated AWSCURRENT.
  • Findings: the Config rules and Security Hub controls move to compliant. Allow for the up to 2 day lag on the success check.
  • Applications: no rise in authentication errors from consumers after rotation; clients using the AWS caching components pick up the new value on their next refresh.

Rollback and common errors

SituationFix
Application fails after rotationAWSPREVIOUS still holds the prior value; move AWSCURRENT back with update-secret-version-stage while you fix the consumer, and check whether the old credential is still valid on the target system
RotateSecret errors with rotation already in progressA stuck AWSPENDING label; confirm AWSCURRENT still works, remove the pending label, retry
Rotation loops between createSecret and setSecretAWS points to concurrency throttling or a race; set reserved concurrency to at least 10 or leave it unset, and avoid manual PutSecretValue during rotation
RotationAbandoned in CloudTrailSomeone wrote a new version during rotation; agree that rotation, not people, owns the value
Changing a schedule triggers an unexpected rotationUse cron() with --no-rotate-immediately when changing an existing schedule

Hardening afterwards

  • Alert on failure, not just on age: an EventBridge rule on RotationFailed (detail-type "AWS Service Event via CloudTrail") gives you hours, not the days the Config check can take.
  • Require rotation at creation: add the rotation configuration to the infrastructure as code module that creates secrets, so bucket A cannot grow.
  • Stop manual edits: limit PutSecretValue and UpdateSecret to the rotation function and break-glass roles, and alert on other callers.
  • Prefer managed rotation: where the owning service offers it, there is no rotation code to break.
  • Measure age centrally: track rotation coverage alongside other credential stores. See How to Measure Secret Age and Rotation Coverage.

Small account or large organisation

A single account with a few dozen secrets can run step 1 weekly in a small script and skip AWS Config. An organisation with hundreds of accounts should deploy the three rules through a conformance pack or Security Hub central configuration, aggregate findings to one account and give each finding an owner from a mandatory tag (SecretsManager.5 checks tags). Do the rotation fixes team by team: the hard part is application readiness, not the API.

Metrics

MetricTarget
Secrets with rotation enabled (excluding documented exceptions)Rising towards 100%
Enabled secrets with no successful rotation inside scheduleZero
Secrets older than the maximum ageZero
Mean time from RotationFailed to fixUnder one business day
Manual value changes outside rotation per monthFalling

Common failure patterns

  • Reporting "rotation enabled" as success: SecretsManager.1 passes for a secret whose function has failed every night for a year. Always pair it with the success check.
  • Rotating the secret but not the credential: a custom function that writes a new value without changing it on the target system leaves the old password valid. The testSecret step must actually log in.
  • Single Region view: ListSecrets and CloudTrail event history are Regional; secrets in rarely used Regions are the ones nobody rotates.
  • Clearing AWSPENDING without checking AWSCURRENT: AWS's own recovery steps start by confirming the current value works.
  • Fixing managed secrets by hand: editing a rds! secret outside the owning service can break that service.

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev 5IA-5 Authenticator Management; IA-5(1) Password-based AuthenticationChange authenticators on a defined schedule and after compromise
NIST SP 800-53 Rev 5AU-6 Audit Record ReviewReview rotation failure events
NIST CSF 2.0PR.AA-01Credentials for services managed by the organisation
NIST CSF 2.0DE.CM-09Monitor for failed rotations and manual changes
MITRE ATT&CKT1555.006 Cloud Secrets Management StoresRotation limits how long stolen values stay useful

Practitioner checklist

  • Export ListSecrets for every account and enabled Region, including planned deletions.
  • Bucket each secret: never set up, never succeeded, overdue, too slow, changed by hand.
  • Set managed secrets aside and handle them through the owning service.
  • Deploy the three Config rules, aligned with SecretsManager.1, .2 and .4 parameters.
  • Diagnose failures from RotationFailed events and the rotation function's logs.
  • Test fixes with --no-rotate-immediately before any live rotation.
  • Alert on RotationFailed through EventBridge and restrict manual value changes.
  • Track rotation coverage and age as standing metrics.

Standards and references

Related NHI Mgmt Group resources: AWS Secrets Manager · Credential Rotation at Scale · How to Rotate database credentials without downtime · Secret Rotation Outage Troubleshooting Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.