Support separate discovery URL and issuer identifier in NewOIDCDiscoveryKeySet
- Dominant language
- Go
- Stars
- 482
- Forks
- 25
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 8
Description
**Is your feature request related to a problem? Please describe.**
The `NewOIDCDiscoveryKeySet()` function fetches the discovery document from `{issuer}/.well-known/openid-configuration` and validates that the `issuer` field returned in the discovery document matches the input issuer parameter exactly.
This validation fails if the client accesses the OIDC endpoint using a different address than the server's configured issuer identifier. For example, a client might access the server via IP address while the server's issuer is configured with a DNS hostname, or clients might use internal service names that are not fully qualified (like `kubernetes.default` in Kubernetes).
**Describe the solution you'd like**
Support alternative validation approaches:
* Allow users to provide the issuer URL and expected issuer identifier as separate parameters.
* Provide an option to disable strict issuer validation.
**Describe alternatives you've considered**
None found.
**Additional context**
The current validation is implemented here https://github.com/hashicorp/cap/blob/b72d477d7f92c08b2dadd2ce2a9c97e45f1ec94c/jwt/keyset.go#L96-L100
Which matches https://datatracker.ietf.org/doc/html/rfc8414#section-3.3
3.3. Authorization Server Metadata Validation
The "issuer" value returned MUST be identical to the authorization
server's issuer identifier value into which the well-known URI string
was inserted to create the URL used to retrieve the metadata. If
these values are not identical, the data contained in the response
MUST NOT be used.
RFC 8414 mandates this validation, though it has no security value: a compromised server can forge any issuer identifier it wants. I assume the validation primarily serves to catch misconfigurations rather than prevent attacks.
**Example scenario: Kubernetes Service Account Token Validation**
I would like to use `NewOIDCDiscoveryKeySet()` for fetching keyset to validate Kubernetes Service Account tokens issued by the Kubernetes API server.
Kubernetes allows applications running inside a Pod to auto-discover the API server address via environment variables:
* `KUBERNETES_SERVICE_HOST` with value `10.96.0.1`
* `KUBERNETES_SERVICE_PORT_HTTPS` with value `443`
When calling `NewOIDCDiscoveryKeySet(ctx, "https://10.96.0.1:443", caPEM)`, the discovery document is fetched successfully but contains:
```json
{
"id_token_signing_alg_values_supported": [
"RS256"
],
"issuer": "https://kubernetes.default.svc.cluster.local",
"jwks_uri": "https://172.20.0.5:6443/openid/v1/jwks",
"response_types_supported": [
"id_token"
],
"subject_types_supported": [
"public"
]
}
```
The validation fails because `https://kubernetes.default.svc.cluster.local` does not match `https://10.96.0.1:443`, even though the server is legitimate and the TLS certificate is valid.
Contributor guide
Assessment
This issue has not been assessed yet.