Back to blog
AWSBest PracticesCloud SecurityIdentity & AccessServerless

Secret Rotation Window Too Short in AWS Secrets Manager

Why AWS Secrets Manager rotation windows under 30 days cause failed rotations and outages, plus CLI, Terraform, and policy-as-code fixes.

TL;DR

This check flags AWS Secrets Manager secrets set to rotate on a window shorter than 30 days. Aggressive rotation schedules can trigger failed rotations, app outages, and locked-out workloads when the rotation Lambda cannot keep up. Set a rotation interval of 30 days or more unless you have a documented reason for tighter cycles, and confirm your rotation function actually succeeds.

Rotating secrets is good hygiene. Rotating them too aggressively is a different kind of risk. When a Secrets Manager secret is configured with a rotation window under 30 days, you increase the chance of rotation collisions, half-applied credentials, and dependent services authenticating against a value that no longer exists. Lensix raises secretsmanager_smallrotation when it finds a secret whose rotation interval falls below that 30 day threshold.

This post explains what the check looks at, why a short rotation window can quietly break production, and how to bring your secrets back to a safe cadence.


What this check detects

Secrets Manager lets you attach an automatic rotation schedule to a secret. That schedule is defined either by a number of days (AutomaticallyAfterDays) or, in newer configurations, a cron or rate expression in RotationRules.ScheduleExpression. When you enable rotation, AWS invokes a Lambda function that runs a four step process: create a new secret version, set it on the backing resource, test it, and finalize it.

The secretsmanager_smallrotation check inspects each secret's rotation configuration and flags any secret where the effective rotation interval is shorter than 30 days. So a secret set to rotate every 7 days, or every 14 days, would be reported.

Note: This check is not telling you that rotation is bad. A secret with no rotation at all is usually a worse finding. The concern here is specifically a window that is too tight for the rotation process to run reliably and for dependent systems to pick up the change.

What the configuration looks like

You can see a secret's rotation settings with the CLI:

aws secretsmanager describe-secret \
  --secret-id prod/payments/db-credentials \
  --query '{Rotation: RotationEnabled, Rules: RotationRules, Lambda: RotationLambdaARN}'

A flagged result might return something like this:

{
  "Rotation": true,
  "Rules": {
    "AutomaticallyAfterDays": 7
  },
  "Lambda": "arn:aws:lambda:us-east-1:111122223333:function:rotate-db-creds"
}

An interval of 7 days is well under the threshold, so Lensix flags it.


Why it matters

Short rotation windows feel like they should be safer. More rotation means a stolen credential is valid for less time, right? That logic holds for the credential lifetime, but it ignores the operational cost of rotation itself, which is where most outages come from.

Rotation can fail, and short windows multiply the chances

Every rotation is a small, multi-step state change against a live resource: a database, an API, an IAM access key. Rotation functions fail for ordinary reasons, including throttling, network timeouts, a database failover mid-rotation, or a permissions drift on the Lambda execution role. The more often you rotate, the more times you roll those dice. A 7 day cadence runs the rotation pipeline roughly four times more often than a 30 day cadence, and each run is a chance for a partial failure that leaves a secret in an inconsistent state.

Dependent applications need time to catch up

When a secret rotates, every consumer needs to fetch the new value. Applications that cache secrets, connection pools that hold long-lived database sessions, and batch jobs that only run weekly may still be using the previous version when the next rotation kicks in. If two rotations happen close together, the older version Secrets Manager keeps around (the AWSPREVIOUS staging label) can be replaced before a slow consumer ever reads it. The result is authentication failures that look random and are painful to trace.

Warning: Secrets Manager keeps a limited set of staged versions. A very tight rotation interval can cycle the AWSPREVIOUS version out before lagging clients pick up AWSCURRENT, which produces intermittent auth errors that are hard to reproduce.

Cost and noise

Each rotation invokes a Lambda, makes API calls, and may open connections to the backing resource. None of that is expensive on its own, but frequent rotation across hundreds of secrets adds up in invocation costs and CloudWatch noise, and it buries genuine rotation failures in alert fatigue.

The risk it is meant to reduce is often overstated

The security upside of going from 30 days to 7 days is marginal in most threat models. If an attacker has a valid credential, they typically exfiltrate or pivot within minutes or hours, not weeks. Shrinking the window from 30 days to 7 does little against that, while measurably increasing your operational exposure. The exception is high-value, machine-to-machine credentials with a clear compliance mandate, which we cover below.


How to fix it

The fix is to set the rotation interval to 30 days or more, confirm the rotation function works, and verify dependent services tolerate the change. Do not simply disable rotation to clear the finding.

Step 1: Identify the affected secrets

aws secretsmanager list-secrets \
  --query "SecretList[?RotationEnabled==\`true\`].[Name,RotationRules.AutomaticallyAfterDays]" \
  --output table

