Error: 7 PERMISSION_DENIED: User not authorized to perform this action when publishing to Pub/Sub from Cloud Function
0 reputation · 08 Apr 2022, 11:57 UTC
0 reputation · 08 Apr 2022, 11:57 UTC
Determine how to validate Pub/Sub publish permissions for a Cloud Function before deployment so that the function works both in the local emulator and in production without encountering a PERMISSION_DENIED error.
--allow-local bypasses IAM checks, allowing the function to use the local user’s default credentials.roles/pubsub.publisher role on the target topic.Given these factors, what steps or configurations can be used to reliably detect missing IAM permissions during local testing?
Can the emulator be run with a service account key to mimic production IAM enforcement?
What is the minimal IAM binding required on the Pub/Sub topic for the function’s service account to publish successfully?
35275 reputation · 08 Apr 2022, 18:03 UTC
To resolve the PERMISSION_DENIED error, you must grant the roles/pubsub.publisher role to the specific service account assigned to your Cloud Function. This binding must be applied either at the project level or, preferably, directly on the target Pub/Sub topic to follow the principle of least privilege.
The minimal permission required to publish messages is pubsub.topics.publish. This is bundled into the following predefined role:
roles/pubsub.publisher (Pub/Sub Publisher)serviceAccount:[YOUR_FUNCTION_SERVICE_ACCOUNT]@[PROJECT_ID].iam.gserviceaccount.comThere is a fundamental difference in how identity is handled between the emulator and the cloud environment:
The Cloud Functions emulator does not connect to the GCP IAM policy engine to validate permissions in real-time. When using --allow-local, the emulator typically relies on Application Default Credentials (ADC). If you are logged in via gcloud auth application-default login, the function uses your personal user permissions, which are usually broader than the production service account, masking potential permission gaps.
To detect missing permissions before deployment, you can force the emulator to use a specific service account identity by pointing to a JSON key file. This mimics the production identity plane:
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-file.json"
Note: Never commit service account JSON keys to version control. Use a secret manager or local environment variables.
If the error persists in production, verify the following:
Diagnostic Detail Needed: Are you using the default App Engine service account or a user-managed custom service account? Default accounts often have broader permissions (like Editor) that can hide configuration errors until they are tightened for security.
Use comments to ask for clarification. Post a solution as an answer.
6,200 reputation · 08 Apr 2022, 18:27 UTC
If the Pub/Sub topic resides in a different Google Cloud project than the function, granting roles/pubsub.publisher in the function's project is not enough. The topic's owning project must contain the IAM binding for serviceAccount:FUNCTION_SA@FUNCTION_PROJECT.iam.gserviceaccount.com on that topic. The local emulator does not replicate cross-project IAM resolution, so a successful local publish does not prove the production binding exists. Verify with gcloud pubsub topics get-iam-policy TOPIC --project=TOPIC_PROJECT and confirm the member and role appear under the topic's project, not merely the function's project. This applies to both Cloud Functions generations, though the default service account differs between them.