[
https://issues.apache.org/jira/browse/KNOX-3534?focusedWorklogId=1052520&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1052520
]
ASF GitHub Bot logged work on KNOX-3534:
----------------------------------------
Author: ASF GitHub Bot
Created on: 04/Nov/26 20:05
Start Date: 04/Nov/26 20:05
Worklog Time Spent: 10m
Work Description: lmccay commented on code in PR #1476:
URL: https://github.com/apache/knox/pull/1476#discussion_r4472683345
##########
gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/K8sDestinationAudienceValidator.java:
##########
@@ -399,19 +526,84 @@ public void init(final FilterConfig filterConfig) throws
Exception {
enforceActSubIsServiceAccount =
Boolean.parseBoolean(filterConfig.getInitParameter(ENFORCE_ACT_SUB_IS_SERVICE_ACCOUNT_PARAM));
+ ingressSourceRoutingEnabled = Boolean.parseBoolean(
+
filterConfig.getInitParameter(INGRESS_SOURCE_SPIFFE_ID_ROUTING_ENABLED_PARAM));
+ ingressSourceRoutingSkipTrustDomainMatch = Boolean.parseBoolean(
+
filterConfig.getInitParameter(INGRESS_SOURCE_SPIFFE_IDS_ROUTING_SKIP_TRUST_DOMAIN_MATCH_PARAM));
+ ingressSourceRoutingSkipValidation = Boolean.parseBoolean(
+
filterConfig.getInitParameter(INGRESS_SOURCE_SPIFFE_IDS_ROUTING_SKIP_VALIDATION_PARAM));
+
+ // Parsed strictly whether or not routing is enabled, so a malformed entry
fails the
+ // topology at startup instead of sitting inert.
+ final String ingressSourceSpiffeIdsParam =
+
blankToNull(filterConfig.getInitParameter(INGRESS_SOURCE_SPIFFE_IDS_PARAM));
+ ingressSourceSpiffeIds = new ArrayList<>();
+ if (ingressSourceSpiffeIdsParam != null) {
+ for (final String entry :
parseCommaSeparated(ingressSourceSpiffeIdsParam)) {
+ final Optional<SpiffeId> parsed = SpiffeId.parse(entry);
+ if (parsed.isEmpty()) {
+ throw new ServletException(String.format(Locale.ROOT,
+ "%s contains an invalid SPIFFE id entry: %s",
INGRESS_SOURCE_SPIFFE_IDS_PARAM, entry));
+ }
+ ingressSourceSpiffeIds.add(lowerCased(parsed.get()));
+ }
+ }
+
if (enforceActSubMatchesSourceSpiffeId && sourceSpiffeIdHeader == null) {
throw new ServletException(String.format(Locale.ROOT,
"%s is true but %s is not configured",
ENFORCE_ACT_SUB_MATCHES_SOURCE_SPIFFE_ID_PARAM,
SOURCE_SPIFFE_ID_HEADER_PARAM));
}
+
+ if (ingressSourceRoutingEnabled) {
+ if (sourceSpiffeIdHeader == null) {
+ throw new ServletException(String.format(Locale.ROOT,
+ "%s is true but %s is not configured",
INGRESS_SOURCE_SPIFFE_ID_ROUTING_ENABLED_PARAM,
+ SOURCE_SPIFFE_ID_HEADER_PARAM));
+ }
+ if (ingressSourceSpiffeIds.isEmpty()) {
+ throw new ServletException(String.format(Locale.ROOT,
+ "%s is true but %s is not configured",
INGRESS_SOURCE_SPIFFE_ID_ROUTING_ENABLED_PARAM,
+ INGRESS_SOURCE_SPIFFE_IDS_PARAM));
+ }
+ }
}
@Override
public AudienceValidationResult validate(final HttpServletRequest request,
final JWT token,
final List<String> configuredAudiences) {
final boolean hasActClaim = token.getClaimAsObject(JWTToken.ACT_CLAIM) !=
null;
- if (!hasActClaim && !validateAudiencesWithoutActClaim) {
- return
AudienceValidationResult.of(AbstractJWTFilter.matchesConfiguredAudiences(token,
configuredAudiences));
+
+ // Resolved before the early returns below because the routing decision
needs it. An
+ // absent value is not rejected here: that rejection happens further down,
after the destination
+ // header and server-name checks, so a request whose source header is
missing or unparseable
+ // is reported only once those earlier checks have passed.
+ final Optional<SpiffeId> sourceSpiffeId = sourceSpiffeIdHeader == null
+ ? Optional.empty() : sourceSpiffeIdFromHeader(request);
+ final boolean fromIngressSource = ingressSourceRoutingEnabled
+ && isConfiguredIngressSource(sourceSpiffeId);
+
+ if (!hasActClaim) {
+ if (fromIngressSource) {
+ // A token with no act claim arriving through the ingress names no
in-cluster destination,
+ // so its audience is either not checked at all or checked against the
fixed configured
+ // list. Both decisions are made before the aud claim is required to
be present, because
+ // the fixed-list check has its own handling for a token that carries
no aud claim.
+ return ingressSourceRoutingSkipValidation
+ ? AudienceValidationResult.of(true)
+ : AudienceValidationResult.of(
+ AbstractJWTFilter.matchesConfiguredAudiences(token,
configuredAudiences));
+ }
+ if (!validateAudiencesWithoutActClaim) {
+ return AudienceValidationResult.of(
+ AbstractJWTFilter.matchesConfiguredAudiences(token,
configuredAudiences));
+ }
+ } else if (fromIngressSource) {
+ // An act claim means the token authorizes one workload to call another
inside the cluster.
+ // Arriving from an ingress identity means it was presented from
outside, which no such call
+ // does.
+ return new AudienceValidationResult(false, "Token has an act claim but
its source SPIFFE id in header "
+ + sourceSpiffeIdHeader + " is a configured ingress source: " +
request.getHeader(sourceSpiffeIdHeader));
Review Comment:
@smolnar82 - I agree. This will break existing clients. We can't do this
now, could be made to be a configurable pattern but I don't know that we really
need to treat ingress differently at this point even. I'll continue to review.
Issue Time Tracking
-------------------
Worklog Id: (was: 1052520)
Time Spent: 50m (was: 40m)
> Add k8s request audience validator bypass for JWTs from an ingress
> ------------------------------------------------------------------
>
> Key: KNOX-3534
> URL: https://issues.apache.org/jira/browse/KNOX-3534
> Project: Apache Knox
> Issue Type: Sub-task
> Components: JWT
> Reporter: Harrison Sheinblatt
> Assignee: Harrison Sheinblatt
> Priority: Major
> Time Spent: 50m
> Remaining Estimate: 0h
>
> The existing K8sDestinationAudienceValidator feature focus on service to
> service audience validation. Enable using the validator for the use case
> where a single topology is to validate all jwts, both service to service and
> ingress traffic JWTs.
> Add flags to enable a feature to match JWTs coming from an ingress gateway
> and treat them differently: either validate the audience against the same
> static whitelist used for the rest of the traffic, or skip audience
> validation. This path would be split and evaluated first. Delegation tokens
> are not allowed on that path, so even if they come from an ingress, still
> treat them as they are now.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)