[ 
https://issues.apache.org/jira/browse/KNOX-3534?focusedWorklogId=1051854&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1051854
 ]

ASF GitHub Bot logged work on KNOX-3534:
----------------------------------------

                Author: ASF GitHub Bot
            Created on: 02/Nov/26 12:12
            Start Date: 02/Nov/26 12:12
    Worklog Time Spent: 10m 
      Work Description: smolnar82 commented on code in PR #1476:
URL: https://github.com/apache/knox/pull/1476#discussion_r4442232445


##########
knox-site/docs/config_request_audience_validator.md:
##########
@@ -143,21 +143,67 @@ request.audience.k8s.audience.path.prefix | Optional path 
prefix searched for in
 Name | Description | Default
 ---------|-------------|--------
 request.audience.k8s.require-all-audiences-match | Whether at least one `aud` 
entry matching the destination is sufficient (`false`, the ordinary "am I an 
intended audience" semantic of RFC 7519 section 4.1.3), or whether the claim 
must be non-empty and every entry must match (`true`). See the note below on 
combining this with the minting-side flags. | `false`
-request.audience.k8s.validate.audiences.without.act.claim | Whether a token 
with no `act` claim is validated against the request destination (`true`) or 
against the fixed `knox.token.audiences` list (`false`). See Non-delegated 
tokens below. Has no effect on a token that does carry an `act` claim. | `true`
+request.audience.k8s.validate.audiences.without.act.claim | Whether a token 
with no `act` claim is validated against the request destination (`true`) or 
against the fixed `knox.token.audiences` list (`false`). See Non-delegated 
tokens below. Has no effect on a token that does carry an `act` claim, nor on a 
token with no `act` claim that ingress source routing routes (see Ingress 
source routing below). | `true`
 request.audience.k8s.enforce.act.sub.service-account.matches.source.spiffeid | 
Whether the most recent actor in the token's `act` chain must match the source 
workload's SPIFFE id. See Actor-subject binding below. Requires 
`source.spiffe-id.header.name` to be configured; setting this `true` without it 
fails topology startup. | `false`
 request.audience.k8s.enforce.act.sub.is.service.account | Whether an actor 
subject that cannot be read as a k8s service-account subject fails validation 
(`true`) or passes unchecked (`false`). Only consulted when the parameter above 
is `true`. | `false`
 
 `request.audience.k8s.require-all-audiences-match=true` rejects a token if its 
`aud` claim is empty or if any entry in it fails to match this request's 
destination. It does not validate that the token carries exactly one audience, 
and it does not make a token single-use. A token with several `aud` entries is 
accepted when every entry matches this destination, for example the same 
service written in both the full and the shortened DNS form, a repeated entry, 
or an entry with no path alongside one with a specific path. What it does do is 
narrow where a multi-audience token can be used: only at a destination that all 
of its audiences name, so an entry naming some other destination can no longer 
be carried along behind a matching one.
 
 Limiting how many audiences a token carries is a minting-side concern. 
`JWTFederationFilter` exposes `delegation.enforce.requested.audience.required` 
and `delegation.enforce.requested.audience.max.one`, which constrain what a 
delegation token may be minted with. A deployment that wants every delegation 
token to carry exactly one audience must set both of those; 
`require-all-audiences-match` is not a substitute for them. Setting it as well 
is still worthwhile as a destination-side backstop: a multi-audience token that 
is minted anyway, for example by an older or misconfigured issuer, is accepted 
only where every one of its audiences names that destination.
 
+###### Ingress source routing parameters ######
+
+These control ingress source routing, described in Ingress source routing 
below. The other three are inert unless 
`request.audience.k8s.ingress.source.spiffe-id.routing.enabled` is `true`, 
except that every entry of `request.audience.k8s.ingress.source.spiffe-ids` is 
validated at startup whether or not routing is enabled.
+
+Name | Description | Default
+---------|-------------|--------
+request.audience.k8s.ingress.source.spiffe-id.routing.enabled | Whether a 
request that arrives from a configured ingress source is routed to a different 
audience check than validation against the request destination. When `true`, 
both `request.audience.k8s.source.spiffe-id.header.name` and 
`request.audience.k8s.ingress.source.spiffe-ids` must be configured, or 
topology startup fails. | `false`
+request.audience.k8s.ingress.source.spiffe-ids | Comma-separated list of full 
SPIFFE ids that identify a request as arriving from an ingress source, e.g. 
`spiffe://example.org/ns/ingress/sa/gateway`. A request matches if the SPIFFE 
id in the source SPIFFE-id header matches any one entry. Each entry must be a 
full SPIFFE id of the form 
`spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>`, even when 
`skip.trust.domain.match` is `true`; an entry that does not parse, including 
the empty entry left by a stray, leading or trailing comma, fails topology 
startup whether or not routing is enabled. Surrounding whitespace on an entry 
is ignored. | n/a (unset; required when routing is enabled)
+request.audience.k8s.ingress.source.spiffe-ids.routing.skip.trust.domain.match 
| Whether the trust domain of a configured ingress source id is left out of the 
comparison, so that only the namespace and the service account must match. This 
relaxes security: any trust domain is then accepted for that namespace and 
service-account pair, so identities in different trust domains that share the 
pair become indistinguishable to this check. | `false` (all three portions must 
match)
+request.audience.k8s.ingress.source.spiffe-ids.routing.skip.validation | 
Whether a token with no `act` claim that arrives from a configured ingress 
source gets no audience validation at all (`true`), or is checked against the 
fixed `knox.token.audiences` list (`false`). With `false`, the fixed-list check 
accepts any `aud` if `knox.token.audiences` is not configured. Has no effect on 
a token with an `act` claim, on a token that does not arrive from a configured 
ingress source, or when routing is disabled. | `false`
+
 ##### Path matching #####
 
 An `aud` entry with no resource path, or with a resource path of exactly `/`, 
matches ANY request path, for either form, including when 
`request.audience.k8s.path.header.name` is configured and the header is present 
on the request. This is deliberate, not an oversight: an entry with an empty 
path is a statement about which destination service a token may be presented 
to, not about which operations on that service it may invoke. An audience meant 
to be scoped to one endpoint must carry that endpoint's path.
 
 ##### Non-delegated tokens #####
 
-`request.audience.k8s.validate.audiences.without.act.claim` controls how a 
token with no `act` claim, that is, a token that is not a delegation token, is 
handled. It defaults to `true`: such a token's `aud` claim is validated against 
the request's actual destination in exactly the same way as a delegation 
token's, and the request is rejected if the token carries no `aud` claim, or an 
`aud` that is not a valid destination for this request. Setting it to `false` 
sends a non-delegated token's `aud` claim to the fixed `knox.token.audiences` 
check (`AbstractJWTFilter.matchesConfiguredAudiences`) instead, the same as if 
this validator were not selected for it. This parameter has no effect on a 
token that does carry an `act` claim: that token is always 
destination-validated by this validator.
+`request.audience.k8s.validate.audiences.without.act.claim` controls how a 
token with no `act` claim, that is, a token that is not a delegation token, is 
handled. It defaults to `true`: such a token's `aud` claim is validated against 
the request's actual destination in exactly the same way as a delegation 
token's, and the request is rejected if the token carries no `aud` claim, or an 
`aud` that is not a valid destination for this request. Setting it to `false` 
sends a non-delegated token's `aud` claim to the fixed `knox.token.audiences` 
check (`AbstractJWTFilter.matchesConfiguredAudiences`) instead, the same as if 
this validator were not selected for it. This parameter has no effect on a 
token that does carry an `act` claim: that token is destination-validated by 
this validator, or rejected if ingress source routing applies to it. Nor does 
it affect a token with no `act` claim that ingress source routing routes.
+
+##### Ingress source routing #####
+
+A request arrives from an *ingress source* when the SPIFFE id in the header 
named by `request.audience.k8s.source.spiffe-id.header.name` matches an entry 
of `request.audience.k8s.ingress.source.spiffe-ids`. An entry matches when the 
namespace and the service account are equal, and the trust domain is equal too 
unless 
`request.audience.k8s.ingress.source.spiffe-ids.routing.skip.trust.domain.match`
 is `true`. Each portion is compared ignoring case. No wildcard or partial form 
is supported in any portion. A header that is missing, or does not parse as a 
SPIFFE id, matches no entry, so such a request is not from an ingress source.
+
+Ingress source routing is off by default 
(`request.audience.k8s.ingress.source.spiffe-id.routing.enabled` is `false`), 
and with it off nothing in this section applies: a request from an ingress 
source is handled like a request from any other source. When it is on, a 
request from an ingress source is routed by whether its token carries an `act` 
claim:
+
+* **A token with an `act` claim is rejected.** A delegation token authorizes 
one in-cluster workload to call another, and is not expected to arrive from an 
ingress source. The rejection does not depend on `skip.validation`, and is 
decided before any other check, so the token's `aud` claim and the other 
configured headers are not examined. The request gets the bad-request response, 
and the log message names the source SPIFFE-id header and its value.
+* **A token with no `act` claim is not validated against the request 
destination.** What it is checked against depends on 
`request.audience.k8s.ingress.source.spiffe-ids.routing.skip.validation`. When 
it is `false` (the default), the token's `aud` claim is checked against the 
fixed `knox.token.audiences` list, the same check 
`validate.audiences.without.act.claim=false` uses. When it is `true`, no 
audience check of any kind is made, so a token with no `aud` claim is accepted, 
and so is one whose `aud` names something unrelated to this request.
+
+Either way a token with no `act` claim from an ingress source does not reach 
destination validation, so the destination SPIFFE-id, server-name and path 
headers are not required for it, none of the matching described under How this 
validator matches applies, and `validate.audiences.without.act.claim` and 
`require-all-audiences-match` have no effect on it.
+
+If `knox.token.audiences` is not configured, the fixed-list check accepts 
every token, including one with no `aud` claim. If it is configured, a token 
with an `aud` claim must share at least one entry with it, and a token with no 
`aud` claim is accepted only if the list contains `NONE`. With routing enabled 
and `skip.validation` left `false`, a token with no `act` claim from an ingress 
source is therefore checked only against `knox.token.audiences`; configure that 
list on the provider to restrict it at all.

Review Comment:
   This is the most important operational caveat of the feature, but it's 
buried mid-section. Could it go into the `skip.validation` row of the param 
table as an explicit **must configure `knox.token.audiences`** note, or a 
warning callout? Otherwise the default looks safe while actually accepting 
every `aud`.





Issue Time Tracking
-------------------

    Worklog Id:     (was: 1051854)
    Time Spent: 40m  (was: 0.5h)

> 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: 40m
>  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