March 1, 2021·6 min read·engineeringistiosecurityjwt

Istio JWT bypass exposes the boundary between authentication and authorization

CVE-2021-21378 affects Istio 1.9.0 when JWT authentication lacks corresponding authorization coverage. The advisory explains why accepting configured issuers does not itself require an authenticated request.

Configuring a trusted JWT issuer does not necessarily require every request to present a token. Istio's RequestAuthentication and AuthorizationPolicy have separate responsibilities, and CVE-2021-21378 exposes the consequences when their coverage does not align. On affected paths, a token from an unknown issuer can pass without the rejection that the authentication configuration should produce.

The 1 March advisory identifies Istio 1.9.0 as affected and gives the vulnerability a CVSS score of 8.2. It describes services that accept JWTs through RequestAuthentication while leaving some paths without the necessary AuthorizationPolicy coverage.

I value identity-based security in Istio, but an identity mechanism needs an enforcement rule before it can restrict access. This advisory makes that distinction concrete at the request level. A configured issuer, an authenticated request, and permission to reach a path are related facts with different meanings.

Authentication describes accepted credentials

The RequestAuthentication API in 1.9.0 states its intended behavior. It defines supported authentication methods for a workload and rejects invalid authentication information under its configured rules.

A request containing no credentials can still be accepted. It has no authenticated request identity, but RequestAuthentication alone does not convert that absence into an authorization rejection. Requiring authentication needs a corresponding authorization rule.

That behavior supports services with both public and protected operations. The same workload can validate tokens when they appear and use authorization policy to decide which requests require an authenticated identity. Requiring a token on every path is one possible policy, not an unavoidable consequence of declaring an issuer.

The vulnerability concerns a separate case. A presented JWT with an issuer outside the configured issuer list bypasses validation on paths meeting the advisory's conditions. The advisory says it should have been rejected. That is not the same as the documented acceptance of a request that presents no token.

Keeping those cases separate prevents a misleading explanation. Missing credentials can be intentionally permitted by the authentication resource. Accepting an unrecognized issuer's presented token is the disclosed validation failure.

Authorization decides whether identity is required

The AuthorizationPolicy API in 1.9.0 supplies the access-control decision. Its request-principal field matches the authenticated request identity, described as the token's issuer and subject.

The API's presence match uses "*" for a nonempty value. A rule requiring a request principal therefore excludes requests with no authenticated principal. This is how the documented configuration connects token validation to an actual access restriction.

The advisory says users with both RequestAuthentication and appropriate AuthorizationPolicy coverage are not subject to this vulnerability. The important word is coverage. Merely having some authorization object in a cluster does not establish that every affected path is protected.

Policy scope depends on namespace and selectors. A policy intended for one workload does not automatically apply to another workload with different labels. The authentication and authorization resources need to select the traffic for which their combined guarantee is intended.

The distinction between request and peer identity also matters. AuthorizationPolicy's principals field refers to source peer identity and requires mTLS. Its requestPrincipals field refers to the request's authenticated identity. A valid workload certificate does not substitute for a required end-user JWT.

A minimal pair makes the dependency explicit

This example follows the versioned API documentation. The issuer and key-set URL are illustrative values that must be replaced with the actual trusted issuer and its public key endpoint.

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: api-jwt
  namespace: applications
spec:
  selector:
    matchLabels:
      app: api
  jwtRules:
    - issuer: issuer-example
      jwksUri: https://example.com/.well-known/jwks.json
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: api-requires-jwt
  namespace: applications
spec:
  selector:
    matchLabels:
      app: api
  action: ALLOW
  rules:
    - from:
        - source:
            requestPrincipals: ["*"]

The first object defines token validation for the selected workload. The second allows requests with an authenticated request principal. In isolation, the second object's allow rule does not match a request lacking that identity.

This example assumes there are no other ALLOW policies granting broader access. Istio combines policy evaluation across the policies that apply to a workload. Adding an identity requirement in one object does not make another permissive matching rule disappear.

That assumption is essential when assessing an existing deployment. A configuration snippet can show the intended rule while omitting another rule that also allows the request. The effective policy is the combination, so auditing only the newest object can miss the actual authorization outcome.

ALLOW rules combine across policies

The versioned authorization documentation gives the evaluation model. A matching DENY rejects the request. If there are no ALLOW policies for a workload, the request is allowed. If ALLOW policies exist, at least one must match for the request to be allowed.

This explains why an ALLOW policy that requires a principal can enforce authentication for a workload when it is the applicable grant. It also explains why a broad second ALLOW can undermine the intended requirement. The rules are alternatives for granting access, subject to DENY evaluation.

An empty policy and an empty rule are different. The API documentation shows a policy with no rules as denying all requests for its selected scope. A policy with one empty rule allows every request in that scope because the empty rule always matches.

These distinctions are easy to miss in YAML review. Removing a nested condition can broaden an existing rule, while removing the rule itself can leave a policy that matches nothing. Understanding the API's evaluation is necessary to interpret such edits.

AUDIT is also distinct from enforcement. The API documentation says audit decisions do not determine whether a request is allowed or denied. An audit policy cannot replace an identity-requiring ALLOW rule merely because both mention the same traffic.

Scope can broaden beyond one label match

The authentication API says that omitting the selector applies the policy to workloads in its namespace. The authorization API likewise uses namespace and an optional selector to define its target. In the root namespace, authorization policy can have mesh-wide scope under the documented rules.

These defaults make the surrounding metadata part of the security configuration. Moving an object between namespaces or removing its selector can change which workloads it affects without changing its issuer or request-principal rule. Reviewing only the nested JWT fields therefore omits part of the effective policy.

The versioned authentication examples also show issuer-specific principal patterns for different hosts. A requirement for any authenticated principal and a requirement for a particular issuer are different restrictions, even though both depend on successful token authentication.

Public paths need deliberate exceptions

The RequestAuthentication documentation includes a pattern requiring JWTs on all paths except a health endpoint. It uses one rule matching authenticated request principals and another allowing the health path.

That structure permits a health request without a token because the path-specific rule supplies a separate grant. It also illustrates why the presence of a JWT policy does not imply a universal token requirement. The authorization configuration intentionally defines exceptions.

The advisory's warning concerns paths without the required authorization coverage. An audit therefore needs to compare the intended public exceptions with the effective policy on each path. It is insufficient to count authentication resources or check that an issuer string appears somewhere in the namespace.

The presented-token cases also remain relevant on public paths. RequestAuthentication promises to reject invalid authentication information when its rules apply, even though a request without credentials can be allowed. A service that treats the mere presence of a bearer token as evidence of validation would be relying on the wrong condition.

A request principal is the output of authentication. An unexamined token string is only input. Access-control decisions should use the authenticated result that the policy system exposes.

The advisory's remediation is configuration alignment

The disclosure recommends auditing RequestAuthentication and AuthorizationPolicy resources against the documented valid-token pattern. It does not name a fixed Istio patch version in this advisory. A remediation description should not invent one.

Its affected-release list is also specific. The source identifies 1.9.0, so the report does not establish the same exposure for every historical Istio release. The mechanism is important enough without expanding the version scope beyond the published disclosure.

My judgement is that the separate resources remain a useful design, provided their composition is explicit. Authentication can support optional credentials, while authorization chooses where an identity is mandatory. The vulnerability shows why users need both the validation guarantee and the access rule to hold for the intended request paths.

For an affected service, the concrete question is whether a request without an authenticated request principal can satisfy another applicable grant. The advisory directs operators to align the two resource types so that protected paths require that principal, even when an unrecognized issuer's token reaches the authentication filter.