3

I'm using Google App Engine to host a couple of services (a NextJS SSR service and a backend API built on Express). I've setup my dispatch.yaml file to route /api/* requests to my API service and all other requests get routed to the default (NextJS) service.

dispatch:
  - url: '*/api/*'
    service: api

The problem: I've also turned on Identity-Aware Proxy for App Engine. When I try to make a GET request from my NextJS service to my API (server-side, via getServerSideProps) it triggers the IAP sign-in page again instead of hitting my API. I've tried out a few ideas to resolve this:

  1. Forwarding all cookies in the API request
  2. Setting the X-Requested-With header as mentioned here
  3. Giving IAP-secured Web App User permissions to my App Engine default service account

But nothing seems to work. I've confirmed that turning off IAP for App Engine allows everything to function as expected. Any requests to the API from the frontend also work as expected. Is there a solution I'm missing or a workaround for this?

Matt Bise
  • 63
  • 1
  • 5
  • How do you perform your request in your code? Do you add a bearer id token in the Authorization header? – guillaume blaquiere May 26 '21 at 09:24
  • @guillaumeblaquiere No, I use Axios to make a `GET` request and pass the cookies from the frontend along in the `cookie` header – Matt Bise May 26 '21 at 14:54
  • Ok, you have a frontend service behind IAP that call a backend service behind IAP? Or is it a backend service that call another backend service? – guillaume blaquiere May 26 '21 at 14:58
  • How about turning off IAP on the Backend Service and instead add a bearer token verification? You include that token when you make the call internally. Public users won't have that token which means a call to the backend service by them will fail. Note: According to the documentation - https://cloud.google.com/iap/docs/managing-access - you should be able to separately turn on/off IAP for Backend Services versus other web services – NoCommandLine May 26 '21 at 15:35
  • @guillaumeblaquiere it's a backend service that calls another backend service. Both deployed via App Engine which is behind IAP – Matt Bise May 26 '21 at 18:05
  • @NoCommandLine I don't see any options to enable/disable IAP for individual App Engine services. It can only be configured for App Engine as a whole (pretty sure I've seen this mentioned in the docs somewhere as well but I can't seem to find it now) – Matt Bise May 26 '21 at 18:07

1 Answers1

2

You need to perform a service to service call. That's no so simple and you have not really example for that. Anyway I tested (in Go) and it worked.

Firstly, based your development on the Cloud Run Service to Service documentation page.

You will have this piece of code in NodeJS sorry, I'm not a NodeJS developer and far least a NexJS developer, you will have to adapt

// Make sure to `npm install --save request-promise` or add the dependency to your package.json
const request = require('request-promise');

const receivingServiceURL = ...

// Set up metadata server request
// See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenRequestOptions = {
    uri: metadataServerTokenURL + receivingServiceURL,
    headers: {
        'Metadata-Flavor': 'Google'
    }
};

// Fetch the token, then provide the token in the request to the receiving service
request(tokenRequestOptions)
  .then((token) => {
    return request(receivingServiceURL).auth(null, null, true, token)
  })
  .then((response) => {
    res.status(200).send(response);
  })
  .catch((error) => {
    res.status(400).send(error);
  });    

This example won't work because you need the correct audience. Here, the variable is receivingServiceURL. It's correct for Cloud Run (and Cloud Functions) but not for App Engine behind IAP. You need to use the Client ID of the OAuth2 credential named IAP-App-Engine-app

Ok, hard to understand what I'm talking about. So, go to the console, API & Services -> Creentials. From there, you have a OAuth2 Client ID section. copy the Client ID column of the line IAP-App-Engine-app, like that

enter image description here

Final point, be sure that your App Engine default service account has the authorization to access to IAP. And add it as IAP-secured Web App User. The service account has this format <PROJECT_ID>@appspot.gserviceaccount.com

Not really clear also. So, go to the IAP page (Security -> Identity Aware Proxy), click on the check box in front of App Engine and go the right side of the page, in the permission panel

enter image description here


In the same time, I can explain how to deactivate IAP on a specific service (as proposed by NoCommandLine). Just a remark: deactivate security when you have trouble with it is never a good idea!!

Technically, you can't deactive IAP on a service. But you can grant allUsers as IAP-secured Web App User on a specific service (instead of clicking on the checkbox of App Engine, click on the checkbox of a specific service). And like that, even with IAP you authorized all users to access to your service. it's an activation without checks in fact.

guillaume blaquiere
  • 66,369
  • 2
  • 47
  • 76
  • the proposal was to turn off IAP and replace with a ```bearer token verification``` meaning there should still be some sort of security. It might not be the best security method but we agree that turning off security is definitely not the best solution – NoCommandLine Jun 03 '21 at 16:43