Secret manager access denied despite correct roles for service account
Asked Answered
R

11

68

I'm writing a cloud function in Nodejs (10), and trying to access a secret like so:

const [secret] = await new SecretManagerServiceClient().accessSecretVersion({
    name: `projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/latest`
})

I created the secret in the web console and the name used in code matches that of the existing secret. On the page for the cloud function details, it states that the service account is [email protected],com, so I added the secretmanager.secretAccessor role to it. However, I'm still getting the same error every time:

Error: 7 PERMISSION_DENIED: Permission 'secretmanager.versions.access' denied for resource 'projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/latest' (or it may not exist).

It makes no difference if I specify a concrete version or just use latest.

Ratite answered 18/6, 2020 at 7:44 Comment(13)
Should be working, double check secret name and service account name, then try removing secretAccessor role and adding it back. If this doesn't help, try redeploying the function.Gabby
Just to be sure: what are you using as the PROJECT_NUMBER? Code looks fine to me and I think the only additional permission I added on my test container was Secret Manager Secret Accessor. Just for reference here is my code that is definitely working on my test container: const dbURI = secret.readSecret("projects/tasklist-XXXXXX/secrets/dev-db-connectionstring/versions/latest").then((connectionString) => { mongoose.connect(connectionString); });Palaeography
@VilleRinne Where are you getting tasklist-XXXXXX from? Mine is just numbers, no letters; perhaps I'm taking the wrong value? (except it's the same path as listed on the secrets web page)Ratite
Tasklist-XXXXXX is just the full project identifier for my project. So when I created the project I entered tasklist as the name and Google appended the numbers at the end to make it unique. You can see the identifiers for every project in the console when you click to change the project and with gcloud.Palaeography
This is just project id, while in your case you use project number, it doesn't matter and should work fine with both. @VilleRinne please do not post project ids on public resources, use placeholders.Gabby
Yeah this is a test project that will get deleted in the next few days, but you are correct.Palaeography
Alright, I can see that the service account does indeed have the secret accessor role, and the code is correct. I don't have IAM persmissions myself so I'll have to reach out to the admin to see if they can spot something amiss. I'll update this post with an answer if I get it resolved.Ratite
Have you tried removing and adding role to service account? Just to rule out this possibility.Gabby
The service account is a default and has never been deleted (heck, we could probably do with deleting some of our unused service accounts!). It did not have any secret manager permissions before the role was added, and did have them after. I'll talk to the admin and try it regardless.Ratite
I realized that I am also using a customer service account on my test project, and I hav given it owner permissions. So maybe you could do one more test with really loose permissions to rule out that you aren't missing something?Palaeography
And by customer service account I of course meant custom :-)Palaeography
A service account with only this role should work fine. May be try creating a new service account, give it only this role and redeploy your function with this service account and try again. Maybe there is something wrong with the default one.Gabby
How are you deploying the function? Both project_id and project_number are acceptable for the secret name.Mastitis
V
55

HTTP cloud function code:

const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');

const secretManagerServiceClient = new SecretManagerServiceClient();
const name = 'projects/shadowsocks-218808/secrets/workflow/versions/latest';

exports.testSecretManager = async (req, res) => {
  const [version] = await secretManagerServiceClient.accessSecretVersion({ name });
  const payload = version.payload.data.toString();
  console.debug(`Payload: ${payload}`);
  res.sendStatus(200);
};

Deploy:

gcloud functions deploy testSecretManager --runtime nodejs10 --trigger-http --allow-unauthenticated

Deploying function (may take a while - up to 2 minutes)...done.                                                                                                                                                                                                                        
availableMemoryMb: 256
entryPoint: testSecretManager
httpsTrigger:
  url: https://us-central1-shadowsocks-218808.cloudfunctions.net/testSecretManager
ingressSettings: ALLOW_ALL
labels:
  deployment-tool: cli-gcloud
