Skip to content

Allow private IPs for in-cluster OIDC and OAuth2 upstream providers - #5618

Merged
tgrunnagle merged 3 commits into
mainfrom
oidc-private-ips-issue_5614
Jun 24, 2026
Merged

Allow private IPs for in-cluster OIDC and OAuth2 upstream providers#5618
tgrunnagle merged 3 commits into
mainfrom
oidc-private-ips-issue_5614

Conversation

@tgrunnagle

Copy link
Copy Markdown
Collaborator

Summary

  • In-cluster OIDC and OAuth2 providers (e.g. Dex, Keycloak deployed as ClusterIP services) were unreachable because newHTTPClientForHost() unconditionally set WithPrivateIPs(false) for any non-localhost host. OIDC providers failed immediately at startup during discovery; OAuth2 providers failed at first token exchange. Both failures block in-cluster deployments.
  • Adds an AllowPrivateIPs boolean flag to OIDCUpstreamRunConfig, OAuth2UpstreamRunConfig, upstream.OIDCConfig, and upstream.OAuth2Config. When true, the upstream HTTP clients accept RFC-1918 and link-local addresses. The flag widens only the private-IP gate — the HTTP-scheme restriction is unchanged, so HTTPS remains required for non-localhost hosts.

Closes #5614

Type of change

  • Bug fix

Test plan

  • Unit tests (task test)
  • Linting (task lint-fix)

New tests cover:

  • TestNewHTTPClientForHost extended with allowPrivateIPs parameter cases
  • TestOAuth2Config_AllowPrivateIPs — field propagated through NewOAuth2Provider and defaults to false
  • buildOIDCConfig / buildPureOAuth2Config propagation tests asserting the flag flows from RunConfig to the upstream config struct

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.

Changes

File Change
pkg/authserver/config.go Add AllowPrivateIPs bool to OIDCUpstreamRunConfig and OAuth2UpstreamRunConfig
pkg/authserver/upstream/oauth2.go Add AllowPrivateIPs to OAuth2Config; update newHTTPClientForHost signature and logic
pkg/authserver/upstream/oidc.go Pass config.AllowPrivateIPs to newHTTPClientForHost and propagate into internal oauth2 config
pkg/authserver/runner/embeddedauthserver.go Propagate AllowPrivateIPs in buildOIDCConfig and buildPureOAuth2Config
pkg/authserver/runner/embeddedauthserver_test.go Tests for flag propagation through both builder functions
pkg/authserver/upstream/oauth2_test.go Tests for newHTTPClientForHost with the new parameter and AllowPrivateIPs field propagation

Does this introduce a user-facing change?

Yes. Operators can now set allow_private_ips: true on an OIDC or OAuth2 upstream config block to allow the embedded auth server to reach providers hosted at private IP addresses inside the same Kubernetes cluster.

upstreams:
  - name: in-cluster-oidc
    type: oidc
    oidc_config:
      issuer_url: https://dex.my-namespace.svc.cluster.local:5556
      client_id: my-client
      client_secret_file: /var/run/secrets/client_secret
      allow_private_ips: true

Special notes for reviewers

The fix intentionally does not widen the HTTP-scheme gate. WithInsecureAllowHTTP is still keyed only on localhost or INSECURE_DISABLE_URL_VALIDATION, so AllowPrivateIPs: true permits https://10.96.x.x:5556 but still rejects http://10.96.x.x:5556. The two properties are orthogonal: private-IP reachability vs. plaintext transport.

The pattern follows the existing serializable security-override convention used for Redis TLS (InsecureSkipVerify in storage/config.go).

Generated with Claude Code

Fixes in-cluster provider deployments (e.g. dex, Keycloak as a
ClusterIP service) that were blocked because the HTTP client
unconditionally rejected private IP ranges at dial time.

- Add AllowPrivateIPs bool to OIDCUpstreamRunConfig and
  OAuth2UpstreamRunConfig (serializable, json/yaml tagged, omitempty)
- Add AllowPrivateIPs bool to upstream.OIDCConfig and upstream.OAuth2Config
- Update newHTTPClientForHost to accept an allowPrivateIPs parameter;
  pass allowInsecure || allowPrivateIPs to WithPrivateIPs so the flag
  widens only the private-IP gate — HTTPS is still required for
  non-localhost hosts
- Propagate the flag through buildOIDCConfig and buildPureOAuth2Config
  in the embedded auth server runner
- Add unit tests for newHTTPClientForHost and config propagation

Implements #5614
… test

Address review feedback:

- Set AllowPrivateIPs on the internal OAuth2Config derived from OIDC
  discovery so the field is consistent for logging and future introspection
- Add a comment to TestNewHTTPClientForHost explaining why the 500ms
  context deadline is sufficient and why the NotContains assertion
  is not vacuous (the private-IP guard fires synchronously before
  any network I/O)
@github-actions github-actions Bot added the size/S Small PR: 100-299 lines changed label Jun 24, 2026
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.00%. Comparing base (8d5875b) to head (a1d6924).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5618      +/-   ##
==========================================
+ Coverage   69.93%   70.00%   +0.07%     
==========================================
  Files         651      651              
  Lines       66502    66505       +3     
==========================================
+ Hits        46507    46559      +52     
+ Misses      16642    16577      -65     
- Partials     3353     3369      +16     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions Bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Jun 24, 2026
@tgrunnagle
tgrunnagle marked this pull request as ready for review June 24, 2026 14:58
@tgrunnagle
tgrunnagle merged commit baa8bb4 into main Jun 24, 2026
105 of 107 checks passed
@tgrunnagle
tgrunnagle deleted the oidc-private-ips-issue_5614 branch June 24, 2026 16:35
@github-actions github-actions Bot mentioned this pull request Jun 24, 2026
2 tasks
alex-feel added a commit to alex-feel/toolhive that referenced this pull request Aug 16, 2026
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>
alex-feel added a commit to alex-feel/toolhive that referenced this pull request Aug 20, 2026
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, mirroring the jwksAllowPrivateIP naming precedent on MCPOIDCConfig, and map it in buildOIDCUpstreamRunConfig. OAuth2UpstreamConfig already carries an equivalent allowPrivateIPs field, added separately for RFC 8693 delegate clients, so no new field is needed on that side.

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>
jhrozek pushed a commit to alex-feel/toolhive that referenced this pull request Aug 27, 2026
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, mirroring the jwksAllowPrivateIP naming precedent on MCPOIDCConfig, and map it in buildOIDCUpstreamRunConfig. OAuth2UpstreamConfig already carries an equivalent allowPrivateIPs field, added separately for RFC 8693 delegate clients, so no new field is needed on that side.

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

size/S Small PR: 100-299 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add AllowPrivateIPs flag to OIDC and OAuth2 upstream configs for in-cluster providers

2 participants