Envoy: Add a HTTP filter for JWT verification

Created on 2 Feb 2018  路  22Comments  路  Source: envoyproxy/envoy

Title: Add a HTTP filter for JWT verification

Description:
JWT verification is important for many services. This filter will allow Envoy proxy to verify the JWT token by fetching the remote pubkey and pass the verified JWT payload to the services for further authorization.

Istio has this filter here: https://github.com/istio/proxy/tree/master/src/envoy/http/jwt_auth
This issue wants to upstream the filter to Envoy.

enhancement

Most helpful comment

Is there some documentation about how to use this? Thanks!

All 22 comments

SGTM

I'll work with @qiwzhang to gradually move codes from istio/proxy. @mattklein123 can you assign the issue to me?

That's great to have this feature. Look istio implementation moved to https://github.com/istio/proxy/tree/master/src/envoy/http/jwt_auth

Really happy to see this moving forward (should be much more feature-complete than my custom filter). A couple questions though while we're still early in the process:

  • Would it be possible to do route-specific filtering? For example, maybe I have stuff at "/api/serviceA/" and "/api/serviceB/" and I would like to have them require audience claims of "serviceA" and "serviceB" respectively? Yes, I can forward the token/claims and have the service check it, or bounce it off an external authz server, but I'd prefer to keep it simple and do it at the edge proxy when it's already got all that stuff decoded.
  • I suppose more generally, could the logic be more configurable, perhaps with a list of rules? This is useful when some stuff (e.g. index.html or other assets getting served by the root prefix route match) should bypass the JWT requirement but I don't want to enumerate each url as a bypass in the current impl. For a concrete example, maybe something like:

    • Require audience of "serviceA" on prefix "/api/serviceA/" (likewise for "serviceB")

    • Require any valid JWT on prefix "/api/"

    • Allow by default (so "/index.html" and "/favicon.ico" and whatnot just work, as well as the serve-index.html-for-everything thing that a lot of these SPAs use)

Also, is there anything blocked with migrating the istio/proxy code into envoy? Happy to help if I can plug in somewhat easily.

The current config doesn't support route-specific filter yet, but it could/would happen in near future.

I don't think we want to do more fine granularity than route with JWT authN filter, but with the upcoming RBAC filter you should be able to fine control the allow by default, etc.

Fair enough, agreed that the multi-audience stuff is getting more into authz than authn so maybe that should be deferred to the RBAC filter (first I'm hearing about it).

That said, I think we could tweak the current configs to use a list of route rules rather than a list of bypass. Should be more general than the current bypass scheme without the complexity of per-issuer or per-audience rules.

name: "jwt-auth"
config:
  rules: [...]
  routes:
    - match: { prefix: "/api/" }
      action: require
    - match: { prefix: "/example/" }
      action: optional  # parse and verify, forward if valid
    - match: { prefix: "/" }
      action: bypass

I happened to be looking at some google api docs and noticed that their api has support for per-route issuer/audience verification: https://cloud.google.com/endpoints/docs/grpc-service-config/reference/rpc/google.api#google.api.Authentication

After thinking about it a bit more, it does seem appropriate to include route-specific issuer/audience checks as part of the authn filter. We're not filtering based on who the _user_ is or what scopes/claims they have (in which case I agree it would be getting too far into authz). We're filtering based on whether the _token_ is valid for the resource it's trying to access.

The configuration wouldn't need to change that much to support this. As a hypothetical, it could look something like this:

name: "jwt-authn"
config:
  providers:
  - id: bookstore_auth
    issuer: https://securetoken.google.com
    audiences:
    - bookstore_android.apps.googleusercontent.com
    - bookstore_web.apps.googleusercontent.com
    remote_jwks: [...]  # same as existing, omitted for brevity
  rules:
  - match: { prefix: "/bookstore/" }
    requirements: [{ provider_id: bookstore_auth }]
  - match: { prefix: "/" }
    requirements: []

Content-wise, it's about the same as the existing proposal, it just gives providers ids so they can be referenced in the rules/requirements.

My plan is to support per_route config in route::per_filter_config. You can put the whole JwtAuthentiction config into this per_filter_config. It may not be optimal since you have to specify jwt rules for each route, but it will serve most use cases.
@llchan will that work for you?

That would in theory work, but the config would be very verbose compared to the proposal above. One implicit advantage of the above is that the level of JWT granularity is decoupled from the routing, and the user can choose how to organize the JWT authn. I can, for example, have 100 route entries, but only 2 jwt-authn rules filtering audiences for prefixes of "/api/v1/" and "/api/v2/". That's just an example, but the main idea is that the granularity is configurable.

I suppose this is not a dealbreaker and per-route configs would work, because I could potentially just use a config generator to expand a more compact config, but I'm curious if there are concrete design flaws/deficiencies with the above?

Hi @llchan, One concern of your proposal is: you put route specific requirement rules in the filter config, it will be send to Envoy as LDS. But route could change dynamically, per-route specific info is preferred to send to Envoy in RDS. We don't want a route change to cause LDS update which is expensive.

Based on your idea, I will propose to move route specific requirement rules into per_route config. but keep providers list in the filter config.

Ah thanks, I understand now. I'm currently using static configs so I didnt think about dynamic updates. I think the hybrid approach of defining providers in the filter config and referencing them in per-route filter configs is a nice middle-ground.

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in the next 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

Status update:

  • first draft of HTTP filter for JWT verification is in. https://github.com/envoyproxy/envoy/pull/3339
  • per-route JWT requirement feature is in progress. The config modificaiton PR (https://github.com/envoyproxy/envoy/pull/3381) is under review, almost ready.
  • Plan to have a separate PR to implement the simple requirement: with one JWT token and simple requirement (no OR and AND combination).

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in the next 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

Is there some documentation about how to use this? Thanks!

Official document is not added yet. But you can look at the config proto file here https://github.com/envoyproxy/envoy/blob/master/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in the next 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

Bump for stale bot. Still interested in this!

We already have sort of support for JWT verification, can we mark this done after #4101? What else on your list? @qiwzhang

We can mark it as done after #4101

Done.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

phlax picture phlax  路  3Comments

boncheo picture boncheo  路  3Comments

justConfused picture justConfused  路  3Comments

weixiao-huang picture weixiao-huang  路  3Comments

dstrelau picture dstrelau  路  3Comments