1

I'm new to google envoy and following this documentation : https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto#envoy-v3-api-msg-extensions-filters-http-jwt-authn-v3-jwtheader

Im using envoy with docker with this simple docker file : FROM envoyproxy/envoy:v1.24-latest COPY envoy.yaml /etc/envoy/envoy.yaml

Im trying to set up a proxy using google envoy with a simple filter : a JWT check from header. The extension envoy.extensions.filters.http.jwt_authn.v3.JwtHeader seems the way to go.

So here is part my yaml :

static_resources:

  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 9911
    filter_chains:
    - filters:
      - name: envoy.filters.http
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtHeader
          name:  Authorization
          value_prefix:  "Bearer "

And here what i got : Didn't find a registered implementation for 'envoy.extensions.filters.http' with type URL: 'envoy.extensions.filters.http.jwt_authn.v3.JwtHeader'

I also tried this :

static_resources:

  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 9911
    filter_chains:
    - filters:
      - name: envoy.filters.http
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
          providers:
            jwt_auth:
              local_jwks:
                inline_string:  '{"keys":[{"typ": "JWT",  "kty":"oct","alg":"HS256","kid":"df","k":"aGVsbG93b3JsZA=="}]}'
              from_headers:
              - name:  Authorization
                value_prefix:  "Bearer "
          rules:
            - match:
                prefix:  "/"
              requires:
                provider_name:  jwt_auth

With the same result.

What am I doing wrong ? I guess something with "name" and "typed_config" but from the doc i found it should be fine. Thanks

Raphael
  • 11
  • 3

2 Answers2

0

OK my main mistake was that jwtAuth must be place in a "http_filters" section, it seems the correct configuration is somethings like :

static_resources:

  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 9901
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: AUTO
          stat_prefix: ingress_http
          access_log:
          - name: envoy.access_loggers.stdout
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
          route_config:
            name: local_route
            virtual_hosts:

          http_filters:
          - name: envoy.filters.http.jwt_authn
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
              providers:
                jwt_auth:
                  local_jwks:
                    inline_string: '{"keys":[{"alg":"HS256","kty":"oct","k":"BzP7aHv89DvBWeO_YmKfKcTlqCjsifWnjInWSBX0_OA"}]}'
                  from_headers:
                  - name: Authorization
                    value_prefix: "Bearer "
              rules:
              - match:
                  prefix:  "/"
                requires:
                  provider_name:  jwt_auth
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite_literal: www.envoyproxy.io
                  cluster: service_envoyproxy_io


  clusters:
  - name: service_envoyproxy_io
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    load_assignment:
      cluster_name: service_envoyproxy_io
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.envoyproxy.io
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: www.envoyproxy.io

That way the proxy is running (if built locally) with "bazel-bin/source/exe/envoy-static -c ../configEnvoy/jwt.yaml -l debug"

The token comes from https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsImt0eSI6Im9jdCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.BzP7aHv89DvBWeO_YmKfKcTlqCjsifWnjInWSBX0_OA

BUT a request like : curl localhost:9901 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsImt0eSI6Im9jdCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.BzP7aHv89DvBWeO_YmKfKcTlqCjsifWnjInWSBX0_OA' --verbose

Leads to "Jwt verification fails".

After digging a little bit and adding some logs here what i got :

[2023-01-24 15:30:01.654][755170][debug][http] [source/common/http/conn_manager_impl.cc:306] [C0] new stream
[2023-01-24 15:30:01.654][755170][debug][http] [source/common/http/conn_manager_impl.cc:972] [C0][S14930449970890273668] request headers complete (end_stream=true):
':authority', 'localhost:9901'
':path', '/'
':method', 'GET'
'user-agent', 'curl/7.61.1'
'accept', '*/*'
'authorization', 'Bearer eyJhbGciOiJIUzI1NiIsImt0eSI6Im9jdCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.BzP7aHv89DvBWeO_YmKfKcTlqCjsifWnjInWSBX0_OA'

