[
https://issues.apache.org/jira/browse/KNOX-3512?focusedWorklogId=1047390&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1047390
]
ASF GitHub Bot logged work on KNOX-3512:
----------------------------------------
Author: ASF GitHub Bot
Created on: 14/Oct/26 08:33
Start Date: 14/Oct/26 08:33
Worklog Time Spent: 10m
Work Description: smolnar82 commented on code in PR #1451:
URL: https://github.com/apache/knox/pull/1451#discussion_r4268510964
##########
gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/TrustedOidcIssuersResource.java:
##########
@@ -225,9 +231,40 @@ private Map<String, Object> issuerToMap(TrustedOidcIssuer
issuer) {
map.put("registeredAt",
issuer.getRegisteredAt() != null ? issuer.getRegisteredAt().toString()
: null);
map.put("registeredBy", issuer.getRegisteredBy());
+ // CA certificates are public; the value is returned as registered so
callers can detect drift.
+ map.put("jwksCa", issuer.getJwksCa());
return map;
}
+ /**
+ * Validates an optional {@code jwksCa}. A Secret reference is checked for
syntax only, since the
+ * Secret may be created after the issuer is registered.
+ *
+ * @return the error description, or null if the value is valid or absent
+ */
+ private static String validateJwksCa(String jwksCa, boolean dynamicJwks) {
+ if (jwksCa == null) {
+ return null;
+ }
+ if (!dynamicJwks) {
+ return "jwksCa requires dynamicJwks=true; it only applies to OIDC
discovery and JWKS fetches";
+ }
+ if (jwksCa.length() > JwksCa.MAX_LENGTH) {
+ return "jwksCa must not exceed " + JwksCa.MAX_LENGTH + " characters";
+ }
+ try {
+ if (JwksCa.isSecretReference(jwksCa)) {
+ JwksCa.parseSecretReference(jwksCa);
+ } else {
+ JwksCa.parsePemBundle(jwksCa);
+ }
+ } catch (IllegalArgumentException e) {
+ // the secret reference errors already name the field; the PEM errors do
not
+ return JwksCa.isSecretReference(jwksCa) ? e.getMessage() : "Invalid
jwksCa: " + e.getMessage();
Review Comment:
Updated the error messages in JwksCa and simply return the message in the
catch.
Issue Time Tracking
-------------------
Worklog Id: (was: 1047390)
Time Spent: 1h 10m (was: 1h)
> KnoxIDF: per-issuer CA bundle (jwksCa) for trusted OIDC issuer discovery and
> JWKS fetches
> -----------------------------------------------------------------------------------------
>
> Key: KNOX-3512
> URL: https://issues.apache.org/jira/browse/KNOX-3512
> Project: Apache Knox
> Issue Type: Task
> Components: JWT, Server
> Affects Versions: 3.1.0
> Reporter: Sandor Molnar
> Assignee: Sandor Molnar
> Priority: Major
> Fix For: 3.1.0
>
> Time Spent: 1h 10m
> Remaining Estimate: 0h
>
> *Problem*
> Knox fetches each trusted OIDC issuer's discovery document and JWKS over
> HTTPS using the global JVM/Knox truststore. Kubernetes apiservers acting as
> issuers often use self-signed certificates, each with its own CA. Today the
> only way to trust them is to import every CA into the global truststore at
> startup. That has two costs:
> - Every CA rotation needs a restart.
> - Trust widens for all TLS clients in Knox (LDAP and the rest).
> TrustedOidcIssuer has no way to carry a CA.
> *Proposal*
> Add an optional {{jwksCa}} field to trusted OIDC issuer registrations. It
> takes one of two forms:
> - Inline PEM: one or more {{---{-}{{-}}BEGIN CERTIFICATE{{-}}{-}---}} blocks.
> - Kubernetes Secret reference: {{{}secret:[<namespace>/]<name>#<key>{}}}.
> Namespace defaults to "knox", the other 2 parts are required. Knox reads it
> through the in-cluster Kubernetes API.
> +Behaviour:+
> - When {{jwksCa}} is set, that issuer's discovery and JWKS TLS connections
> trust only the given bundle, and hostname verification stays on. The global
> truststore is never changed, so other TLS clients in Knox do not trust the
> issuer CA.
> - When {{jwksCa}} is not set, nothing changes.
> - {{jwksCa}} is only accepted together with {{{}dynamicJwks: true{}}}.
> - If {{jwksCa}} is configured but cannot be loaded (Secret or key missing,
> unparsable PEM), verification fails closed and does not fall back to the
> global truststore.
> - CA changes take effect without a restart:
> -- Inline: re-registering the issuer replaces its trust material straight
> away.
> -- Secret reference: Knox reads the Secret lazily, with no background
> refresh. It reads it:
> --- on the first discovery or JWKS fetch for the issuer.
> --- on access, when the cached CA is older than
> {{gateway.trusted.oidc.issuer.ca.secret.max.age.secs}} (default
> {{{}1800{}}}). This picks up CAs removed from the bundle.
> --- after a fetch fails with a TLS trust error (handshake or certificate
> validation). Knox re-reads the Secret and retries once, at most once every
> 30s per issuer. Timeouts and non-200 responses don't trigger a re-read.
> --- on {{{}POST /trusted-oidc-issuers/refresh-jwks{}}}, which drops the
> cached CA so the next fetch reads it again.
> -- If the Secret can't be read the first time, verification fails closed. If
> a max-age re-read fails, Knox keeps the last working CA and logs the failure.
> - Rotating the issuer's signing key still needs no config change. When a
> token's kid is not in the cached JWKS, the JWKS is fetched again.
> *Changes*
> - {{{}TrustedOidcIssuer{}}}, {{RegisterIssuerRequest}} and the admin REST
> resource get the new jwksCa field. Registration validates it and returns 400
> invalid_request when:
> -- it is set but dynamicJwks is false
> -- it is too long
> -- a secret: value has the wrong syntax
> -- inline PEM does not parse
> - {{TRUSTED_OIDC_ISSUERS}} table: new {{jwks_ca}} column ({{{}TEXT{}}}, or
> {{CLOB}} on Oracle).
> - {{TrustedOidcIssuerService}} exposes per-issuer TLS trust. It is used by
> OIDC discovery (Apache HttpClient) and by the JWKS fetch (Nimbus
> {{DefaultResourceRetriever}} with a per-issuer {{{}SSLSocketFactory{}}}).
> - JWTokenAuthority gets an overload of verifyToken that takes the JWKS
> SSLSocketFactory.
> - Docs: new field, config properties and RBAC requirements. Also a
> shared-root option: if every cluster chains to one root CA, use the same
> bundle or Secret for every issuer.
> Acceptance criteria
> - Issuers with different self-signed CAs all validate.
> - Replacing an issuer's CA bundle (inline or Secret) takes effect without a
> Knox restart.
> - An unrelated TLS client in Knox does not trust the issuer CA.
> - Rotating an apiserver signing key needs no Knox config change.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)