GCP Service Account accessing Apigee-X based Proxy with OAuth2

Hi,

    I have a GCP workload (in Cloud Run) that I need to have call an Apigee-X based proxy.  The proxy currently defends using an OAuth2 token and I see no need (desire) to change that.

    In our existing calls (under Apigee Edge) we have the calling application get an auth token from the IdP (3rd party outside Google and on-prem using username/password credentials) then exchange it for the actual OAuth2 token Apigee uses to defend the proxy (this is all standard stuff).  During the exchange, the "exchange" proxy (which also validates the apikey/secret) checks with the IdP that the auth token was legit and mints an OAuth2 token for that caller.

   Now, my workload is running in GCP Cloud Run (under the context of a dedicated Service Account for this execution) and I still need an Apigee-based OAuth2 token.  It seems unnecessary to have the application reach out (with username/password) to the 3rd party IdP for the auth token.  Instead, I should think I can leverage the Service Account and generate some sort of "local" token that the Apigee-X proxy could validate and use in place of the auth token.

    What are the recommended mechanics of having a GCP-based application get an OAuth2 token that Apigee can use?

 

Solved Solved
0 4 478
2 ACCEPTED SOLUTIONS

Yes I think your instinct is correct. You should be able to just generate a Google-issued OAuth token from the Cloud Run instance, identifying the Service Account, and then transmit that token to the API proxy. The Proxy can then verify that JWT, in the same way as it verifies any other JWT - by referring to the JWKS endpoint. 

I am not a Cloud Run expert, but I believe the technique described here can help you easily obtain a token from within your Cloud Run app. You simply configure the Cloud Run app to send a GET to the metadata server.  This works only from within Google Cloud, like from a Cloud Run app, or something running in AppEngine, or from a service running in GKE,  or even from Cloud Shell. 

 

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]" \
     -H "Metadata-Flavor: Google"

 

The trick then, is to determine which JWKS to use when verifying that JWT within your Apigee proxy.

I think you might need a condition to check... maybe the originating request headers.... and if the request is originating from Google, then use Google's JWKS endpoint to verify the JWT.  If the request is originating from your other IDP, then use THAT endpoint. 

You could also decode the JWT to examine the Subject claim, and then use that within the Condition. 

Does this make sense?

View solution in original post

CloudRun do the curl you highlighted - then call a special GCP-only "exchange" to convert that token to a generic OAuth2 token. Thus, I don't need to change all of my existing proxies - just the "exchange" proxy.

Makes sense!

how do I validate the JWT from the Google computeMetadata call?

Which actor is doing the verifying? If you are talking about using an API Proxy within Apigee to verify the JWT issued by the computeMetadata call, then... you can use the builtin VerifyJWT policy for that purpose. You would specify this URL as your JWKS URI. https://www.googleapis.com/oauth2/v3/certs

The policy then looks like this:

 

<VerifyJWT name='VJWT-Google-Issued'>
  <Algorithm>RS256</Algorithm>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <PublicKey>
    <JWKS uri='https://www.googleapis.com/oauth2/v3/certs'/>
  </PublicKey>
  <Issuer>accounts.google.com</Issuer>
  <Audience>insert-your-previously-selected-audience-here</Audience>
</VerifyJWT>

 

That doesn't verify the SUBJECT of the JWT, but it does verify that it was Google that issued it. If you also want to verify that it came from the particular Service Account, then include the Subject element also in that policy, specifying the email addr for the Service Account.

The reason you might not want to configure the policy to insist on a particular value of the Subject - what if you use different service accounts for different instance sof Cloud Run? If you always have a known service account, then I would suggest including the Subject element in the configuration for the VerifyJWT policy. (BTW the subject value that you verify can be dynamic, something you look up from KVM or properties file or similar).

View solution in original post

4 REPLIES 4

Yes I think your instinct is correct. You should be able to just generate a Google-issued OAuth token from the Cloud Run instance, identifying the Service Account, and then transmit that token to the API proxy. The Proxy can then verify that JWT, in the same way as it verifies any other JWT - by referring to the JWKS endpoint. 

I am not a Cloud Run expert, but I believe the technique described here can help you easily obtain a token from within your Cloud Run app. You simply configure the Cloud Run app to send a GET to the metadata server.  This works only from within Google Cloud, like from a Cloud Run app, or something running in AppEngine, or from a service running in GKE,  or even from Cloud Shell. 

 

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]" \
     -H "Metadata-Flavor: Google"

 

The trick then, is to determine which JWKS to use when verifying that JWT within your Apigee proxy.

I think you might need a condition to check... maybe the originating request headers.... and if the request is originating from Google, then use Google's JWKS endpoint to verify the JWT.  If the request is originating from your other IDP, then use THAT endpoint. 

You could also decode the JWT to examine the Subject claim, and then use that within the Condition. 

Does this make sense?

Thanks @dchiesa1 .  Just a follow-on for clarification...

I think what I'd do is have the CloudRun do the curl you highlighted - then call a special GCP-only "exchange" to convert that token to a generic OAuth2 token.  Thus, I don't need to change all of my existing proxies - just the "exchange" proxy.

BUT - how do I validate the JWT from the Google computeMetadata call?

I think that is outlined here:

https://cloud.google.com/compute/docs/instances/verifying-instance-identity#verify_signature

Agreed?

 

 

CloudRun do the curl you highlighted - then call a special GCP-only "exchange" to convert that token to a generic OAuth2 token. Thus, I don't need to change all of my existing proxies - just the "exchange" proxy.

Makes sense!

how do I validate the JWT from the Google computeMetadata call?

Which actor is doing the verifying? If you are talking about using an API Proxy within Apigee to verify the JWT issued by the computeMetadata call, then... you can use the builtin VerifyJWT policy for that purpose. You would specify this URL as your JWKS URI. https://www.googleapis.com/oauth2/v3/certs

The policy then looks like this:

 

<VerifyJWT name='VJWT-Google-Issued'>
  <Algorithm>RS256</Algorithm>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <PublicKey>
    <JWKS uri='https://www.googleapis.com/oauth2/v3/certs'/>
  </PublicKey>
  <Issuer>accounts.google.com</Issuer>
  <Audience>insert-your-previously-selected-audience-here</Audience>
</VerifyJWT>

 

That doesn't verify the SUBJECT of the JWT, but it does verify that it was Google that issued it. If you also want to verify that it came from the particular Service Account, then include the Subject element also in that policy, specifying the email addr for the Service Account.

The reason you might not want to configure the policy to insist on a particular value of the Subject - what if you use different service accounts for different instance sof Cloud Run? If you always have a known service account, then I would suggest including the Subject element in the configuration for the VerifyJWT policy. (BTW the subject value that you verify can be dynamic, something you look up from KVM or properties file or similar).

Thank you!