Credential Brokering Patterns for AI Agents Part 2.5: Where KMS Grants Stop Scaling AWS KMS grants cap credential-brokering designs for AI agents at 50 CreateGrant and RetireGrant requests per second per account per region, making the grant-minting rate the ceiling for every token exchange, Christian Posta writes in part 2.5 of his credential-brokering series. Because each exchange in the design's "Mode 3" requires three KMS calls (CreateGrant, Decrypt, RetireGrant) and grants never expire, stranded grants can fill a key's 50,000-grant limit in about 17 minutes at the mint ceiling, after which CreateGrant returns LimitExceededException and every token exchange fails. Posta says the pushback from Stephane Nangue in LinkedIn comments was correct and that it changes the recommendation he made at the end of part 2, with a variant that gives the broker standing kms:Decrypt while it never touches the ciphertext. Credential Brokering Patterns for AI Agents Part 2.5: Where KMS Grants Stop Scaling Mode 3 from part 2 takes standing decrypt away from the token vault with KMS grants. The grant quota caps the whole system at 50 exchanges a second. Here's the variant that keeps the property and scales. We’ve been digging into credential shielding/brokering for AI agents typically in the egress/outbound direction. In part 1 https://blog.christianposta.com/credential-brokering-patterns-for-ai-agent-egress/ I introduced the approaches discussed in the CB4A paper https://datatracker.ietf.org/doc/html/draft-hartman-credential-broker-4-agents-00 which lead us to an uncomfortable place: lots of credentials centralized into a token vault. In part 2 https://blog.christianposta.com/credential-brokering-patterns-for-ai-agent-egress-part2/ I walked through three ways to protect the token vault behind a credential broker, and landed on “Mode 3”: the controller the STS that owns the vault keeps the ciphertext, has kms:Encrypt and loses kms:Decrypt entirely. Every unwrap needs a short-lived AWS KMS grant minted by a separate decision broker. The controller alone can’t read/decrypt anything, the broker can decrypt but has nothing to read no DB access , and a compromised controller can’t mass decrypt the store. That’s the property we want to keep. In this blog I want to look at the part of that design that falls over under real load the KMS grant , and useful alternatives. It’s a short one, but it changes the recommendation I made at the end of part 2. KMS grants don’t scale When I posted part 2, Stephane Nangue https://www.linkedin.com/in/stephane-nangue-480a2557/ pushed back in the comments https://www.linkedin.com/posts/ceposta credentials-vault-security-share-7490393823735566336-FWmz/ on two things. The second per-user scoping is broker code rather than IAM is now addressed in updates to part 2 https://blog.christianposta.com/credential-brokering-patterns-for-ai-agent-egress-part2/ itself. The first is simple: Mode 3 doesn’t scale, and the workarounds caching, session-scoped grants, etc put the standing decrypt right back. He’s right. So how bad is it? If you look at the KMS request quotas https://docs.aws.amazon.com/kms/latest/developerguide/requests-per-second.html , CreateGrant and RetireGrant default to 50 requests per second, per account, per region, while the shared symmetric Decrypt quota is 10,000 to 100,000 per second depending on the region. All of these are adjustable, but every token exchange in Mode 3 is three KMS calls CreateGrant , Decrypt , RetireGrant , so the mint rate is the ceiling for the whole system, and it’s a ceiling you share with every AWS service in the account that mints grants on your behalf e.g. EBS creates one per encrypted volume attach . A shared enterprise gateway exchanging on every tool call will find 50 a second pretty quickly. Grants are also durable. They don’t expire, somebody has to retire them https://docs.aws.amazon.com/kms/latest/developerguide/grant-delete.html , and each key holds at most 50,000 https://docs.aws.amazon.com/kms/latest/developerguide/resource-limits.html grants-per-key . A broker crash, a throttled RetireGrant , a bug in the retirement path, etc leaves grants stranded, and at the mint ceiling you fill the key in about 17 minutes, at which point CreateGrant returns LimitExceededException and every token exchange in the environment fails. And every grant that doesn’t get retired is now “hidden” .. and becomes a row the controller can decrypt whenever it wants until someone notices. So if retirement is failing in the background you’ve basically drifted back to Mode 2 for every one of those rows, or worse reaching limits and not issuing new grants – crashes the system . What if the broker calls Decrypt itself? We don’t have to limit to the decrypt grant we send to the controller. We can flip who calls Decrypt . The broker gets standing kms:Decrypt but never touches the ciphertext, and the controller keeps the ciphertext with no kms:Decrypt at all. The controller still can’t read a row on its own and the broker still has nothing to read, but instead of minting a grant and handing it back, the broker unwraps the DEK itself and returns it to the controller. sequenceDiagram autonumber participant AG as Agent / MCP client participant GW as Gateway dataplane participant CT as Controller STS + vault participant BR as Broker PDP + unwrapper participant KMS as AWS KMS participant UP as Upstream API AG- GW: MCP request + IdP subject token GW- GW: mint freshness proof SVID-signed :