Anything with a value under 30 in the second column should be reviewed.

Step 2: Update the rotation interval

Use rotate-secret with a new rotation rule to set a 30 day window:

aws secretsmanager rotate-secret \
  --secret-id prod/payments/db-credentials \
  --rotation-lambda-arn arn:aws:lambda:us-east-1:111122223333:function:rotate-db-creds \
  --rotation-rules '{"AutomaticallyAfterDays": 30}'

Danger: Calling rotate-secret triggers an immediate rotation in addition to changing the schedule. On a production secret that means a live credential change right now. Run this during a maintenance window, or set the schedule using a ScheduleExpression with RotateImmediately set to false (shown below) so you only change the cadence.

To change the cadence without forcing an immediate rotation, use a schedule expression and disable the immediate rotate:

aws secretsmanager rotate-secret \
  --secret-id prod/payments/db-credentials \
  --rotation-rules '{"ScheduleExpression": "rate(30 days)"}' \
  --no-rotate-immediately

Step 3: Confirm the change

aws secretsmanager describe-secret \
  --secret-id prod/payments/db-credentials \
  --query 'RotationRules'

You should see the updated interval reflected.

Console steps

  1. Open the Secrets Manager console and select the secret.
  2. Scroll to Rotation configuration and choose Edit rotation.
  3. Under Rotation schedule, set the interval to 30 days or more, or define an equivalent schedule expression.
  4. Leave Rotate secret immediately when stored unchecked unless you intend to force a rotation now.
  5. Save.

Terraform

If you manage secrets as code, set the interval in the rotation rules block:

resource "aws_secretsmanager_secret_rotation" "db_creds" {
  secret_id           = aws_secretsmanager_secret.db_creds.id
  rotation_lambda_arn = aws_lambda_function.rotate_db_creds.arn

  rotation_rules {
    automatically_after_days = 30
  }
}

Tip: Before pushing a cadence change to dozens of secrets, test against one non-production secret and watch the rotation Lambda's CloudWatch logs through a full rotation cycle. Confirm all four steps (createSecret, setSecret, testSecret, finishSecret) complete cleanly.


How to prevent it from happening again

Manual fixes drift back over time. Bake the policy into the places where secrets get created and changed.

Validate in CI with policy-as-code

If you use Terraform, an OPA or Conftest policy can block plans that set a rotation interval below 30 days. Here is a Rego rule that fails the build:

package terraform.secrets

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_secretsmanager_secret_rotation"
  days := resource.change.after.rotation_rules[_].automatically_after_days
  days < 30
  msg := sprintf("Secret rotation for %s is %d days; minimum allowed is 30", [resource.address, days])
}

Wire that into your pipeline against a terraform plan -out converted to JSON, so the gate runs before any apply.

Detect drift at runtime

Console clickops and one-off CLI calls bypass your IaC gates. Keep Lensix scanning continuously so a manually shortened window surfaces as a finding within your normal review cycle rather than during an incident. Pairing a CI gate with continuous scanning covers both the create path and the drift path.

Standardize on a module

If teams provision secrets through a shared Terraform module, set the default automatically_after_days to 30 and validate the input variable so nobody can pass something smaller without an explicit override:

variable "rotation_days" {
  type    = number
  default = 30

  validation {
    condition     = var.rotation_days >= 30
    error_message = "Rotation interval must be at least 30 days."
  }
}

Best practices

  • Default to 30 to 90 days. For most database and service credentials, a rotation window in the 30 to 90 day range balances security and reliability. Reserve tighter windows for cases with a real mandate.
  • Always test the rotation function end to end. A rotation schedule is only as good as the Lambda behind it. Confirm the testSecret step actually authenticates against the backing resource so a broken rotation surfaces before it ships a dead credential.
  • Fetch secrets fresh, do not cache forever. Use the AWS Secrets Manager caching client or the Lambda extension with a sane TTL so applications pick up rotated values without restarts and without holding stale ones indefinitely.
  • Alert on rotation failures. Create a CloudWatch alarm or an EventBridge rule on Secrets Manager rotation failure events so a silent failure does not sit unnoticed until the next deploy.
  • Document any exception. If a specific secret genuinely needs a short window, record why, and make sure its consumers are built to handle frequent rotation gracefully.
  • Use multi-user rotation for databases. The alternating users strategy keeps one credential valid while the other rotates, which removes most of the downtime risk from frequent rotation if you do need it.

Note: Multi-user rotation requires two database users and a rotation function that supports the alternating-users strategy. AWS provides templates for this for several engines, and it is the most reliable way to rotate without a connection blip.

The goal is not the fastest possible rotation. It is rotation you can trust to run unattended without breaking the services that depend on it. A 30 day floor gives the rotation pipeline and your consumers the room they need, and it clears the secretsmanager_smallrotation finding without trading one risk for a worse one.