Skip to content

feat(models): Vertex AI credentials at the egress gateway through a configurable credential authority - #3259

Draft
QuentinBisson wants to merge 7 commits into
kagent-dev:mainfrom
giantswarm:feat/vertex-gateway-credentials
Draft

QuentinBisson wants to merge 7 commits into
kagent-dev:mainfrom
giantswarm:feat/vertex-gateway-credentials

Conversation

@QuentinBisson

@QuentinBisson QuentinBisson commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Vertex AI ModelConfigs with apiKeySecret put the service account key into the runtime, which Substrate actors can't mount and the credential compiler rejects (#2873, Vertex row of #3258).

Change

The gateway now sets the Vertex token: both Vertex providers bind Authorization: Bearer on the location's Vertex host, and the Go ADK, Python ADK and Claude Code skip their own Google auth and send a placeholder the gateway replaces. Which credential provider resolves a ModelConfig's Secret is a new controller setting, runtimeDefaults.modelCredentialAuthorities, per provider and k8s.io by default. With the default the Secret holds an access token; with a provider that mints tokens it can hold a service account key, for example https://github.com/giantswarm/substrate-credential-providers (routed with kagent-dev/substrate#90).

QuentinBisson and others added 2 commits October 18, 2026 15:23
…NT_SKIP_VERTEX_AUTH

With KAGENT_SKIP_VERTEX_AUTH=true the Go ADK builds its Vertex AI clients
without Application Default Credentials: the genai client runs on a plain
HTTP client and the Anthropic Vertex client on a placeholder token source,
and both send the placeholder bearer the egress gateway replaces with the
access token its credential provider serves. The HTTP client option now comes
before the Vertex option, which wraps only a client passed before it.

Co-authored-by: Timo Derstappen <teemow@gmail.com>
Signed-off-by: QuentinBisson <quentin@giantswarm.io>
…onfigurable credential authority

A GeminiVertexAI or AnthropicVertexAI ModelConfig with apiKeySecret now binds
authorization: Bearer on the Vertex AI origin of its location, so the Secret
never enters the runtime: the ADK translation drops the Secret volume and
GOOGLE_APPLICATION_CREDENTIALS and renders KAGENT_SKIP_VERTEX_AUTH, and the
Claude compiler renders CLAUDE_CODE_SKIP_VERTEX_AUTH with the placeholder
bearer in ANTHROPIC_CUSTOM_HEADERS instead of the key file.

The ate-secret:// authority of a ModelConfig credential is the controller
setting runtimeDefaults.modelCredentialAuthorities, keyed by ModelConfig
provider, default k8s.io (Helm: config.runtimeDefaults). With k8s.io the
Secret holds an access token; a credential provider class that mints access
tokens can hold a service account key instead. The compiler does not inspect
the Secret, since the class that fetches it owns its format. The egress
binding check accepts any DNS name without a port as the authority and
refuses IP addresses. MCP and EgressPolicy credentials keep k8s.io.

Co-authored-by: Timo Derstappen <teemow@gmail.com>
Signed-off-by: QuentinBisson <quentin@giantswarm.io>
Under KAGENT_SKIP_VERTEX_AUTH the Python ADK's Gemini and Claude models on
Vertex AI and the Vertex AI embedding client resolve no Application Default
Credentials and send the placeholder bearer the egress gateway replaces: the
genai client gets a credential holding the placeholder without an expiry, so it
is never refreshed, and the Anthropic Vertex client a fixed access token.

Co-authored-by: Timo Derstappen <teemow@gmail.com>
Signed-off-by: QuentinBisson <quentin@giantswarm.io>
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Oct 18, 2026
k8s.io would set the stored service account key itself as the bearer
token, so a Vertex AI apiKeySecret that resolves to it is a validation
error naming runtimeDefaults.modelCredentialAuthorities.<provider>.
Vertex AI ModelConfigs refuse tokenPassthrough, which neither ADK
runtime honours on Vertex AI. The Vertex AI binding is keyed by a name
no environment variable can carry.

Signed-off-by: QuentinBisson <quentin@giantswarm.io>
…ex AI

The Vertex AI option wraps the configured HTTP client with its
authorization. Passed after it, the custom client replaced the authorized
one and requests left without an Authorization header; the test asserts
both the ADC access token and the transport's headers reach Vertex AI.

Signed-off-by: QuentinBisson <quentin@giantswarm.io>
Under KAGENT_SKIP_VERTEX_AUTH the Python ADK builds the AsyncAnthropicVertex
client with the placeholder access token and passes it through the public
client field, instead of reaching into the parent's cached client property.

Signed-off-by: QuentinBisson <quentin@giantswarm.io>
…provider enum

Every provider the published ModelConfig CRD accepts is a valid modelCredentialAuthorities key, so a provider added to the CRD without the controller setting fails the test.

Signed-off-by: QuentinBisson <quentin@giantswarm.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant