Ali Nahid
Ali Nahid

Reputation: 957

How to make http cloud function only accessible from cloud endpoints

My architecture is:

  1. I have bunch of cloud functions (firebase)
  2. I have setup a ESPv2 based cloud endpoints setup with cloud run with the cloud functions as backend
  3. I have a SPA running on firebase hosting which is making calls to the endpoints (15 api endpoints)
  4. For now the APIs (cloud endpoints) are secured via APIKey (restricted)

I want make the cloud functions secured such that only the cloud endpoints (or other services within my project) can make calls to it. Directly calling the fqdns of these cloud functions should yield 403/4xx.

How do I achieve this? Is there any way?

** I don’t have organisation account so creating a service perimeter isn’t an option.

EDIT

I have accepted guillaume blaquiere's ans as the correct one. Although the ans the did not solve the issue I was facing but it is the correct ans to the question I asked.

In case anyone facing similar issue, my biggest mistake (and I wasted 1 day behind it) was with 'x-google-backend > address'. I was using only the FQDN of the cloud function not the entire URL. So This is wrong:

/myfunction/mymodule1/dosomething:
    post:
      summary: I command you to do something
      operationId: doSomething
      x-google-backend:
        address: https://xxxxxxxx.cloudfunctions.net
        path_translation: APPEND_PATH_TO_ADDRESS
      parameters:
        - name: someheaderparam
          in: header
          description: shhh
          required: true
          type: string
        - name: payload
          in: body
          description: playload
          required: false
          schema:
            type: object
      responses:
        '200':
          description: OK
          schema:
            type: object
        '401':
           $ref: '#/responses/UnauthorizedError'

For this to work I needed to use the entire url of the function not just FQDN.

I my case my firebase/cloud function was an express app where I had published the function like this

exports.myfunction = functions.https.onRequest(app);

So the name of the cloudfunction is myfunction and its base url is:

https://xxxxxxxx.cloudfunctions.net/myfunction

Using express I added several paths to it, such as

app.post('/mymodule1/dosomething', validateToken(), somemethod);

If my function were to be publicly accessible, in order to invoke 'somemethod' function the url would have been:

https://xxxxxxxx.cloudfunctions.net/myfunction/mymodule1/dosomething

In order to have this mapped using openAPI behind api gateway the specification looks like this:

/mymodule1/dosomething:
    post:
      summary: I command you to do something
      operationId: doSomething
      x-google-backend:
        address: https://xxxxxxxx.cloudfunctions.net/myfunction
        path_translation: APPEND_PATH_TO_ADDRESS
      parameters:
        - name: someheaderparam
          in: header
          description: shhh
          required: true
          type: string
        - name: payload
          in: body
          description: playload
          required: false
          schema:
            type: object
      responses:
        '200':
          description: OK
          schema:
            type: object
        '401':
           $ref: '#/responses/UnauthorizedError'

This is also true even if the function is not an express app. In the openAPI specification, the x-google-backend address must be the URL of the function not just the FQDN of the cloud function.

Upvotes: 0

Views: 1780

Answers (1)

guillaume blaquiere
guillaume blaquiere

Reputation: 75888

To achieve this, you need 2 things

  • Firstly to restrict access to your Cloud Function
  • Then, you need to all only allow Cloud Endpoints to access to your functions

Like this, the function will be reachable from the internet but only the authorized service (ESPv2) will be able to invoke them.


  1. For the first point, deploy your function in private mode (add --no-allow-unauthenticated param when you deploy them)

  2. Then,

  • Create a service account dedicated to your ESPv2 service (if not yet the case)
  • Redeploy your ESPv2 service with this custom service account
  • Grant the service account the roles/cloudfunctions.invoker
    • Either on the project, this means the service account will be able to invoke any function in the project
    • Or at the functions level to allow the service account to invoke only a subset of functions. It's particularly interesting when all the functions aren't in the same project.

Upvotes: 2

Related Questions