CONTEXT:
For a project I am working on I have setup service to service authentication using a service account for a gRPC API sat behind the Extensible Service Proxy (ESP) as per the instructions here. For reference my authentication configuration looks like the following
authentication:
providers:
- id: google_service_account
issuer: <service-account-email>
jwks_uri: https://www.googleapis.com/robot/v1/metadata/x509/<service-account-email>
rules:
- selector: "*"
requirements:
- provider_id: google_service_account
I then have a ruby client that reads in a service account key (attained through the GCP console) from disk and generates a JWT using the googleauth gem to be used to authenticate with the API.
module Authenticated
def credentials
@credentials ||= Google::Auth::ServiceAccountJwtHeaderCredentials
.make_creds(json_key_io: service_account_json_io)
.apply(jwt_aud_uri: ENV.fetch('SERVICE_NAME'))
end
def self.service_account
@service_account ||= StringIO.new(
File.read('/etc/secrets/service-account.json'),
)
end
private
def service_account_json_io
Authenticated.service_account.tap(&:rewind)
end
end
Currently this is in a working state and the client is able to authentication with ESP.
THE PROBLEM:
Since implementing the above I have another client application needing to reuse the same API. This means having to generate a new service account key and mounting that into the new application for authentication. Eventually if I create more clients then having to securely store many service account keys is error prone and a potential security risk. Instead I'd like to use the GCE metadata server to generate the JWT from lets say the default compute engine service account (although I may use a different account later) and pass this through to the ESP.
What I have tried so far is to change the ESP authentication configuration as follows
authentication:
providers:
- id: google_service_account
issuer: https://accounts.google.com
jwks_uri: https://www.googleapis.com/robot/v1/metadata/x509/<gce-default-service-account-email>
rules:
- selector: "*"
requirements:
- provider_id: google_service_account
and updated the ruby client to request a JWT from the metadata server as follows
module Authenticated
METADATA_SERVER_IDENTITY_URI = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?format=full&audience='.freeze
def credentials
{ authorization: "Bearer #{identity_jwt}" }
end
private
def identity_jwt
http = Net::HTTP.new(identity_uri.hostname)
http.request(identity_request).body
end
def identity_request
Net::HTTP::Get.new(identity_uri).tap do |req|
req.add_field('Metadata-Flavor', 'Google')
end
end
def identity_uri
URI.parse("#{METADATA_SERVER_IDENTITY_URI}https://#{ENV['SERVICE_NAME']}")
end
end
This again generates a JWT however this time with the issuer set to https://accounts.google.com (as reflected in the ESP authentication configuration). However this time the client is unable to authenticate with the ESP reporting Error: KEY_RETRIEVAL_ERROR
THE QUESTION... FINALLY:
Is it possible to authenticate against the ESP using a JWT generated through the GCE metadata server? And what are the configuration steps?