ApigeeX to IAP-Protected Cloud Run – Invalid IAP Credentials

Hi @dchiesa1 and team,
Continuing the discussion from apigeex calling cloud function via ILB protected by IAP - Invalid IAP credentials: JWT email claim:

I’m currently working through this setup and found the previous posts helpful. However, we’re facing some challenges when connecting to an IAP-protected backend.

Our goal is to obtain an IAP token using a Service Callout (SC) in Apigee and send it as the X-Serverless-Authorization header to the backend.

We’re using the following endpoint to generate the token:

https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts
   /{SERVICE_ACCOUNT}:generateAccessToken

(all on one line)

We’ve already granted the role to the service account, as mentioned in earlier posts. However, the token generated from this endpoint does not work with IAP, it results in an invalid credentials error.

an you please suggest where we might be going wrong?
Any insights would be greatly appreciated!

I have 3 comments on that.

  • First, your approach is not working because you are using generateAccessToken on the iamcredentials.googleapis.com, and not generateIdToken as would be required by Cloud Run protected by IAP.

  • 2nd: IAP is normally and primarily used to control and govern access by human users to webapps. Not necessarily APIs that are accessed by services. The flow is:

    • The User attempts to access the protected application URL (e.g., https://my.service.run.app).
    • IAP (integrated with the load balancer) intercepts the request.
    • IAP checks for valid session credentials (a token/cookie) from a previous sign-in.
    • If no valid credentials are found, IAP redirects the User’s browser to the Google Identity Provider (Google’s OAuth 2.0 Authorization Endpoint).
    • The user sees the standard “Sign in with Google” screen. They provide their credentials (email/password) and maybe MFA.
    • The User may also see an OAuth Consent Screen
    • IAP redirects back to obtain an identity token
    • There’s a session and cookie established, which stores the token
    • IAP proxies to the backend, providing the token

    So you can see it’s oriented toward providing an interactive login-and-consent experience for users connecting to WebApps. Applying IAP in front of Cloud Run services that are primarily going to be accessed by other services… seems like the wrong thing. All that redirection will never happen. In fact you don’t want it to happen, because a service (like Apigee) is not going to respond to an HTTP redirect pointing to a login page. It’s possible to use IAP, and it will work in the happy path, but it is not ideal. You can configure your Cloud Run service to require authentication without relying on IAP.

  • 3rd: To send an Identity token to a Cloud Run service, you do not need to “manually” obtain a token.

I put together an example a couple months ago of the various ways you can configure Apigee to connect to a Cloud Run upstream. It is here.

I want to make sure you are aware that Apigee can do the token acquisition for you. You do not need to make an explicit call to iamcredentials.googleapis.com to obtain a token. You can if you like, but it’s not necessary. To make it simpler, use the Authentication element within the ServiceCallout policy. It looks something like this:

<ServiceCallout name='SC-Invoke-Cloud-Run-Service'>
  <Request>
    <Set>
      <Verb>GET</Verb>
    </Set>
  </Request>
  <Response>serviceResponse</Response>

  <HTTPTargetConnection>
    <!-- tell Apigee to obtain an ID Token and pass it to the Cloud Run service -->
    <Authentication>
      <HeaderName>X-Serverless-Authorization</HeaderName>
      <GoogleIDToken>
        <Audience  useTargetUrl="true"/>
      </GoogleIDToken>
    </Authentication>
    <SSLInfo>
      <Enabled>true</Enabled>
    </SSLInfo>
    <Properties>
      <Property name='success.codes'>2xx, 3xx, 4xx, 5xx</Property>
    </Properties>
    <URL>https://my-service-uw.a.run.app</URL>
  </HTTPTargetConnection>
</ServiceCallout>

Using this approach means you must deploy the API Proxy with a specific service account.

Check my example for more details. There’s even a screencast where I Walk through all the options. The thing I am describing here falls under what I called “platform authentication” in the README for the example.

The approach you are currently using falls under what I called “impersonated authentication” in the example.