LLM API Key Rotation Automation Script: A Working Setup
Why you need an LLM API key rotation automation script
If you're searching for a rotation script, you already know the problem: your LLM provider key is sitting in environment variables across staging, production, CI, and a couple of laptops, and nobody is confident it hasn't leaked into a log line or a git history somewhere. Rotating it manually — generate new key, update every environment, revoke old key, hope nothing breaks — is exactly the kind of task that gets postponed until an incident forces it.
An automation script for LLM API key rotation does three things reliably: generates a new key on a schedule (or on demand), pushes it to every place that consumes it, and revokes the old key only after confirming the new one works. Below is a practical pattern you can adapt regardless of which LLM provider you're using, plus a simpler alternative if you're tired of owning this problem entirely.
What "rotation" actually needs to solve
Before writing a script, be clear on what you're protecting against:
- Leaked keys — committed to a repo, printed in logs, pasted into a support ticket.
- Long-lived credentials — a key that's been valid for 18 months is a bigger liability than one valid for 30 days, even if it's never leaked.
- Blast radius — one key used everywhere means one leak compromises everything.
- Downtime during rotation — if you revoke the old key before the new one propagates, requests start failing.
A good rotation script handles the last point by overlapping validity windows: the old key stays active until the new one is confirmed working in every consumer.
A basic rotation script pattern
Most providers expose key creation and revocation through an admin API or console. The shape of the automation is the same regardless:
#!/usr/bin/env bash
set -euo pipefail
# 1. Create a new key
NEW_KEY=$(curl -s -X POST "$PROVIDER_ADMIN_URL/keys" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "prod-'"$(date +%Y%m%d)"'"}' | jq -r '.key')
# 2. Push to secrets manager
aws secretsmanager put-secret-value \
--secret-id llm-api-key \
--secret-string "$NEW_KEY"
# 3. Trigger a rolling redeploy or config reload
kubectl rollout restart deployment/api-worker
# 4. Health check against the new key
sleep 30
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $NEW_KEY" \
"$PROVIDER_API_URL/health")
if [ "$STATUS" != "200" ]; then
echo "New key failed health check, aborting revocation"
exit 1
fi
# 5. Revoke the old key (only after health check passes)
curl -s -X DELETE "$PROVIDER_ADMIN_URL/keys/$OLD_KEY_ID" \
-H "Authorization: Bearer $ADMIN_TOKEN"
Run this on a cron schedule (every 30–90 days is reasonable) or trigger it manually the moment you suspect a leak. The critical detail is step 4: never revoke on a timer without confirming the new key actually works, or you'll cause an outage in the name of security hygiene.
Handling multiple environments
If you have staging, production, and CI all sharing one provider key, rotation gets harder because you have to push to N places atomically. Two options:
- Fan-out from one secrets manager. Store the key once (AWS Secrets Manager, HashiCorp Vault, Doppler) and have every environment read it at boot rather than baking it into config files. Rotation then only touches one place.
- Separate keys per environment. Slower to set up but means a leak in staging logs doesn't touch production, and you can rotate environments independently.
Option 2 is the better default if your provider lets you create keys cheaply.
Where this gets harder than it looks
The script above assumes one shared secret across your whole team. In practice, most teams eventually want per-service or per-developer keys so a leak or misuse can be traced and revoked without regenerating everything. That means your rotation automation now has to track ownership, usage, and revocation per key, not just per environment — which is a lot more state to manage in a bash script.
This is the exact problem SubToAPI solves for teams building on Claude. Instead of rotating one provider credential everywhere, you generate scoped application keys (sub_live_...) per service or per team member from a dashboard, see usage per key, and revoke individually — no shared secret to rotate across environments in the first place. Rotation becomes "revoke this one key" instead of "coordinate a fan-out across five systems." Check the pricing if you want to compare the operational cost of a rotation script against not needing one, and the quickstart if you want to see how key issuance works.
If you're keeping your existing rotation script but want the same underlying Claude account, you can still point it at scoped keys instead of a single root credential — the docs cover authentication, and messages covers the request format if you're swapping providers into an existing script.
Testing your rotation script safely
Don't test key rotation for the first time in production. A minimal test loop:
# Dry run: create key, verify, immediately revoke
NEW_KEY=$(create_key.sh)
verify_key.sh "$NEW_KEY"
revoke_key.sh "$NEW_KEY"
Run this weekly against a non-production project so you catch API changes (providers do change key-management endpoints) before your real rotation cron job fails silently at 3am.
Also log every rotation event — timestamp, key ID created, key ID revoked, health check result — to a place your team actually looks (Slack webhook, not just a log file nobody tails). Silent failures in rotation scripts are worse than no automation at all, because you get the false confidence of "we rotate keys" without the safety.
questions
Do I need a rotation script if I only have one developer using the API? Yes, but it can be simpler — a manual quarterly rotation with a calendar reminder is fine at that scale. Automation matters more once multiple services or people share one credential.
How often should LLM API keys be rotated? 30–90 days for scheduled rotation is a reasonable default; rotate immediately (not on schedule) the moment a key appears in a log, repo, or ticket.
Can I rotate keys without any downtime? Yes, if you keep the old key active until the new key passes a health check in every consuming environment, then revoke the old one — never revoke before confirming the new key works.