Area 06 // AI SecurityLesson 99 / 14013 min read
Secrets management and API key rotation
Secrets such as model-provider API keys must live in a secrets manager or the platform's secret store (never in code, prompts, logs or images), be scoped and given to each service at runtime, and be rotated on a schedule and immediately after any leak, with an overlap period so nothing breaks.
Think of it like this
Analogy
A building's master keys don't hang on a hook by the door. They're in a locked key cabinet; staff sign one out for a shift and return it. Each key opens only what's needed. When a key goes missing, the locks are changed, and the old key stops working. Changing the locks every so often anyway means a quietly copied key doesn't work forever.
The problem it solves
AI apps are full of valuable secrets: model-provider keys (which can run up thousands in charges), vector-database credentials, cloud keys, OAuth client secrets. They leak through git commits, frontend bundles, Docker images, CI logs, screenshots, traces, and now through prompts, since anything placed in a model's context can come back out. Leaked LLM keys are actively hunted and abused within minutes.
How it works: secrets management
- Keep secrets out of code and repos: load them from the environment or a mounted file; add
.envto.gitignoreand commit only a.env.examplewith placeholders (environments and config). - Store them in a secrets manager: a cloud secrets service, HashiCorp Vault, or your platform's secret store (e.g. GitHub Actions secrets, your host's environment settings). Access is logged and permissioned.
- Inject at runtime: the platform passes secrets to the running service; fail fast at startup if one is missing (see the code).
- Scope them: one key per service and environment (dev, staging, prod), minimal permissions, provider-side spending limits and usage alerts.
- Keep keys server-side: browsers and mobile apps call your backend, which calls the model; never ship provider keys to clients.
- Keep secrets out of model context: tools fetch what they need using credentials the model never sees (least privilege); redact secrets from logs and traces.
- Scan: pre-commit hooks and repository push protection (e.g. GitHub secret scanning) block commits containing key-shaped strings; scan prompts and logs too.
How it works: API key rotation
- Schedule rotation (e.g. every 90 days, or as policy requires) and rotate immediately when people leave or a leak is suspected.
- Rotation steps: create a new key → store it in the secrets manager → deploy services so they pick it up → overlap period where both work → revoke the old key → confirm no traffic used it.
- For keys you issue (your own API for customers), support two active keys per client and an overlap window (see the code).
- After a leak, revoke first: kill the exposed key, replace it, then check usage logs for abuse and find how it leaked.
- Prefer short-lived credentials where possible (workload identity, OIDC from CI to the cloud), so there's little to rotate.
- Automate: rotation scripts or the secrets manager's built-in rotation, with alerts when keys get old.
See it in code
- Needs
- Nothing: plain Python 3. The keys are obviously fake placeholders.
Fail-fast loading from the environment, an overlap window for rotating keys you issue, and a simple secret scanner.
import os, re, time
# SECRETS MANAGEMENT: read keys from the environment (filled by a secrets manager), fail fast if missing.
def require(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is not set") # never fall back to a key in the code
return value
os.environ["LLM_API_KEY_CURRENT"] = "key-v2-example" # in production: injected by the platform
os.environ["LLM_API_KEY_PREVIOUS"] = "key-v1-example"
print("loaded:", require("LLM_API_KEY_CURRENT")[:7] + "...")
# API KEY ROTATION for keys YOU issue: accept old and new during an overlap window, then retire the old one.
ROTATED_AT, OVERLAP_S = time.time() - 3_600, 24 * 3_600 # rotated 1 hour ago, 24h grace period
def key_is_valid(presented: str, now: float) -> str:
if presented == os.environ["LLM_API_KEY_CURRENT"]:
return "valid (current)"
if presented == os.environ["LLM_API_KEY_PREVIOUS"] and now - ROTATED_AT < OVERLAP_S:
return "valid (previous, still in overlap window)"
return "rejected"
print(key_is_valid("key-v1-example", time.time()))
print(key_is_valid("key-v1-example", time.time() + 2 * 24 * 3_600))
# SECRET SCANNING: block commits/prompts/logs that contain something shaped like a key.
SECRET_RE = re.compile(r"(sk-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY-----)")
snippet = 'client = OpenAI(api_key="sk-' + "x" * 24 + '")'
print("secret found in code:", bool(SECRET_RE.search(snippet)))loaded: key-v2-...
valid (previous, still in overlap window)
rejected
secret found in code: TrueOnly print a prefix of a key, never the whole thing. Real scanners (gitleaks, trufflehog, GitHub secret scanning) know hundreds of key formats and verify some of them with the provider.
A real example
Example
The weekend bill
A developer pasted a provider key into a public notebook while debugging on Friday. By Saturday morning, scrapers had found it and were reselling access; the account racked up about $14,000 in charges before a spending alert fired.
Afterwards the team moved every key into their cloud secrets manager, created separate keys per service with monthly spending caps, enabled push protection on all repos, added a pre-commit secret scanner, set alerts at 50% of each key's normal daily spend, and wrote a one-page "key leaked" runbook: revoke, replace, check usage, report.
The easy way
Start here
Put keys in your hosting platform's secret settings (or a .env file that is git-ignored for local work), read them with os.environ, set a monthly spending limit on every provider key, and turn on secret scanning with push protection for your repositories.
When you grow: the production setup
Teams use a central secrets manager with fine-grained access and audit logs, workload identity and OIDC instead of static keys where possible, automated rotation with overlap, per-service and per-environment keys with budgets, secret scanning in pre-commit, CI and on prompts and logs, and a tested leak-response runbook.
Trade-offs
What you gain
- Leaks become rare, small and short-lived.
- Access to secrets is audited.
- Rotation becomes routine instead of a fire drill.
What it costs you
- More setup than a key in a config file.
- Rotation needs coordination across services.
- Secrets managers are critical dependencies themselves.
When not to use it
- Never skip it for real keys; even prototypes should keep keys out of git and set spending limits.
Common mistakes
- Committing
.envfiles or keys in notebooks. - Shipping provider keys in frontend or mobile code.
- Putting credentials or internal codes in system prompts.
- One shared key for every service, person and environment.
- "Deleting" a leaked key from git history instead of revoking it.
Interview questions
Try answering out loud first, then open the model answer.
How do you manage API keys for LLM providers in production?
Model answer
Store them in a secrets manager or platform secret store, inject at runtime and fail fast if missing, keep them server-side only, use one key per service and environment with spending limits and alerts, keep them out of prompts, logs and traces, scan for leaks in commits and logs, and rotate on a schedule and after any suspected exposure.
Walk through rotating an API key without downtime.
Model answer
Create the new key; store it in the secrets manager; deploy services to use it while the old key still works; monitor until no traffic uses the old key; revoke the old key; confirm and document. For keys you issue, support two active keys per client with an overlap window and communicate deadlines.
A key has leaked publicly. What do you do?
Model answer
Revoke it immediately and issue a replacement through the secrets manager; check provider usage logs for abuse and contact the provider about fraudulent charges; find and fix how it leaked (scanning, process); rotate any other secrets exposed the same way; and record the incident.
Quiz
Pick an answer to see whether it’s right and why.
0 of 5 answered
Key terms
- Secret
- Any credential that grants access, such as an API key, password, token or private key. It must never appear in code, prompts, logs or images.
- Secrets manager
- A service that stores secrets encrypted, controls and logs who can read them, and delivers them to apps at runtime. Examples include cloud secret stores and HashiCorp Vault.
- Key rotation
- Replacing a key with a new one on a schedule or after a leak, usually with a short overlap so services can switch without downtime, then revoking the old key.
- Secret scanning
- Automatically searching code, commits, logs or prompts for strings that look like keys or passwords, and blocking or alerting when one is found.
- Environment variable
- A named value set outside your code (in the shell, a .env file or a server's settings), used for secrets and config.
Before and after
Progress is saved in this browser only.