Search code examples
google-cloud-platformgoogle-cloud-functionsgoogle-iamgoogle-cloud-scheduler

Cloud Scheduler - cannot create job for Cloud Functions PERMISSION_DENIED


I have this rather simple python and bash script that should create SA, deploy cloud function (with HTTP trigger) and set scheduler to trigger this function.

main.py

import functions_framework

# Register an HTTP function with the Functions Framework
@functions_framework.http
def my_http_function(request):
  # Your code here

  # Return an HTTP response
  return 'OK'

requirements.txt

functions-framework==3.*

commands.sh

#!/bin/bash

SA_NAME=cf-sa-test
PROJECT=<PROJECT-ID>
REGION=europe-west1
SA_EMAIL=$SA_NAME@$PROJECT.iam.gserviceaccount.com
PROJECT_NUMBER=$(gcloud projects list --filter="$PROJECT" --format="value(PROJECT_NUMBER)")
CF_NAME=my_http_function

gcloud iam service-accounts create $SA_NAME --project=$PROJECT --description="CF SA TEST" --display-name="CF SA TEST"

gcloud functions deploy $CF_NAME --project=$PROJECT --gen2 --region=$REGION --runtime=python311 --source=. --entry-point=my_http_function --trigger-http --run-service-account=$SA_EMAIL --no-allow-unauthenticated

gcloud scheduler jobs create http cf-test-job \
--location=$REGION \
--schedule="0 */6 * * *" \
--uri="$(gcloud functions describe $CF_NAME --gen2 --project=$PROJECT --region=$REGION --format="value(serviceConfig.uri)")" \
--http-method=GET \
--oidc-service-account-email=$SA_EMAIL

When executed commands.sh adds SA, deploy cloud function but it throws error on gcloud scheduler jobs create:

$ ./commands.sh
Created service account [cf-sa-test].
Preparing function...done.                                                                                                                                                                                                                                 
✓ Deploying function...                                                                                                                                                                                                                                    
  ✓ [Build] Logs are available at [https://console.cloud.google.com/cloud-build/builds;region=europe-west1/b219ea91-2cbe-4bfe-a813-27779ecab550?project=<PROJECT-NUMBER>]                                                                                      
  ✓ [Service]                                                                                                                                                                                                                                              
  . [ArtifactRegistry]                                                                                                                                                                                                                                     
  . [Healthcheck]                                                                                                                                                                                                                                          
  . [Triggercheck]                                                                                                                                                                                                                                         
Done.                                                                                                                                                                                                                                                      
You can view your function in the Cloud Console here: https://console.cloud.google.com/functions/details/europe-west1/my_http_function?project=<PROJECT-ID>

buildConfig:
  build: projects/<PROJECT-NUMBER>/locations/europe-west1/builds/b219ea91-2cbe-4bfe-a813-27779ecab550
  entryPoint: my_http_function
  runtime: python311
  source:
    storageSource:
      bucket: gcf-v2-sources-<PROJECT-NUMBER>-europe-west1
      object: my_http_function/function-source.zip
  sourceProvenance:
    resolvedStorageSource:
      bucket: gcf-v2-sources-<PROJECT-NUMBER>-europe-west1
      generation: '1685431646792344'
      object: my_http_function/function-source.zip
environment: GEN_2
labels:
  deployment-tool: cli-gcloud
name: projects/<PROJECT-ID>/locations/europe-west1/functions/my_http_function
serviceConfig:
  allTrafficOnLatestRevision: true
  availableCpu: '0.1666'
  availableMemory: 256M
  ingressSettings: ALLOW_ALL
  maxInstanceCount: 100
  maxInstanceRequestConcurrency: 1
  revision: my-http-function-00001-bij
  service: projects/<PROJECT-ID>/locations/europe-west1/services/my-http-function
  serviceAccountEmail: cf-sa-test@<PROJECT-ID>.iam.gserviceaccount.com
  timeoutSeconds: 60
  uri: https://<FUNCTION-URL>
state: ACTIVE
updateTime: '2023-05-30T07:28:19.023163428Z'
ERROR: (gcloud.scheduler.jobs.create.http) PERMISSION_DENIED: The principal (user or service account) lacks IAM permission "iam.serviceAccounts.actAs" for the resource "cf-sa-test@<PROJECT-ID>.iam.gserviceaccount.com" (or the resource may not exist)

I figured out that maybe scheduler SA needs to have access to cloud function SA so I tried to run

gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL --project=$PROJECT --member=serviceAccount:service-$PROJECT_NUMBER@gcp-sa-cloudscheduler.iam.gserviceaccount.com --role=roles/iam.serviceAccountUser
gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL --project=$PROJECT --member=serviceAccount:service-$PROJECT_NUMBER@gcp-sa-cloudscheduler.iam.gserviceaccount.com --role=roles/iam.serviceAccountTokenCreator

Result was:

Updated IAM policy for serviceAccount [cf-sa-test@<PROJECT-ID>.iam.gserviceaccount.com].
bindings:
- members:
  - serviceAccount:service-<PROJECT-NUMBER>@gcp-sa-cloudscheduler.iam.gserviceaccount.com
  role: roles/iam.serviceAccountTokenCreator
- members:
  - serviceAccount:service-<PROJECT-NUMBER>@gcp-sa-cloudscheduler.iam.gserviceaccount.com
  role: roles/iam.serviceAccountUser
etag: BwX85KXvXas=
version: 1

I waited like 10 minutes just in case but result was the same:

ERROR: (gcloud.scheduler.jobs.create.http) PERMISSION_DENIED: The principal (user or service account) lacks IAM permission "iam.serviceAccounts.actAs" for the resource "cf-sa-test@<PROJECT-ID>.iam.gserviceaccount.com" (or the resource may not exist)

I must be doing some silly mistake because all those steps look correct. What am I doing wrong here? Thanks.


Solution

  • Thanks to @Veera Nagireddy suggestions to check permissions and a night of good sleep I finally managed to find out why I could not create scheduler job with OIDC. Scheduler did not have permissions to service account because I tried to create scheduler job in different project than cloud function... I was missing --project=$PROJECT in gcloud command and it was using default project instead.