name: projects/shadowsocks-218808/locations/us-central1/functions/testSecretManager
runtime: nodejs10
serviceAccountEmail: [email protected]
sourceUploadUrl: https://storage.googleapis.com/gcf-upload-us-central1-43476143-b555-4cb2-8f6f-1b2d1952a2d7/42c4cda4-98a8-4994-a3be-d2203b9e646a.zip?GoogleAccessId=service-16536262744@gcf-admin-robot.iam.gserviceaccount.com&Expires=1596513795&Signature=kbLw5teN8EoYmj4fEweKKiIaakxcrhlUg2GGHV4jWJjvmeEfXePpRNOn9yz2zLn%2Fba0UqM9qdJMXujs5afBk%2BVBmywPEiptAZe2qgmldpr%2BsYejFu0woNgsPHVqtJ0NoWDo6W2dq4CuNNwO%2BaQ89mnhahUUQTInkJ55Y3wCIe9smk%2BqWtcvta3zICiToA7RQvPKY5MS6NViyj5mLxuJtDlTY9IKPL%2BqG6JAaQJSFYKYVgLyb6JfirXk8Q7%2FMvnHPpXPlhvsBLQksbF6jDPeefp2HyW4%2FSIQYprfpwKV3hlEIQyRQllz5J9yF83%2FxDPh%2BQPc5QmswKP5XAvYaszJPEw%3D%3D
status: ACTIVE
timeout: 60s
updateTime: '2020-08-04T03:34:32.665Z'
versionId: '2'

Test:

gcloud functions call testSecretManager --data '{}'

Got error same as you:

error: |-
  Error: function terminated. Recommended action: inspect logs for termination reason. Details:
  7 PERMISSION_DENIED: Permission 'secretmanager.versions.access' denied for resource 'projects/shadowsocks-218808/secrets/workflow/versions/latest' (or it may not exist).

solution:

You can find the serviceAccountEmail: [email protected] from the deployment information details of cloud function.

go to IAM & Admin web UI, click ADD ANOTHER ROLE button, add Secret Manager Secret Accessor role to this service account.

enter image description here

Test again:

> gcloud functions call testSecretManager --data '{}'

executionId: 1tsatxl6fndw
result: OK

Read the logs for testSecretManager cloud function:

gcloud functions logs read testSecretManager

You will see the logs for the secret payload string.

Vulcan answered 4/8, 2020 at 4:35 Comment(3)
For those looking today, you have to go under IAM & Admin > IAM, not the Service Accounts section. Wasted a huge amount of time trying to add permissions from under the Service Accounts section... they should really make this clearer.Fuze
@arao6, you must answer this question with your comment. Your comment is the correct answer. Thanks!Karafuto
Thank you for the tip. I just added the Secret Manager Secret Accessor role to Editor under my App Engine default service account and it worked perfectly.Pelias
Y
33

I had the same issue and to solve it, I just had to:

  1. Find the Service Account under General of my Google Cloud Function.

    It looked like <project-name>@appspot.gserviceaccount.com

  2. In IAM Admin, Add Secret Manager Secret Accessor Role to this Service Account.

After this, everything worked!

Yarvis answered 8/8, 2020 at 20:29 Comment(2)
<project-name> was the key thing here. As I had many service accounts in thereSumrall
Oh god. Now I understood where I'm going wrong. I tool whole day to fix it.Illuminism
L
17

I have had similar issues working with secretmanager and the python google-cloud-secretmanager library (2.4). Specifically, after creating a secret and giving my service account the secretmanager.secretAccessor role on this secret (and nothing else, following the principle of least privilege), I was getting the following error when trying to access it:

details = "Permission 'secretmanager.versions.access' denied for resource 'projects/projectid/secrets/keyname/versions/latest' (or it may not exist)."

I could only make it work by also adding the secretmanager.viewer role at the project level, which as far as I can tell is not described in the documentation.

