A rotation policy attaches a schedule and a rotator plugin to a secret path. When the schedule fires, SM rewrites the value, invalidates the old lease, and writes a signed rotation attestation to the audit stream.

Create a rotation policy (KV)

tt secrets rotation-policies create \
  --path=secret/prod/db/password \
  --schedule="0 0 * * 0"       \
  --rotator=random-string      \
  --rotator-args=length=48

Create a rotation policy (database)

Database engines rotate at the role level — SM issues a fresh username/password from the DB and revokes the previous one:
tt secrets rotation-policies create \
  --path=database/roles/prod-postgres \
  --schedule="@daily" \
  --rotator=db-role
Every dynamic credential inherits the current root — rotate the root and every issued credential is revoked and re-minted transparently to callers using tt-secrets-agent.

Attestations

Every rotation writes a signed attestation:
{
  "policy_id":  "rp_xxx",
  "path":       "secret/prod/db/password",
  "previous_version": 12,
  "new_version": 13,
  "rotated_at": "2026-09-18T02:00:00Z",
  "signature":  "sig:v1:..."
}
Verify with tt secrets rotation-policies verify rp_xxx --version=13. Attestations satisfy the “prove this secret was rotated within N days” line item on most audits.

Emergency rotation

tt secrets rotation-policies rotate-now rp_xxx --reason="incident #4821"
Bypasses the schedule and writes an incident-linked attestation.

Engines

KV, transit, PKI, database rotator plugins.

Policies

Who can force emergency rotation vs schedule-only.