[ 
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)

Reply via email to