Skip to content

Expose upstream provider allowPrivateIP in MCPExternalAuthConfig - #6288

Draft
alex-feel wants to merge 1 commit into
stacklok:mainfrom
alex-feel:crd-upstream-allow-private-ip
Draft

Expose upstream provider allowPrivateIP in MCPExternalAuthConfig#6288
alex-feel wants to merge 1 commit into
stacklok:mainfrom
alex-feel:crd-upstream-allow-private-ip

Conversation

@alex-feel

Copy link
Copy Markdown

Summary

The embedded auth server's upstream provider config has supported allow_private_ips since #5618pkg/authserver/config.go carries it on both OIDCUpstreamRunConfig and OAuth2UpstreamRunConfig, and pkg/authserver/runner/embeddedauthserver.go propagates it into provider construction — but the operator layer never exposed it: OIDCUpstreamConfig/OAuth2UpstreamConfig in mcpexternalauthconfig_types.go have no such field and buildOIDCUpstreamRunConfig/buildOAuth2UpstreamRunConfig never set it (grep -rn AllowPrivateIPs cmd/thv-operator/ is empty before this PR).

The result: an operator-deployed embedded AS can never federate an IdP that resolves to a private address. The AS exits fail-closed at OIDC discovery —

failed to create embedded auth server: ... failed to create upstream provider "idp":
failed to discover OIDC endpoints: Get "https://idp.internal.example/.well-known/openid-configuration":
dial tcp 10.0.0.5:443: the provided URL redirects to a private IP address, which is not allowed

— and the proxy pod crash-loops. Declaring the provider as type: oauth2 with explicit endpoints does not help: the same host-scoped HTTP client gates the token exchange (newHTTPClientForHost in pkg/authserver/upstream/oauth2.go), so the failure just moves from startup to the first sign-in. Self-hosted IdPs on corporate networks (GitLab, Keycloak behind split-horizon DNS) are a common shape for exactly the deployments the operator targets.

What changed:

  • allowPrivateIP (optional, default false) added to both OIDCUpstreamConfig and OAuth2UpstreamConfig, mirroring the jwksAllowPrivateIP / protectedResourceAllowPrivateIP naming precedent on MCPOIDCConfig — the same per-resource opt-in shape Allow opt-in internal/private remoteUrl hosts for co-located MCP backends (operator ValidateRemoteURL has no allowlist) #5784 discusses for remoteUrl.
  • buildOIDCUpstreamRunConfig / buildOAuth2UpstreamRunConfig map it onto the existing AllowPrivateIPs run-config field. Everything below the operator already propagates it end to end, so this is the last missing link.
  • CRD manifests regenerated (MCPExternalAuthConfig, and VirtualMCPServer which embeds the same upstream config types).

Closes #4523

Type of change

  • New feature

Test plan

  • Unit tests (task test) — TestBuildAuthServerRunConfig extended: a new case pins the flag reaching the run config on both provider types, and the existing OIDC case pins the default staying false. Operator unit packages are green locally via go test ./cmd/thv-operator/...; the envtest-based integration suites need the kubebuilder control-plane binaries and run in CI.

API Compatibility

  • This PR does not break the v1beta1 API, OR the api-break-allowed label is applied and the migration guidance is described above.

Additive optional field only; default false preserves the current behavior exactly.

Does this introduce a user-facing change?

Yes: MCPExternalAuthConfig (and VirtualMCPServer) upstream providers accept allowPrivateIP: true, allowing the embedded auth server to federate IdPs that resolve to private addresses. The default false preserves the current SSRF-protective behavior.

The embedded auth server's upstream provider config has supported
allow_private_ips since stacklok#5618, and the runner already propagates it, but
the operator CRD never exposed the field and the controllerutil builders
never set it — so an operator-deployed embedded AS could never federate
an IdP that resolves to a private address: the AS exits fail-closed at
OIDC discovery and the proxy pod crash-loops. Declaring the provider as
type oauth2 with explicit endpoints does not help, because the same
host-scoped HTTP client gates the token exchange.

Add allowPrivateIP to OIDCUpstreamConfig and OAuth2UpstreamConfig
(mirroring the jwksAllowPrivateIP naming precedent on MCPOIDCConfig),
map it in buildOIDCUpstreamRunConfig and buildOAuth2UpstreamRunConfig,
and regenerate the CRD manifests (MCPExternalAuthConfig and
VirtualMCPServer, which embeds the same types).

Closes stacklok#4523

Signed-off-by: Aleksandr Filippov <71711753+alex-feel@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add allowPrivateIP to MCPExternalAuthConfig upstream provider configs

1 participant