promptdojo_

Provider keys: one per environment, zero in the logs — step 1 of 7

A provider key is a spending limit and a data feed. Guard it like both.

Last lesson covered keys in general. ML service keys deserve their own lesson because the blast radius is different: whoever holds your Anthropic or OpenAI key can spend your budget at API rates and send prompts as you — and bots scrape GitHub for sk- prefixes around the clock. A leaked provider key gets exercised in minutes, not weeks. The bill arrives later.

One key per environment

The single-key setup — same ANTHROPIC_API_KEY on your laptop, in staging, and in prod — fails the moment anything goes wrong. Issue three keys instead:

  • dev — lives in your local .env, low spend limit. If it leaks, you rotate it over coffee and prod never notices.
  • staging — lives in the deploy platform's secret store.
  • prod — lives only in the platform's secret store. It has never touched a laptop, a notebook, or a .env file. Nobody can paste what they've never seen.

Separate keys also mean separate usage graphs. When spend spikes, the dashboard tells you which environment leaked — that's your incident triage done before it starts.

The leak nobody greps for: your own logs

Everyone knows not to commit keys. The sneakier failure is the inference log. Claude adds "helpful" debugging to your service and you get:

DEBUG headers={'authorization': 'Bearer sk-ant-prd-2481...'}
ERROR retry with key sk-ant-prd-2481... failed

Those lines flow into a log aggregator that half the company can search and that keeps data long after the deploy is gone. The key is now stored in plaintext, outside every secret store, indexed. Rules:

  1. Log request IDs, latency, token counts. Never headers, never client config, never the key.
  2. If you must confirm a key loaded, log a redacted prefix: key[:7] + "...". Enough to see which key, useless to a thief.
  3. Scan logs for key prefixes (sk-ant-, sk-) the same way you scan commits. It's a substring check — ten lines of Python.

Rotation, the short version

Found a key in a log or a commit? Revoke first, investigate second. Provider dashboard → revoke old key → issue new → update the secret store → redeploy → audit usage between leak and revocation. Because your code reads os.environ and the value lives in one place per environment, the whole dance is ten minutes. That convenience is the actual payoff of everything in this chapter.

Run the editor. Three environments, three keys, and only redacted prefixes ever reach stdout.