[2023-01-24 15:30:01.654][755170][debug][http] [source/common/http/conn_manager_impl.cc:955] [C0][S14930449970890273668] request end stream
[2023-01-24 15:30:01.654][755170][debug][connection] [./source/common/network/connection_impl.h:92] [C0] current connecting state: false
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/filter.cc:157] Called Filter : setDecoderFilterCallbacks
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/filter.cc:53] Called Filter : decodeHeaders
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/matcher.cc:71] Prefix requirement '/' matched.
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/extractor.cc:254] extract authorizationBearer 
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:151] jwt_auth: JWT authentication starts (allow_failed=false), tokens size=1
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:162] jwt_auth: startVerify: tokens size 1
[2023-01-24 15:30:01.654][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:180] jwt_auth: Parse Jwt eyJhbGciOiJIUzI1NiIsImt0eSI6Im9jdCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.BzP7aHv89DvBWeO_YmKfKcTlqCjsifWnjInWSBX0_OA
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:186] jwt_auth: jwt jwt_t eyJhbGciOiJIUzI1NiIsImt0eSI6Im9jdCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.BzP7aHv89DvBWeO_YmKfKcTlqCjsifWnjInWSBX0_OA
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:187] jwt_auth: jwt alg_ HS256
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:188] jwt_auth: jwt audiences_ []
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:189] jwt_auth: jwt header_str_ {"alg":"HS256","kty":"oct"}
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:190] jwt_auth: jwt kid_ 
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:191] jwt_auth: jwt payload_str_ {"sub":"1234567890","name":"John Doe","iat":1516239022}
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:192] jwt_auth: jwt signature_ 3�h{��;�Y��bb�)���(�������H���
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:193] jwt_auth: jwt iss_ 
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:306] jwt_auth: jwks alg_ HS256
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:308] jwt_auth: jwks crv_ 
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:309] jwt_auth: jwks hmac_key_ 3�h{��;�Y��bb�)���(�������H���
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:310] jwt_auth: jwks kid_ 
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:311] jwt_auth: jkws kty_ oct
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:312] jwt_auth: jwks okp_key_raw_ 
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/authenticator.cc:394] jwt_auth: JWT token verification completed with: Jwt verification fails
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/filter.cc:109] Jwt authentication completed with: Jwt verification fails
[2023-01-24 15:30:01.655][755170][debug][http] [source/common/http/filter_manager.cc:917] [C0][S14930449970890273668] Preparing local reply with details jwt_authn_access_denied{Jwt_verification_fails}
[2023-01-24 15:30:01.655][755170][debug][jwt] [source/extensions/filters/http/jwt_authn/filter.cc:97] Called Filter : decodeHeaders Stop
[2023-01-24 15:30:01.655][755170][debug][http] [source/common/http/filter_manager.cc:959] [C0][S14930449970890273668] Executing sending local reply.
[2023-01-24 15:30:01.655][755170][debug][http] [source/common/http/conn_manager_impl.cc:1588] [C0][S14930449970890273668] encoding headers via codec (end_stream=false):
':status', '401'
'www-authenticate', 'Bearer realm="http://localhost:9901/", error="invalid_token"'
'content-length', '22'
'content-type', 'text/plain'
'date', 'Tue, 24 Jan 2023 14:30:01 GMT'
'server', 'envoy'

jwt is the sent token and jwks is the local token, i checked authenticator.cc and it goes through google::jwt_verify::verifyJwtWithoutTimeChecking so i really don't get it, why the verification fails, the signature are the same. I'm quite new to jwt, is there a reason (appart from time check) that could make a check with the good signature fail ?

Raphael
  • 11
  • 3
0

In fact the problem was in the "k" in the yaml configuration, i putted the last part of the token instead of the secret base64 encoded. Since the last part of the token is also encoded the proxy start smoothly anyways.

I guess for advanced user it's obvious but i'm a newbie in JWT.

So here is a simple working yaml config :

static_resources:

  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 9901
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: AUTO
          stat_prefix: ingress_http
          access_log:
          - name: envoy.access_loggers.stdout
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
          route_config:
            name: local_route
            virtual_hosts:

          http_filters:
          - name: envoy.filters.http.jwt_authn
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
              providers:
                jwt_auth:
                  local_jwks:
                    inline_string: '{"keys":[{"kty":"oct","alg":"HS256","k":"aGVsbG93b3Jk"}]}'
                  from_headers:
                  - name: Authorization
                    value_prefix: "Bearer "
              rules:
              - match:
                  prefix:  "/"
                requires:
                  provider_name:  jwt_auth
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite_literal: www.envoyproxy.io
                  cluster: service_envoyproxy_io


  clusters:
  - name: service_envoyproxy_io
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    load_assignment:
      cluster_name: service_envoyproxy_io
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.envoyproxy.io
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: www.envoyproxy.io

So in the line (i removed all the optional keys): inline_string: '{"keys":[{"kty":"oct","alg":"HS256","k":"aGVsbG93b3Jk"}]}' aGVsbG93b3Jk is helloword in base64 : https://www.base64encode.org/

Then you can validate https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIsImF1ZCI6ImV4YW1wbGVfc2VydmljZSIsImV4cCI6MjAwMTAwMTAwMX0.Bx9ms9QsEoM3jlqD1RFjxUbvpjLebAALzo4q-SL7Rzg Where you put your secret (here helloworld) in the signature section.

You can test using curl : curl localhost:9901 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIsImF1ZCI6ImV4YW1wbGVfc2VydmljZSIsImV4cCI6MjAwMTAwMTAwMX0.Bx9ms9QsEoM3jlqD1RFjxUbvpjLebAALzo4q-SL7Rzg' --verbose

Here is the proxy log :

[2023-01-31 11:04:28.467][252749][debug][jwt] [source/extensions/filters/http/jwt_authn/filter.cc:109] Jwt authentication completed with: OK
[2023-01-31 11:04:28.467][252749][debug][router] [source/common/router/router.cc:470] [C0][S5111927710838764941] cluster 'service_envoyproxy_io' match for URL '/'
[2023-01-31 11:04:28.468][252749][debug][router] [source/common/router/router.cc:678] [C0][S5111927710838764941] router decoding headers:
':authority', 'www.envoyproxy.io'
':path', '/'
':method', 'GET'
':scheme', 'http'
'user-agent', 'curl/7.61.1'
'accept', '*/*'
'x-forwarded-proto', 'http'
'x-request-id', '525bfe52-96c7-44f6-af33-4253635e056b'
'x-envoy-expected-rq-timeout-ms', '15000'
Raphael
  • 11
  • 3