Hey, Just started using Pulumi and running into s...
# google-cloud
m
Hey, Just started using Pulumi and running into some issues trying to get on GCP. I’m trying to setup a REST API for a cloud function. I am using gen1 cloudfunction for now and I’ve set a custom service account to the cloudfunction and on first time deploy this works well, but if I attempt to update the cloudfunction then I get the following error
Copy code
gcp:cloudfunctions:Function (init):
    error: 1 error occurred:
        * Error while updating cloudfunction configuration: googleapi: Error 400: Invalid function service account requested: <mailto:shared-role@test.iam.gserviceaccount.com|shared-role@test.iam.gserviceaccount.com>. Please visit <https://cloud.google.com/functions/docs/troubleshooting> for 
in-depth troubleshooting documentation., badRequest
I can’t seem to figure out why this is happening or what’s wrong. Here is samples of the related code
Copy code
const serviceAccount = new gcp.serviceaccount.Account("shared-role", {
    accountId: "shared-role",
    displayName: "Shared Role",
    project: config.projectId,
  });

  serviceAccount.email.apply((email) =>
    <http://pulumi.log.info|pulumi.log.info>(`Service account email: ${email}`),
  );

  const serviceAccountKey = new gcp.serviceaccount.Key(
    "service-account-key",
    {
      serviceAccountId: serviceAccount.name,
    },
  );
  const serviceAccountKeyJson = serviceAccountKey.privateKey.apply((key) =>
    Buffer.from(key, "base64").toString("utf8"),
  );

  const cloudBuildApi = new gcp.projects.Service("cloud-build-api", {
    service: "<http://cloudbuild.googleapis.com|cloudbuild.googleapis.com>",
    project: config.projectId,
  });

  const cloudFunctionsApi = new gcp.projects.Service("cloud-fn-api", {
    service: "<http://cloudfunctions.googleapis.com|cloudfunctions.googleapis.com>",
    project: config.projectId,
  });

  const serviceAccountAgentRole = new gcp.projects.IAMMember(
    "cloud-functions-service-agent-role",
    {
      project: config.projectId,
      role: "roles/cloudfunctions.serviceAgent",
      member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
    },
  );

  const serviceAccountUserRole = new gcp.projects.IAMMember(
    "service-account-user-role",
    {
      project: config.projectId,
      role: "roles/iam.serviceAccountUser",
      member: pulumi.interpolate`user:${config.userEmail}`, // or the relevant user/service account
    },
  );

  // Grant Editor role
  const editorRole = new gcp.projects.IAMMember("custom-sa-editor-role", {
    project: config.projectId,
    role: "roles/editor",
    member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
  });

  // Grant Compute Engine Service Agent role
  const computeServiceAgentRole = new gcp.projects.IAMMember(
    "custom-sa-compute-agent-role",
    {
      project: config.projectId,
      role: "roles/compute.serviceAgent",
      member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
    },
  );

  // Assign the "Cloud Functions Invoker" role to the service account
  const invokerRole = new gcp.projects.IAMMember(
    "cloud-fn-invoker-role",
    {
      project: config.projectId,
      role: "roles/cloudfunctions.invoker",
      member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
    },
    { dependsOn: cloudFunctionsApi },
  );

  const cloudBuildBuilderRole = new gcp.projects.IAMMember(
    "cloud-build-builder-role",
    {
      project: config.projectId,
      role: "roles/cloudbuild.builds.builder",
      member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
    },
    { dependsOn: cloudFunctionsApi },
  );

  // Add Artifact Registry Reader Role
  const artifactRegistryReaderRole = new gcp.projects.IAMMember(
    "artifact-registry-reader-role",
    {
      project: config.projectId,
      role: "roles/artifactregistry.reader",
      member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
    },
    { dependsOn: [cloudBuildApi, cloudFunctionsApi] },
  );

  // Assign Firestore permissions to the service account
  const firestoreRoleBinding = new gcp.projects.IAMMember("firestoreAccess", {
    project: config.projectId,
    role: "roles/datastore.user",
    member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
  });

  // Grant Storage Object Viewer role to the Cloud Functions service account
  const storageObjectViewerRole = new gcp.projects.IAMMember(
    "storage-object-viewer-role",
    {
      project: config.projectId,
      role: "roles/storage.objectViewer",
      member: pulumi.interpolate`serviceAccount:${serviceAccount.email}`,
    },
    { dependsOn: [cloudFunctionsApi] },
  );

const sourceCodePath = path.resolve(
    __dirname,
    "../../../../packages/functions/gcp/init",
  );

  // Create a new bucket object for the zipped source code
  const sourceArchiveObject = new gcp.storage.BucketObject(
    "source-archive-object",
    {
      bucket: bucket.name,
      source: new pulumi.asset.FileArchive(sourceCodePath),
    },
  );

const initFunction = new gcp.cloudfunctions.Function(
    "init",
    {
      runtime: "python310",
      entryPoint: "handler",
      sourceArchiveBucket: bucket.name,
      sourceArchiveObject: sourceArchiveObject.name,
      triggerHttp: true,
      environmentVariables: {
        BUCKET_NAME: bucket.name,
        WORKFLOW_NAME: "init-workflow",
        PROJECT_ID: config.projectId,
        LOCATION_ID: "us-central1",
        GOOGLE_APPLICATION_CREDENTIALS: serviceAccountKeyJson,
      },
      serviceAccountEmail: serviceAccount.email,
    },
    {
      dependsOn: [
        cloudBuildApi,
        cloudFunctionsApi,
        invokerRole,
        artifactRegistryReaderRole,
        editorRole,
        computeServiceAgentRole,
        serviceAccountUserRole,
        cloudBuildBuilderRole,
      ],
    },
  );
Any direction is greatly appreciated.