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:

LayerThe question it answersWhat solves itGap 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:

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:

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 needSecrets manager handles it?Proxy layer handles it?
Encrypted secret storageYesNo (not its job)
Access control (who can retrieve)Yes (IAM/policies)No (not its job)
Automatic secret rotationYes (for supported backends)No
Per-run spend capNoYes
Endpoint allowlist at call timeNoYes
Mid-run vendor key revokeNo (revoking the stored secret doesn't revoke in-flight calls)Yes
Per-call cost audit logNoYes
Agent identity in vendor callsNoYes (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:

  1. Storage: One long-lived Keybrake admin key in AWS Secrets Manager or Vault (not in environment variables or code).
  2. Access control: IAM role or Vault policy scoped to your agent's service identity, allowing only retrieval of the Keybrake admin key.
  3. Enforcement: Issue a vault key per agent run at job start. Set daily_usd_cap to the maximum authorized spend for that run. Set allowed_endpoints to exactly the vendor endpoints the agent needs. Set expires_in to the job's expected TTL plus a buffer.
  4. Audit: The Keybrake proxy audit log captures every call automatically with cost parsed from vendor responses. Set agent_run_label to 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.

Get early access

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