Hi guys, I am trying to create a gcp service acco...
# general
b
Hi guys, I am trying to create a gcp service account and a k8s secret associated to it via pulumi but am failing with two issues * I am unable to create a IAM binding to the service account using the role
roles/storage.admin
(whats also weird is that using
roles/editor
works). Using
gcloud projects add-iam-policy-binding ...
however works as expected and the storage admin role is associated * I can't get the
k8s.core.v1.Secret
class to accept the created service account key as the data for the secret I am using the following code, any help is greatly appreciated!
Copy code
js
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as k8s from "@pulumi/kubernetes";

const gcloudProjectId = '...'
const resourceName = "team-v1-tyll-kaniko";
const serviceAccount = new gcp.serviceAccount.Account(`${resourceName}`, {
  accountId: "team-v1-tyll-kaniko",
  displayName: "team-v1-tyll-kaniko",
  project: gcloudProjectId
});

const serviceAccountKey = pulumi
  .all([serviceAccount.email, serviceAccount.project])
  .apply(([email, project]) => {
    return new gcp.serviceAccount.Key(`${resourceName}-key`, {
      serviceAccountId: `projects/${project}/serviceAccounts/${email}`
    });
  });

const serviceAccountBinding = pulumi
  .all([serviceAccount.email, serviceAccount.project])
  .apply(([email, project]) => {
    return new gcp.serviceAccount.IAMBinding(`${resourceName}-binding`, {
      // Throws with Role roles/storage.admin is not supported for this resource.
      // role: "roles/storage.admin",
      role: "roles/editor",
      serviceAccountId: `projects/${project}/serviceAccounts/${email}`,
      members: [`serviceAccount:${email}`]
    });
  });

const secret = new k8s.core.v1.Secret("kaniko-secret", {
  type: "generic",
  metadata: { name: "kaniko-secret" },
  data: {
    // Throws with ObjectMeta: v1.ObjectMeta: TypeMeta: Kind: Data: decode base64: illegal base64 data at input byte 17, parsing 205
    "kaniko-secret": serviceAccountKey
  }
});
Solved the secret creation, the role binding problem still persists though
Copy code
js
const secret = serviceAccountKey.apply(key => {
  return pulumi.all([key.privateKey]).apply(([privateKey]) => {
    return new k8s.core.v1.Secret("kaniko-secret", {
      type: "generic",
      metadata: { name: "kaniko-secret" },
      stringData: {
        "kaniko-secret": Buffer.from(privateKey, "base64").toString("utf8")
      }
    });
  });
});
g
1. you don’t have to construct the serviceAccountId manually. it’s actually exposed on the serviceAccount as
serviceAccount.accountId
. That saves you from having unwrap all the properties like project and email from the serviceAccount. 2. I recommend using IAMMember over iam policy or binding, since the the latter two may cause weird surprises when you assign the same role in other parts of your code or via the cloud console 3. IAMBinding has no property
serviceAccountId
- why are you putting it there? 4. Use TypesScript - saves you from mistakes like the one at 3. 😛
5. You have to use the resources from the
gcp.projects
namespace. I.e.
gcp.projects.IAMMember
or
gcp.projects.IAMBinding
. The binding / member resources in the
gcp.serviceAccount
namespace are to grant a service account (A) or user (B) the permissions to *use*/assume another service account (C). This is also described in the docs: https://pulumi.io/reference/pkg/nodejs/@pulumi/gcp/serviceAccount/#IAMMember
b
@glamorous-printer-66548 Awesome, thanks for the hint. Using
gcp.projects.IAMMember
works like a charm. Just one thing, when using
serviceAccount.accountId
as the value for the
serviceAccountId
property on the
gcp.serviceAccount.Key
class terraform throws an error stating
project: required field is not set
. Using
serviceAccount.name
instead works, e.g.
Copy code
ts
const serviceAccount = new gcp.serviceAccount.Account(
  "kaniko-service-account",
  {
    accountId: config.iam.serviceAccountName,
    displayName: config.iam.serviceAccountName,
    project: globalConfig.gcloud.projectId
  }
);

const serviceAccountKey = new gcp.serviceAccount.Key(
  `kaniko-service-account-key`,
  {
    // Using serviceAccount.accountId results in an error would be thrown stating `project: required field is not set`
    serviceAccountId: serviceAccount.name
  }
);