0

I wanted to add security to my Cloud Function so I removed the allUsers access to call it - so I could instead only call it from a service account within my GCP.

So I have followed the tutorial in the GCP docs exactly:

Cloud Function

async function createTask(taskName, functionToFire, payload, fireAt){
    const tasksClient = new CloudTasksClient()
    const projectId = JSON.parse(process.env.FIREBASE_CONFIG).projectId
    console.log(`${taskName} will fire ${functionToFire} at ${fireAt}...`)
    const location = 'us-central1'
    const queuePath = tasksClient.queuePath(projectId, location, taskName)
    const url = `https://us-central1-${PROJECT_ID}.cloudfunctions.net/task/${functionToFire}`
    const serviceAccountEmail = 'cloud-tasks@${PROJECT_ID}.iam.gserviceaccount.com';
    // const sendAt = Date.now() / 1000 + 10 // plus 10 seconds of current epoch
    const task = {
        httpRequest: {
          httpMethod: 'POST',
          url,
          oidcToken: {
            serviceAccountEmail
          },
          body: Buffer.from(JSON.stringify(payload)).toString('base64'),
          headers: {
            'Content-Type': 'application/json',
          },
        },
        scheduleTime: {
          seconds: (fireAt / 1000) // Convert millis to seconds
        }
    }
    await tasksClient.createTask({ parent: queuePath, task })
    return 200;
}

Cloud Function permissions

The service account has been given the following permissions on this specific function called task:

  • Cloud Functions Admin
  • Cloud Functions Invoker
  • Cloud Functions Service Agent

enter image description here

However when the task actually fires, it gives this error:

PERMISSION_DENIED(7): HTTP status code 403

i've also had the following error:

UNAUTHENTICATED(16): HTTP status code 401

I've tested using 2 service accounts - the recommended one using the docs (shown above) and also a service account I created specifically for this called cloud-tasks@${PROJECT_ID}.iam.gserviceaccount.com.

I also went to the generic IAM page and checked the permissions of these service accounts:

  1. Default service account:

enter image description here

  1. Service account I created:

enter image description here

Both return the PERMISSION_DENIED or UNAUTHENTICATED errors shown above when the function fires:

enter image description here

Any idea what the problem is? I've tried almost everything.

Zorgan
  • 8,227
  • 23
  • 106
  • 207

1 Answers1

4

You forgot to put the audience in your OIDC token definition. You can find the object definition in the nodeJS documentation

...
...
 const task = {
        httpRequest: {
          httpMethod: 'POST',
          url,
          oidcToken: {
            serviceAccountEmail: serviceAccountEmail
            //Audience is the raw URL, without extra path or query parameter
            audience: https://us-central1-${PROJECT_ID}.cloudfunctions.net/task           },
...
...

guillaume blaquiere
  • 66,369
  • 2
  • 47
  • 76
  • Thought that was optional but yes that indeed fixed the problem. Thankyou! – Zorgan Jun 28 '21 at 09:28
  • Based on this [doc](https://cloud.google.com/run/docs/triggering/using-tasks#node.js), I thought `audience` is not required, but it turns out that adding it fixed the problem for me. – davidbilla Nov 30 '21 at 18:48