node.jsgoogle-cloud-platformgoogle-apigoogle-cloud-iamgoogle-client

Google API Node.js Library - Grant Role to service account at project level


Goal

Assign a role dialogflow.admin to a service account I created for a project using the Node.js Client library for Google APIs.

Issue

When I try to update my service accounts IAM Policy and add a role to the service account. I get an error that the role is not supported for this resource type.

I am trying to give my service account the Dialogflow API Admin Role roles/dialogflow.admin

The method in the Node.js client library I am using is iam.projects.serviceAccounts.setIamPolicy.

I have already managed to create the service account with this Node.js client library with a function shown here.

async function createServiceAccount(projectID, serviceAccountID){
    const authClient = await auth.getClient();
    var request = {
        name: "projects/"+projectID,
        resource: {
        "accountId": serviceAccountID,
        "serviceAccount": {
            "description" : "Service Account for project: "+projectID+" for DialogFlow authentication with VA",
            "displayName": "VA Dialogflow Service Account "+projectID
        }
      },
      
      auth: authClient,
    };
  
    await iam.projects.serviceAccounts.create(request, function(err, response) {
      if (err) {
        console.error(err);
        return;
      }
       console.log(JSON.stringify(response, null, 2));
    });
}

after this function runs, and I am sure the service account is created, I run my function that is meant to set the roles of this service account.

async function setServiceAccountRoles(projectID, serviceAccountID){
    const authClient = await auth.getClient();
    var request = {
        resource_: "projects/"+projectID+"/serviceAccounts/"+serviceAccountID,
        resource: {
            policy: {
                bindings: [
                    {
                        // role: "projects/"+projectID+"roles/dialogflow.admin",
                        role: "roles/dialogflow.admin",
                        "members": [
                            "serviceAccount:"+serviceAccountID
                        ]
                    }
                    ],
                    version: 1
            }
        },
      
      auth: authClient,
    };
  
    await iam.projects.serviceAccounts.setIamPolicy(request, function(err, response) {
      if (err) {
        console.error(err);
        return;
      }
       console.log(JSON.stringify(response, null, 2));
    });
}

Error

When I run this function I am give this error:

  code: 400,
  errors: [
    {
      message: 'Role roles/dialogflow.admin is not supported for this resource.',
      domain: 'global',
      reason: 'badRequest'
    }
  ]

I have used these following resources to get this far: https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts/setIamPolicy

https://cloud.google.com/iam/docs/reference/rest/v1/Policy

https://cloud.google.com/iam/docs/granting-changing-revoking-access#granting_access_to_a_service_account_for_a_resource

Alternative methods.

I have tried changing the role to a project specific path like this:

async function setServiceAccountRoles(projectID, serviceAccountID){
    const authClient = await auth.getClient();
    var request = {
        resource_: "projects/"+projectID+"/serviceAccounts/"+serviceAccountID,
        resource: {
            policy: {
                bindings: [
                    {
                        role: "projects/"+projectID+"roles/dialogflow.admin",
                        "members": [
                            "serviceAccount:"+serviceAccountID
                        ]
                    }
                    ],
                    version: 1
            }
        },
      
      auth: authClient,
    };
  
    await iam.projects.serviceAccounts.setIamPolicy(request, function(err, response) {
      if (err) {
        console.error(err);
        return;
      }
       console.log(JSON.stringify(response, null, 2));
    });
}

however, with this I get the error : message: "Role (projects/va-9986d601/roles/dialogflow.admin) does not exist in the resource's hierarchy.",

Is it possible that the only way to update my service account's roles and permission is through the console or gcloud commands? If so, is there any recommended ways of running said gcloud commands through the node.js client library or from a node application itself?


Solution

  • You are trying to set an IAM policy on the service account. That is used to grant other identities access to the service account itself.

    You should modify the IAM binding for the project and not for the service account.

    Use the getIamPolicy and setIamPolicy. Examples are included with the documentation.

    WARNING: be very careful writing code that modifies a project's bindings. If you overwrite the bindings you can easily lock yourself out of your project. Then you would need to open a paid support ticket with Google Cloud Support. Practice with a throw away project.