Permalink
Fetching contributors…
Cannot retrieve contributors at this time
165 lines (125 sloc) 3.88 KB

JWT Authentication Proxy

Overview

(TODO:figure)

Processing flow

Soon after the server runs:

  1. This proxy run as a sidecar of the server.
  2. Configure which issuers to use, via Envoy config.

Before an user sending request:

  1. The user should request an issuer for an access token (JWT)
    • Note: JWT claims should contain aud, sub, iss and exp.

For every request from user client:

  1. Client send an HTTP request together with JWT, which is intercepted by this proxy
  2. The proxy verifies JWT:
    • The signature should be valid
    • JWT should not be expired
    • Issuer (and audience) should be valid
  3. If JWT is valid, the user is authenticated and the request will be passed to the server, together with JWT payload (user identity).
    If JWT is not valid, the request will be discarded and the proxy will send a response with an error message.

How to build it

  bazel build //src/envoy:envoy

How to run it

  • Start Envoy proxy. Run
bazel-bin/src/envoy/envoy -c src/envoy/http/jwt_auth/sample/envoy.conf
  • Start backend Echo server.
go run test/backend/echo/echo.go
  • Then issue HTTP request to proxy.

With valid JWT:

token=`cat src/envoy/http/jwt_auth/sample/correct_jwt`
curl --header "Authorization: Bearer $token" http://localhost:9090/echo -d "hello world"

Note: the token is generated by:

With invalid JWT:

token=`cat src/envoy/http/jwt_auth/sample/invalid_jwt`
curl --header "Authorization: Bearer $token" http://localhost:9090/echo -d "hello world"

How it works

How to receive JWT

If a HTTP request contains a JWT in the HTTP Authorization header:

  • Authorization: Bearer <JWT> Envoy proxy will try to verify it with configured issuers.

Behavior after verification

  • If verification fails, the request will not be passed to the backend and the proxy will send a response with the status code 401 (Unauthorized) and the failure reason as message body.

  • If verification succeeds, the request will be passed to the backend, together with an additional HTTP header:

    sec-istio-auth-userinfo: <UserInfo>
    

    Here, <UserInfo> is base64 encoded payload JSON.

  • The authorization header with JWT token is removed.

How to configure it

Add this filter to the filter chain

In Envoy config,

"filters": [
  {
    "type": "decoder",
    "name": "jwt-auth",
    "config": <config>
  },
  ...
]

Config format

Format of <config> is defined in AuthFilterConfig message in config.proto file. It can be specified in JSON format as following examples

{
   "jwts": [
      {
         "issuer": "issuer1_name",
         "audiences": [
            "audience1",
            "audience2"
          ],
         "jwks_uri": "http://server1/path1",
         "jwks_uri_envoy_cluster": "issuer1_cluster"
      },
      {
         "issuer": "issuer2_name",
         "audiences": [],
         "jwks_uri": "server2",
         "jwks_uri_envoy_cluster": "issuer2_cluster",
         "public_key_cache_duration": {
             "seconds": 600,
             "nanos": 1000
          }
      }
  ]
}

Clusters

All public key servers should be listed in the "clusters" section of the Envoy config. The format of the "url" inside "hosts" section is "tcp://host-name:port".

Example:

"clusters": [
  {
    "name": "example_issuer",
    "connect_timeout_ms": 5000,
    "type": "strict_dns",
    "circuit_breakers": {
     "default": {
      "max_pending_requests": 10000,
      "max_requests": 10000
     }
    },
    "lb_type": "round_robin",
    "hosts": [
      {
        "url": "tcp://account.example.com:8080"
      }
    ]
  },
  ...
]