AI agents · Secrets management · API key security
AI agent secrets management: why secrets stores aren't enough
Most teams deploying AI agents start with the right instinct: don't hardcode API keys, use a secrets manager. HashiCorp Vault, AWS Secrets Manager, and similar tools are excellent — for storing and retrieving secrets securely. What they don't do is cap how much an agent can spend with those secrets, enforce which endpoints the agent is allowed to call, or give you a per-call audit log with the agent's identity attached. Secrets management is a necessary first layer. It's not a complete solution for autonomous agents calling vendor APIs that cost real money.
TL;DR
Vault and AWS SSM solve storage and access control. They don't solve enforcement (spending caps, endpoint allowlists at call time) or audit (per-call cost, agent identity in the vendor's logs). AI agents need all four layers. A proxy layer handles enforcement and audit; secrets management handles the other two. They're complementary, not alternatives.
The four-layer model for AI agent API key security
When thinking about how an AI agent should interact with a vendor API like Stripe, Twilio, or Resend, there are four distinct problems to solve:
| Layer | The question it answers | What solves it | Gap for AI agents |
|---|---|---|---|
| Storage | Where is the API key stored, and is it encrypted at rest? | HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Doppler | Solved. All major secrets managers handle this well. |
| Access control | Which services or agents are allowed to retrieve this secret? | Vault policies, IAM roles, service accounts, short-lived dynamic secrets | Partially solved. IAM controls who can get the secret but not what they do with it after retrieval. |
| Enforcement | What can the agent actually do once it has the key — what endpoints, what spend? | Proxy layer with policy enforcement (Keybrake, custom middleware) | Gap. Secrets managers hand over the key and step back. What happens next is not their concern. |
| Audit | What did the agent call, when, what did it cost, and what was the response? | Proxy-layer audit log with cost parsing | Gap. Vendor logs (Stripe Dashboard, Twilio logs) exist but don't include agent identity or tie calls back to agent runs. |
The enforcement and audit layers are where AI agent workloads differ from traditional server applications. A human-operated API client makes deliberate calls — if someone sees a spike in Stripe charges, they can stop it manually. An autonomous agent can make hundreds of Stripe calls in the time it takes a Slack alert to fire, and those calls are indistinguishable in the Stripe Dashboard unless you've built attribution into your call metadata.
Why Vault dynamic secrets don't fully solve the problem
HashiCorp Vault's dynamic secrets engine is one of the most powerful features in the secrets management space: instead of storing long-lived secrets, Vault generates short-lived credentials on demand and revokes them automatically when they expire. For database passwords and cloud provider credentials, this is transformative.
For vendor API keys — Stripe, Twilio, Resend, Shopify Admin — dynamic secrets help less than you'd expect:
- Stripe doesn't support dynamic key generation via Vault. Vault's Stripe secrets engine doesn't exist in the official plugins registry. You'd need to build a custom plugin that calls Stripe's restricted key API — which would give you short-lived keys, but Stripe restricted keys scope by permission type (read vs write) not by spend cap or endpoint.
- Short TTL doesn't cap spend. A Stripe key that expires in 1 hour can still issue $50,000 in charges during that hour. Expiry limits time exposure, not financial exposure.
- Revocation doesn't undo charges. Revoking a Vault lease (which invalidates the dynamic secret) doesn't reverse Stripe charges that were already processed during the credential's lifetime.
- Vault audit logs record secret retrieval, not vendor API calls. You can see that your agent fetched the Stripe key from Vault at 2:03am. You can't see which customers it charged, for how much, using that key.
Why Stripe restricted keys don't fully solve the problem either
Stripe's own restricted keys allow you to scope a key to specific permission types: read-only on customers, read-write on payment intents. This is a meaningful improvement over full-access keys and is worth doing regardless of what else you put in place.
What restricted keys don't provide:
- No spend cap. A restricted key with write access to
/v1/payment_intentscan create unlimited payment intents of unlimited size. Permission scope is not spend control. - No per-agent-run attribution. A Stripe restricted key doesn't carry agent run context. The Stripe Dashboard shows calls by key, not by the agent run that made them.
- No allowlist on specific customers or merchants. A restricted key with payment intent access can create charges for any customer in your account, not just the ones the agent is authorized to process for this run.
- No mid-run revoke without affecting other systems. Revoking a Stripe restricted key affects all systems using that key simultaneously.
The enforcement gap in practice: a runaway billing scenario
Here's what the enforcement gap looks like when it bites:
Your team sets up a billing agent with best practices: the Stripe key is stored in AWS Secrets Manager, retrieved via an IAM role with minimal permissions, used in a short-lived Lambda invocation. Perfect secrets management.
A data pipeline bug feeds the billing agent a customer list with 5,000 entries instead of 50. The Lambda executes, retrieves the Stripe key from Secrets Manager, and begins calling stripe.PaymentIntent.create() in a loop. At Lambda's default 1,000 concurrent execution limit, this takes roughly 30 seconds to complete all 5,000 charges.
What your secrets management layer did during those 30 seconds: nothing. It handed over the key correctly, per the IAM role. There was nothing wrong with the secret retrieval. The problem was in the enforcement layer — specifically, the absence of a per-invocation spend cap on what could be done with the key once retrieved.
The proxy pattern: adding enforcement and audit without replacing secrets management
The most important architectural insight: a proxy enforcement layer is complementary to secrets management, not a replacement. The two layers solve different problems and can be used together:
# Step 1: retrieve the Keybrake admin key from Vault/SSM (secrets management layer)
import boto3
ssm = boto3.client("ssm")
keybrake_admin_key = ssm.get_parameter(
Name="/prod/keybrake/api_key",
WithDecryption=True
)["Parameter"]["Value"]
# Step 2: issue a per-run vault key (enforcement layer)
import httpx
r = httpx.post(
"https://proxy.keybrake.com/vault/keys",
headers={"Authorization": f"Bearer {keybrake_admin_key}"},
json={
"vendor": "stripe",
"daily_usd_cap": 500.0,
"allowed_endpoints": ["POST /v1/payment_intents"],
"expires_in": "30m",
"agent_run_label": f"billing-agent/{run_id}",
},
)
vault_key = r.json()["vault_key"]
# Step 3: use the vault key (never the real Stripe key) in the agent
stripe.api_key = vault_key
stripe.api_base = "https://proxy.keybrake.com/stripe"
The Keybrake admin key (the only long-lived secret) lives in AWS Secrets Manager or Vault. It never touches the agent. The agent only ever sees the ephemeral vault key, which expires in 30 minutes, caps at $500, and is scoped to a single endpoint. The real Stripe key lives in Keybrake's secure environment and is never exposed to your Lambda, your agent, or your orchestration layer.
What each layer handles
| What you need | Secrets manager handles it? | Proxy layer handles it? |
|---|---|---|
| Encrypted secret storage | Yes | No (not its job) |
| Access control (who can retrieve) | Yes (IAM/policies) | No (not its job) |
| Automatic secret rotation | Yes (for supported backends) | No |
| Per-run spend cap | No | Yes |
| Endpoint allowlist at call time | No | Yes |
| Mid-run vendor key revoke | No (revoking the stored secret doesn't revoke in-flight calls) | Yes |
| Per-call cost audit log | No | Yes |
| Agent identity in vendor calls | No | Yes (via vault key label) |
Minimum viable setup for new projects
If you're starting fresh with an AI agent that will call vendor APIs, the minimum viable setup that covers all four layers:
- Storage: One long-lived Keybrake admin key in AWS Secrets Manager or Vault (not in environment variables or code).
- Access control: IAM role or Vault policy scoped to your agent's service identity, allowing only retrieval of the Keybrake admin key.
- Enforcement: Issue a vault key per agent run at job start. Set
daily_usd_capto the maximum authorized spend for that run. Setallowed_endpointsto exactly the vendor endpoints the agent needs. Setexpires_into the job's expected TTL plus a buffer. - Audit: The Keybrake proxy audit log captures every call automatically with cost parsed from vendor responses. Set
agent_run_labelto include your job ID for queryable attribution.
The real vendor API keys (Stripe, Twilio, Resend) live only in Keybrake. Your agent code never sees them. If you need to rotate the Stripe key, you rotate it in Keybrake — not across every Lambda, K8s secret, and environment variable in your infrastructure.
How Keybrake fits
Keybrake is the proxy and enforcement layer for the non-LLM vendor APIs your agents call. It holds your real Stripe, Twilio, and Resend keys. You issue short-lived vault keys per agent run, attach spending policies, and call vendor APIs through the proxy. The result: per-run spend caps enforced at call time, endpoint allowlists that can't be bypassed, one-click revoke that works immediately without key rotation, and a per-call audit log with agent identity attached.
Related questions
Do I need Vault if I'm already using Keybrake?
They solve different problems, so "instead of" is the wrong frame. Vault (or AWS SSM) stores your Keybrake admin key securely — exactly one secret to store, with full audit of who retrieved it and when. Keybrake handles what happens after retrieval: enforcement and per-call auditing for your vendor APIs. If you're already using Vault for other secrets, adding your Keybrake admin key to Vault is a natural fit. If you're starting from scratch and only have one secret to store (the Keybrake admin key), AWS Secrets Manager's free tier or a simple encrypted environment variable may be sufficient for early-stage projects.
What's the difference between Keybrake's vault keys and Vault's dynamic secrets?
Vault's dynamic secrets generate credentials directly with the backend system (database, AWS, etc.) and revoke them via the backend's own API. Keybrake's vault keys are proxy credentials — your agent calls Keybrake, which holds and uses the real vendor credential on your behalf. Vault dynamic secrets for Stripe don't exist as a first-class plugin. Keybrake's vault keys fill that gap: short-lived, policy-enforced, automatically expiring proxy credentials for Stripe, Twilio, and Resend that work today without any custom Vault plugin development.
Can I use Keybrake alongside existing secrets management without changing my infrastructure?
Yes. You add one new secret to your existing secrets store (the Keybrake admin key). Your existing secrets management policies, rotation schedules, and audit logging remain unchanged. In your agent code, you add a call to issue a vault key at job start — one HTTP request — and then replace the vendor SDK's base URL and key with the vault key. The rest of your application doesn't change. If you decide to remove Keybrake later, you restore the original SDK base URL and retrieve the vendor key from your secrets store instead. There's no lock-in at the infrastructure layer.
Further reading
- AI agent credential management — the full architecture framework: storage vs. access vs. enforcement vs. audit, and how the four dimensions interact.
- AI agent API key rotation — why rotation schedules address the wrong threat model for autonomous agent workloads.
- AI agent audit trail schema — what a complete per-call audit log looks like and the SQL queries that matter for incident review.
- AI agent API key best practices — the full checklist: storage, scoping, rotation, enforcement, and audit — for any vendor API your agent calls.