envoyproxy/envoy

GCP Authentication Filter should be able to use the token endpoint to inject access token

Open

#28,866 opened on Aug 6, 2023

View on GitHub
 (7 comments) (0 reactions) (0 assignees)C++ (5,373 forks)batch import
area/gcp_authnenhancementhelp wanted

Repository metrics

Stars
 (27,997 stars)
PR merge metrics
 (Avg merge 8d) (378 merged PRs in 30d)

Description

Title: GCP Authentication Filter should be able to use the token endpoint to inject access token

Description: The GCP Authentication filter injects the id_token (JWT) from http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity into the Authorization header of the request.

However, some Google services seem to expect the access_token from http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token instead. One example is the https://healthcare.googleapis.com APIs.

When the URI is changed to the token endpoint, the response from computeMetadata/v1/instance/service-accounts/default/token is JSON:

 {"access_token":"ya29.c.redacted","expires_in":3400,"token_type":"Bearer"}

The GCP Authentication filter seems to inject the JSON response directly like so:

Authorization: Bearer {\"access_token\":\"ya29.c.redacted\",\"expires_in\":3400,\"token_type\":\"Bearer\"}

The correct access token can be retrieved using the following curl / jq commands:

curl \ 
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
-H "Metadata-Flavor: Google" | jq -r '.access_token'

and the expected header is:

Authorization: ya29.c.redacted

Currently, I am getting over this by using a Lua filter in tandem with the GCP Authentication filter like so to strip the access_token:

http_filters:
  - name: 'envoy.filters.http.gcp_authn'
    typed_config:
      '@type': type.googleapis.com/envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig
      http_uri:
        uri: 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token?audience=[AUDIENCE]'
        cluster: 'gcp_authn'
        timeout: 10s
  #  Lua filter to extract the access token from the GCP metadata server response
  - name: envoy.filters.http.lua
    typed_config:
      '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
      inline_code: |
        function envoy_on_request(request_handle)
            local auth_header = request_handle:headers():get("Authorization")

            if auth_header then
                local access_token = string.match(auth_header, '"access_token":"([^"]+)"')
                if access_token then
                    request_handle:headers():replace("Authorization", "Bearer " .. access_token)
                end
            end
        end
  - name: envoy.filters.http.router
    typed_config:
      '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

However, it'll be great to have this as a configuration option in the GCP Authentication Filter to automatically use the access_token / manipulate the response body using JSON path expressions to inject the right header.

Contributor guide