Skip to main content
Version: 7.0

Secret rotation practices

Why rotate secrets

Regular secret rotation helps mitigate risks:

RiskHow rotation helps
Password leakA compromised password becomes invalid quickly
Long-lived tokensShorter lifetimes reduce the attack window
Insider threatsFormer employees lose access after rotation
Compliance requirementsStandards like PCI DSS and SOC 2 mandate regular password changes

Rotation workflow

┌─────────────────────────────────────────────────────────────┐
│ 1. Generate 2. Target system 3. Passwork │
│ new password (update) (save) │
│ │
│ openssl rand ──► ALTER ROLE ... ──────► passwork-cli update│
└─────────────────────────────────────────────────────────────┘
Important: order of operations

First update the password in the target system (database, service), then save it to Passwork. Otherwise you'll have a mismatch: Passwork holds the new password while the system still uses the old one.

Rotation via CLI

PostgreSQL

#!/bin/bash
set -e

ITEM_ID="<item-id>"
DB_USER="order_service"

# 1. Generate new password
NEW_PASS=$(openssl rand -base64 32)

# 2. Apply to PostgreSQL
psql -h pg.prod.internal -U postgres -d postgres -c \
"ALTER ROLE ${DB_USER} WITH PASSWORD '${NEW_PASS}';"

# 3. Store in Passwork
passwork-cli update --password-id "${ITEM_ID}" --password "${NEW_PASS}"

echo "Password rotated for ${DB_USER}"

MySQL

#!/bin/bash
set -e

ITEM_ID="<item-id>"
DB_USER="inventory_svc"

NEW_PASS=$(openssl rand -base64 32)

mysql -h mysql.prod.internal -u root -p"${MYSQL_ROOT_PASSWORD}" -e \
"ALTER USER '${DB_USER}'@'%' IDENTIFIED BY '${NEW_PASS}';"

passwork-cli update --password-id "${ITEM_ID}" --password "${NEW_PASS}"

echo "Password rotated for ${DB_USER}"

API key

#!/bin/bash
set -e

ITEM_ID="<item-id>"

# 1. Request a new key from the external service
NEW_KEY=$(curl -s -X POST https://api.service.com/keys/rotate \
-H "Authorization: Bearer ${OLD_KEY}" | jq -r '.new_key')

# 2. Store in Passwork
passwork-cli update --password-id "${ITEM_ID}" --password "${NEW_KEY}"

echo "API key rotated"

Rotation via Python SDK

Complete example with error handling:

#!/usr/bin/env python3
"""PostgreSQL password rotation script."""

import os
import secrets
import sys
import psycopg2
from passwork import Client


def rotate_password(item_id: str, db_user: str) -> bool:
"""
Rotate the password for a PostgreSQL user.

Returns:
True on success, False on failure.
"""
client = Client(
url=os.environ["PASSWORK_HOST"],
token=os.environ["PASSWORK_TOKEN"],
)

# Fetch admin credentials from Passwork
admin_item = client.get_password(
item_id=os.environ["PG_ADMIN_ITEM_ID"]
)

# Create new password
new_password = secrets.token_urlsafe(32)

try:
# Connect to PostgreSQL
conn = psycopg2.connect(
host=admin_item.fields["PG_HOST"],
dbname="postgres",
user=admin_item.login,
password=admin_item.password,
)
conn.autocommit = True

# Apply new password
with conn.cursor() as cur:
cur.execute(
"ALTER ROLE %s WITH PASSWORD %s",
(db_user, new_password)
)
conn.close()

# Persist to Passwork
item = client.get_password(item_id=item_id)
item.password = new_password
client.update_password(item)

print(f"Password rotated for {db_user}")
return True

except psycopg2.Error as e:
print(f"Database error: {e}", file=sys.stderr)
return False

except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return False


if __name__ == "__main__":
success = rotate_password(
item_id=os.environ["TARGET_ITEM_ID"],
db_user=os.environ["PG_USER"],
)
sys.exit(0 if success else 1)

Scheduling rotation

Cron job

# /etc/cron.d/passwork-rotation
# Rotate DB passwords every Sunday at 3:00 AM

0 3 * * 0 passwork /opt/scripts/rotate-db-passwords.sh >> /var/log/rotation.log 2>&1

Recommendations

Rotation frequency

Secret typeSuggested frequency
Production DB passwords30–90 days
External service API keys90 days or per vendor policy
Service tokens7–30 days
SSH keys6–12 months