Repository navigation
feat: add per-provider OIDC discovery URL override - #2386
Merged
Merged
Conversation
benmcclelland
force-pushed
the
sis/oidc-discovery-urls
branch
from
September 11, 2026 22:50
44966e4 to
2fda0a8
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Three moderate findings remain regarding cache identity, URL validation, and parsing provider URLs containing =.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds per-provider OIDC discovery URL overrides for IAM, including JWKS and thumbprint fetching through configured endpoints while preserving issuer validation.
Changes:
- Adds startup parsing and endpoint resolution.
- Updates OIDC discovery, JWKS, and thumbprint fetching.
- Exposes configuration through CLI, environment, embedded IAM, Helm, tests, and documentation.
File summaries
| File | Summary | Final review comments |
|---|---|---|
iamapi/server.go |
Parses discovery URL mappings. | Moderate (3 votes): validate both URLs structurally at startup. Moderate (1 vote): support = in provider URL paths when parsing pairs. |
iamapi/server_test.go |
Tests parsing and startup validation. | No final comments. |
iamapi/internal/iamutil/webidentity.go |
Uses overridden discovery endpoints. | Moderate (1 vote): include the resolved discovery target in cache and singleflight identity, or invalidate caches when it changes. |
iamapi/internal/iamutil/oidc.go |
Resolves OIDC endpoints and policies. | No final comments. |
iamapi/internal/iamutil/oidc_thumbprint.go |
Fetches thumbprints from override endpoints. | No final comments. |
iamapi/internal/iamutil/oidc_thumbprint_test.go |
Tests override thumbprint behavior. | No final comments. |
iamapi/internal/iamutil/oidc_test.go |
Tests discovery resolution. | No final comments. |
iamapi/controller.go |
Applies overrides during provider creation. | No final comments. |
iamapi/controller_test.go |
Tests end-to-end OIDC overrides. | No final comments. |
extra/example-iam.conf |
Documents environment configuration. | No final comments. |
embedgw/iam.go |
Adds embedded IAM configuration support. | No final comments. |
cmd/versitygw/iam.go |
Passes CLI configuration through. | No final comments. |
cmd/internal/gwcli/iam.go |
Adds the CLI flag and environment variable. | No final comments. |
chart/values.yaml |
Adds Helm values. | No final comments. |
chart/templates/iam-deployment.yaml |
Injects the Helm setting. | No final comments. |
chart/README.md |
Documents Helm usage. | No final comments. |
chart/Chart.yaml |
Bumps the chart version. | No final comments. |
Review details
Suppressed comments (2)
iamapi/internal/iamutil/webidentity.go:718
- The new discovery location is not represented in
jwksCacheKeyor the singleflight key, which still use only the issuer and thumbprints. If an embedded process restarts the IAM server with the same provider/thumbprints but a changed override (or has two server instances with different overrides), cached/coalesced key material from the old endpoint can be used and the configured endpoint is ignored until the cache expires. Include the resolved discovery target in the cache identity or invalidate the cache when the endpoint policy changes.
discoveryURL, policy := policy.ResolveDiscovery(issuerURL)
client := ssrfSafeHTTPClient(thumbprints, policy)
var doc oidcDiscoveryDoc
if err := fetchJSON(ctx, client, discoveryURL, &doc); err != nil {
iamapi/server.go:117
- Splitting at the first
=makes overrides unusable for provider URLs that contain=in an otherwise valid path (the existing provider validator accepts paths):https://issuer/tenant=abc=https://cluster/...is parsed withdiscoveryURLset toabc=https://...and rejected. Since the discovery side is required to start withhttp://orhttps://, locate the separator immediately before that scheme (or define an escaping rule) instead of assuming=cannot occur in the provider URL.
providerURL, discoveryURL, ok := strings.Cut(pair, "=")
- Files reviewed: 17/17 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
`AssumeRoleWithWebIdentity` always fetched a provider's discovery document from `<provider url>/.well-known/openid-configuration`, so an identity provider that issues tokens naming a public issuer while serving its metadata and keys on a cluster-internal path could not be used: reaching it meant relaxing the endpoint checks for every registered provider. `--oidc-discovery-url` moves that one fetch to an operator-named endpoint, which is how keys can be looked up over an optimized private path while the tokens themselves stay verifiable from the public internet against the issuer alone, as the JWT spec requires. The flag takes `<provider url>=<discovery url>` pairs, can be repeated once per provider, and is also read from `VGW_IAM_OIDC_DISCOVERY_URLS` as a comma-separated list; the Helm chart exposes the same list as `iamServer.oidc.discoveryUrls`. The discovery URL is fetched exactly as written, so it must carry the `/.well-known/openid-configuration` path when the provider serves it there. A malformed pair is rejected at startup rather than at the first assume-role call. Only the fetch moves. The provider URL is still what a token's `iss` claim is matched against, the fetched document's own `issuer` field must still equal it, and the key set still comes from the `jwks_uri` that document publishes. A configured discovery endpoint is named by the operator at startup rather than by a request, so it and the `jwks_uri` it publishes waive the private-address check for that provider's fetch chain only, without `--oidc-allow-private-endpoints` and its far broader effect on every other provider. Transport rules are unchanged: a plaintext discovery URL still requires `--oidc-allow-insecure-transport`. Thumbprint auto-fetch follows the override and pins the discovery endpoint's certificate chain, since that is the host every later fetch is verified against.
niksis02
force-pushed
the
sis/oidc-discovery-urls
branch
from
September 14, 2026 11:13
2fda0a8 to
1c1272c
Compare
benmcclelland
approved these changes
Sep 14, 2026
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.
AssumeRoleWithWebIdentityalways fetched a provider's discovery document from<provider url>/.well-known/openid-configuration, so an identity provider that issues tokens naming a public issuer while serving its metadata and keys on a cluster-internal path could not be used: reaching it meant relaxing the endpoint checks for every registered provider.--oidc-discovery-urlmoves that one fetch to an operator-named endpoint, which is how keys can be looked up over an optimized private path while the tokens themselves stay verifiable from the public internet against the issuer alone, as the JWT spec requires.The flag takes
<provider url>=<discovery url>pairs, can be repeated once per provider, and is also read fromVGW_IAM_OIDC_DISCOVERY_URLSas a comma-separated list; the Helm chart exposes the same list asiamServer.oidc.discoveryUrls. The discovery URL is fetched exactly as written, so it must carry the/.well-known/openid-configurationpath when the provider serves it there. A malformed pair is rejected at startup rather than at the first assume-role call.Only the fetch moves. The provider URL is still what a token's
issclaim is matched against, the fetched document's ownissuerfield must still equal it, and the key set still comes from thejwks_urithat document publishes. A configured discovery endpoint is named by the operator at startup rather than by a request, so it and thejwks_uriit publishes waive the private-address check for that provider's fetch chain only, without--oidc-allow-private-endpointsand its far broader effect on every other provider. Transport rules are unchanged: a plaintext discovery URL still requires--oidc-allow-insecure-transport.Thumbprint auto-fetch follows the override and pins the discovery endpoint's certificate chain, since that is the host every later fetch is verified against.