Logography answered 30/4, 2021 at 9:22 Comment(6)
OMG THANK YOU, finally, it took me so long to find out the accessor role is not enough 😣🙏Touchy
I'm struggling with the same. How did you add the role "at the project level"?Pirzada
When adding roles in GCP, you can typically add them on the whole project (you do this by going to the projects IAM page and giving the permission to the user/service account), or with more granularity on the ressource level (you do this by visiting the relevant ressource's page, here a Secret manager secret, and setting the permission there). Sometimes it's a bit more confusing and you need a mix of both project-wide and ressource-level permissions to make it work - as is the case here.Logography
in my case i didn't need to do it at project level but did go into secret manager --- clicked into my secret --- went to permissions tab --- and added App Engine default service account the following permissions: (was already there) = Editor + 1) Secret Manager Secret Accessor + 2) Secret Manager Viewer = now worksRather
This is the answer; this worked for me. but I don't understand. The default compute service account is Editor on the project. Should have all rights to everything. Why do I specially need to grant secretAccessor ? Nothing in the documentation tells me I need to do this with the default service account.Interpellant
@Interpellant that's the thing, "Should have all rights to everything" is incorrect (that would be "owner"). Editor has wide rights, but not all of them.Logography
T
1

A bit late, but maybe this answer could be useful for future users. I encountered the same behavior only with Python. I tried lots of things but only thing that worked was creating new service account with zero roles(if I granted it secretmanager.secretAccessor role immediately, I got the same error). Then when empty service account is created, in IAM tab I press +Add, copy my empty service account adress and ONLY then I add secretmanager.secretAccessor role to it. Then I use this account as the account that will execute particular function. You of course may need to add other roles depending on what your function is intended to accomplish.

Tereasaterebene answered 28/7, 2020 at 6:42 Comment(0)
L
1

I had similar problem using terraform under gitlab. I must add two authorizations to the service account which runs the pipeline:

resource "google_project_iam_policy" "gitlab" {
  project     = "secret_owner_project_id"
  policy_data = data.google_iam_policy.iam.policy_data
}

data "google_iam_policy" "iam" {
  binding {
    role = "roles/secretmanager.secretAccessor"
    members = [
      "serviceAccount:[email protected]",
    ]
  }
  binding {
    role = "roles/viewer"
    members = [
      "serviceAccount:[email protected]",
    ]
  }
}
Let answered 17/6, 2021 at 9:22 Comment(0)
U
1

In my case, I was using my project-id instead of my project-number as mentioned in the OP's description:

const [secret] = await new SecretManagerServiceClient().accessSecretVersion({
    name: `projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/latest`
})

This wasn't very clear, especially since my project-id and numbers have been the same in my other projects.

You can find the project-number in the GCP console > Your Project > Settings and Utilities (3 dots on top right as of 2023) > Project Settings

Unrivaled answered 13/10, 2023 at 20:53 Comment(0)
E
1

In order to fix this issue, you must go to IAM (main page) -> Select the right Service Account as the Principal on there. THEN add the role of Secret Manager Secret Accessor.

If you go to the IAM -> Service Accounts page, and then go to add a new role, you will not find the Secrets Manager Secrets Accessor role - along with many others that aren't available there.

Can't take credit for this, this is from
arao6's comment on the previous top comment. I just don't have the rep to like posts yet.

Entryway answered 28/2 at 0:17 Comment(0)
P
0

OAuth scope plays an important role here and please make sure the scope is defined correctly.

To use Secret Manager with workloads running on Compute Engine or GKE, the underlying instance or node must have the cloud-platform OAuth scope. If you receive an error with the following message, it means the instance or node was not provisioned with the correct OAuth scopes.

Request had insufficient authentication scopes

The required OAuth scope to use Secret Manager is:

https://www.googleapis.com/auth/cloud-platform

Example gcloud command to create dataproc with scope

gcloud dataproc clusters create xyz-pqr --region asia-south1 --subnet projects/xyz-pqr/regions/asia-south1/subnetworks/abc-serverless-vpc --zone asia-south1-b --master-machine-type n1-standard-4 --master-boot-disk-size 100 --num-workers 2 --worker-machine-type n1-standard-4 --worker-boot-disk-size 100 --image-version 2.0-debian10 --project xyz-development -scopes https://www.googleapis.com/auth/cloud-platform

Pazpaza answered 30/12, 2021 at 6:41 Comment(0)
C
0

I was having the same issue when running Go program and was getting error - rpc error: code = PermissionDenied desc = Permission 'secretmanager.versions.access' denied for resource 'projects/...' on my machine. It did not work by setting role "Secret Manager Secret Accessor" on my Compute Engine default service account that looks something like [email protected], nor editing permissions from within Secret Manager, side panel permissions.

What helped was gcloud secrets list and gcloud secrets get-iam-policy my-secret, as mentioned in this document. I am assuming it probably refreshed something locally, and I was able to get through without getting an error. https://cloud.google.com/sdk/gcloud/reference/secrets/get-iam-policy

Also gcloud secrets get-iam-policy my-secret will give which service account you are using with that secret.

Update -

I had the issue again, and this time, the command below helped.

gcloud auth application-default login

Hope this helps someone.

Coralline answered 31/7, 2023 at 22:13 Comment(0)
S
0

If you encounter this problem trying to add the "firestore-send-email" firebase extension with terraform (google_firebase_extensions_instance), you can fix the problem creating two service accounts beforehand :

  • service-${YOUR_PROJECT_ID}@gcp-sa-firebasemods.iam.gserviceaccount.com
  • service-${YOUR_PROJECT_ID}@gcf-admin-robot.iam.gserviceaccount.com

and add the roles below to the service accounts.

Terraform code:

resource "google_project_service_identity" "staging_firebaseext" {
  provider = google-beta

  project = google_firebase_project.staging.project
  service = "firebaseextensions.googleapis.com"
}

resource "google_project_iam_member" "staging_firebaseext" {
  project =google_project.staging.project_id

  for_each = toset([
    "roles/firebasemods.serviceAgent",
    "roles/secretmanager.admin",
  ])

  role = each.key

  member  = "serviceAccount:service-${google_project.staging.number}@gcp-sa-firebasemods.iam.gserviceaccount.com"
  depends_on = [
    google_project_service_identity.staging_firebaseext,

  ]
}

resource "google_project_service_identity" "staging_cloudfunc" {
  provider = google-beta

  project = google_firebase_project.staging.project
  service = "cloudfunctions.googleapis.com"
}

resource "google_project_iam_member" "staging_cloudfunc" {
  project =google_project.staging.project_id

  for_each = toset([
    "roles/cloudfunctions.serviceAgent",
    "roles/artifactregistry.reader"
  ])

  role = each.key

  member  = "serviceAccount:service-${google_project.staging.number}@gcf-admin-robot.iam.gserviceaccount.com"
  depends_on = [
    google_project_service_identity.staging_cloudfunc,
  ]
}
Sword answered 10/4 at 7:17 Comment(0)
G
0

Add secret manager accesor to the service account of cloud build you can do it in Pulumi:

  const project = await gcp.organizations.getProject({});

  const cloudBuildSASecretManager = new gcp.projects.IAMBinding(
    `${env}-cloud-build-sa-secret-manager`,
    {
      project: gcpProject,
      role: "roles/secretmanager.secretAccessor",
      members: [`serviceAccount:${project.number}@cloudbuild.gserviceaccount.com`],
    }
  );

or in with gcloud:

gcloud projects add-iam-policy-binding $PROJECT_ID \ 
--member="serviceAccount:[email protected]" \ 
--role="roles/cloudbuild.serviceAgent"
Glimmer answered 12/6 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.