Search code examples
google-cloud-platformgoogle-cloud-functionsgoogle-cloud-api-gateway

I can't get google cloud functions gen 2 to work with only authorized requests from behind a API Gateway


I recently switched to google cloud functions gen 2 and am having an issue with authentication via API Gateway. I have the new cloud function being called by my gateway with the function itself not allowing unauthorized users. The gateway has a service account attached to it with the cloud functions invoker role (and owner role since I'm troubleshooting).

The error message in the cloud function log is

The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#unauthorized-client

I have a test function with the same code that uses cloud functions gen 1 and does not allow unauthenticated users. This function works great when you hit my api gateway. I also have a cloud function gen 2 that does allow unauthenticated users and that also works as expected when hitting the gateway, it's just my gen 2 that doesn't allow unauthenticated users.

For my API gateway yaml file, this is what the file looks like (with sensitive information XXX'd out),

swagger: "2.0"
info:
  title: XXXXXXXX api gateway for carson blade analytics app
  description: Sample API on API Gateway with a Google Cloud Functions backend
  version: 1.0.0
schemes:
  - https
produces:
  - application/json
paths:
  /convert_csv:
    get:
      summary: Converts an XLSX file to a CSV file
      operationId: convert
      x-google-backend:
        address: https://convert-csv-XXXXX-ue.a.run.app
      responses:
        "200":
          description: A successful response
          schema:
            type: string

When I hit the unauthenticated allowed one and look at it's headers, I see

{     
 "aud": "https://convert-csv-XXXXX-ue.a.run.app/",
 "azp": "XXXX",
 "email": "[email protected]",
 "email_verified": true,
 "exp": 1660101164,
 "iat": 1660097564,
 "iss": "https://accounts.google.com",
  "sub": "XXXXX"
}

with the email being the email that is associated with the service account that has the correct cloud function invoker role and the aud being the same address as the address in the cloud api yaml. So it's replacing the authentication header that I'm sending in with its service account one as expected. I've tried reading all the documentation and have tried a bunch of different yaml configurations, but I just can't figure this out.

To summarize, With each one being attached to a cloud api gateway and hitting the endpoint from postman, gen 2 with allow unauthenticated turned off -> doesn't work. gen 2 with allow unauthenticated turned on -> works. gen 1 with allow unauthenticated turned off -> works

Any help would be extremely appreciated, thanks.


Solution

  • Cloud Functions 2nd gen is a wrapper on top of Cloud Run. Many times, the 2 products are entangled.

    • You must have the Cloud Functions Invoker role AND the Cloud Run Invoker roles (your issue)
    • You can filter the logs by selecting Cloud Run service and not Cloud Functions

    It's absolutely not clear, and from the beginning in the Alpha version. Despite my remarks to the PM and engineering team, the product has been publicly released and now there are a lot of mistakes and confusions because of this lack of clear separation. Too bad :(