Skip to content

Consumers silently ignore unsupported MCPExternalAuthConfig types #5930

Description

@danbarr

Problem

MCPExternalAuthConfig has nine spec.type values, but each consumer kind supports only a subset, and the unsupported combinations fail silently instead of being rejected or reported. A user who applies one of these configs sees a valid resource and a running workload, while the credential is never injected.

Confirmed against v0.40.1 and current main:

Referencing resource headerInjection bearerToken
MCPServer (externalAuthConfigRef) Silent no-op: explicit placeholder in addHeaderInjectionConfig (cmd/thv-operator/pkg/controllerutil/tokenexchange.go:386-401) Silently inert: wires runner.WithRemoteAuth, but remote auth only applies when RemoteURL is set (pkg/runner/runner.go:430-434), which MCPServer never sets
MCPRemoteProxy (externalAuthConfigRef) Silent no-op: same dispatcher as above Works (the only functional consumer)
VirtualMCPServer inline outgoingAuth Works Hard error: no converter registered (pkg/vmcp/auth/converters/interface.go:73-79)
VirtualMCPServer outgoingAuth.source: discovered Works Backend silently dropped from the vMCP with only a log line (pkg/vmcp/workloads/k8s.go:290-296, 457-461)

The discovered-mode case is a bad interaction: bearerToken on an MCPRemoteProxy is a legitimate, working configuration, but fronting that proxy with a discovered-mode vMCP makes the backend vanish from aggregation.

Beyond confusion, this is a security-adjacent footgun: someone who believes headerInjection is authenticating their proxy to a backend has a workload making unauthenticated calls while the resource reads as fully configured.

Ask

  1. Reconcile-time validation surfaced as status conditions. When a workload references an MCPExternalAuthConfig whose type that kind doesn't support, set ExternalAuthConfigValidated=False with a reason like UnsupportedAuthType instead of no-op'ing. The mirroring plumbing already exists (this is the same flow that surfaces EnterpriseRequired today). For vMCP discovered mode, surface the skipped backend in VirtualMCPServer status rather than log-and-drop.
  2. Document supported consumer kinds in the CRD. State which kinds support each spec.type in the field godoc on MCPExternalAuthConfigSpec.Type and on each consumer's externalAuthConfigRef, so it flows into the generated schema descriptions and reference docs.

An admission webhook rejecting the combination at apply time would be nice UX on top, but cross-resource checks at admission are best-effort (ref may not exist yet, either side can change later), so the conditions in (1) should be the source of truth.

Context

Found while reviewing stacklok/docs-website#1053, which initially documented headerInjection/bearerToken for MCPServer and MCPRemoteProxy per stacklok/docs-website#1013. Related fields with a similar accepted-but-unwired pattern: dcrConfig.softwareId/softwareStatement are plumbed to run config but never sent in the RFC 7591 registration request (pkg/auth/dcr/resolver.go:800-807).

Metadata

Metadata

Assignees

No one assigned

    Labels

    kubernetesItems related to Kubernetes

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions