feat(cloudflare/ai-gateway): AiGatewayProviderKey — declarative BYOK provider keys#586
Open
agcty wants to merge 1 commit into
Open
feat(cloudflare/ai-gateway): AiGatewayProviderKey — declarative BYOK provider keys#586agcty wants to merge 1 commit into
agcty wants to merge 1 commit into
Conversation
eacd314 to
07189a4
Compare
sam-goodwin
reviewed
Jun 16, 2026
07189a4 to
5909b1e
Compare
5909b1e to
4354af0
Compare
…keys)
Declarative BYOK provider keys for AI Gateway. The resource owns both
halves of Cloudflare's BYOK contract: the Secrets Store secret named
per the {gatewayId}_{provider}_{alias} lookup convention (scoped to
ai_gateway) and the gateway provider config that activates it.
- Rotation: a value change patches the named secret in place — runtime
lookup is by name, so traffic picks up the new key immediately.
- defaultConfig / rate limits: immutable in place on the API, converged
by recreating the config row (the secret is untouched).
- provider / alias / gateway / store changes replace the resource (the
secret name is the identity).
- read brands name-matched configs Unowned (no ownership signal).
Depends on @distilled.cloud/cloudflare gaining updateProviderConfig /
deleteProviderConfig and optional secret/secretId on create
(alchemy-run/distilled#336).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4354af0 to
8b62a28
Compare
Contributor
Author
|
@sam-goodwin rebased and tested with cf resources now |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
AI gateways are commonly deployed per stage, but BYOK provider keys (OpenAI, Anthropic, Google Vertex, Bedrock, ...) are a manual dashboard step per gateway today, which breaks fully-declarative deploys. Cloudflare made BYOK API-configurable, powered by Secrets Store (BYOK docs, changelog).
API research
Cloudflare's BYOK contract has two halves:
{gateway_id}_{provider_slug}_{alias}with theai_gatewayscope. AI Gateway resolves keys by name at request time; the docs are explicit thatsecret_idis not used for runtime lookup, so API-created secrets must follow the convention./accounts/{account_id}/ai-gateway/gateways/{gateway_id}/provider_configs):POSTcreates the row,GETlists rows, andDELETE {id}removes a row. The documentedPUT {id}endpoint only rotates the secret value; this resource rotates by patching the named Secrets Store secret instead, because runtime lookup is by name.Requests then drop provider
Authorizationheaders entirely; a non-default key is selected per request withcf-aig-byok-alias.Design
One resource,
Cloudflare.AiGatewayProviderKey, owning both remote objects, mirroring howAiGatewaySpendingLimitowns the limit + top-up config pair:StoreSecretspecialization: the naming convention alone is not the full contract; the docs instruct creating the provider configuration as well, and the config row carriesdefault_configand per-key rate limits. The resource follows the documented API flow: create the named secret scoped toai_gateway, then create the config row referencing it viasecret_id.storeId; the resource validates this up front so Cloudflare does not fail later with a misleading provider-config secret lookup error.gateway/store/provider/aliaschanges replace;diffmirrorsStoreSecret's redacted value comparison for rotation.valuechange PATCHes the named secret in place. Gateway traffic picks it up through the name-based lookup, so the provider-configPUT {id}rotation endpoint is intentionally not used.defaultConfig/ rate limits: no in-place update exists, so structural drift is converged by recreating the config row. The secret is untouched, so other key configs are not disrupted.SecretNameAlreadyExists-> unconditional PATCH; config list-scan -> recreate-on-drift -> create with bounded retry for Secrets Store propagation.readbrands name-matched configsUnownedbecause provider configs expose no ownership signal, same asStoreSecret.storeis an explicit prop likeStoreSecret's, keeping the dependency graph visible.Dependency
This builds against the embedded
@distilled.cloud/cloudflare0.25.1workspace. That version already contains the API surface this resource uses: optionalsecretIdoncreateProviderConfiganddeleteProviderConfigfor destroy/recreate. TheupdateProviderConfigendpoint from alchemy-run/distilled#336 is not required by this design.Validation
bun run buildfrompackages/alchemypasses against embedded Distilled0.25.1.CLOUDFLARE_ACCOUNT_ID=... CLOUDFLARE_API_TOKEN=... bun run test test/Cloudflare/AiGateway/AiGatewayProviderKey.test.ts.🤖 Generated with Claude Code