Google Cloud (GCP) Classic

Pulumi Official
Package maintained by Pulumi
v6.32.0 published on Wednesday, Jul 20, 2022 by Pulumi

getProjectServiceAccount

Get the email address of a project’s unique automatic Google Cloud Storage service account.

For each Google Cloud project, Google maintains a unique service account which is used as the identity for various Google Cloud Storage operations, including operations involving customer-managed encryption keys and those involving storage notifications to pub/sub. This automatic Google service account requires access to the relevant Cloud KMS keys or pub/sub topics, respectively, in order for Cloud Storage to use these customer-managed resources.

The service account has a well-known, documented naming format which is parameterised on the numeric Google project ID. However, as noted in the docs, it is only created when certain relevant actions occur which presuppose its existence. These actions include calling a Cloud Storage API endpoint to yield the service account’s identity, or performing some operations in the UI which must use the service account’s identity, such as attempting to list Cloud KMS keys on the bucket creation page.

Use of this data source calls the relevant API endpoint to obtain the service account’s identity and thus ensures it exists prior to any API operations which demand its existence, such as specifying it in Cloud IAM policy. Always prefer to use this data source over interpolating the project ID into the well-known format for this service account, as the latter approach may cause provider update errors in cases where the service account does not yet exist.

When you write provider code which uses features depending on this service account and your provider code adds the service account in IAM policy on other resources, you must take care for race conditions between the establishment of the IAM policy and creation of the relevant Cloud Storage resource. Cloud Storage APIs will require permissions on resources such as pub/sub topics or Cloud KMS keys to exist before the attempt to utilise them in a bucket configuration, otherwise the API calls will fail. You may need to use depends_on to create an explicit dependency between the IAM policy resource and the Cloud Storage resource which depends on it. See the examples here and in the gcp.storage.Notification resource.

For more information see the API reference.

Example Usage

Pub/Sub Notifications

using Pulumi;
using Gcp = Pulumi.Gcp;

class MyStack : Stack
{
    public MyStack()
    {
        var gcsAccount = Output.Create(Gcp.Storage.GetProjectServiceAccount.InvokeAsync());
        var binding = new Gcp.PubSub.TopicIAMBinding("binding", new Gcp.PubSub.TopicIAMBindingArgs
        {
            Topic = google_pubsub_topic.Topic.Name,
            Role = "roles/pubsub.publisher",
            Members = 
            {
                gcsAccount.Apply(gcsAccount => $"serviceAccount:{gcsAccount.EmailAddress}"),
            },
        });
    }

}
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/pubsub"
	"github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		gcsAccount, err := storage.GetProjectServiceAccount(ctx, nil, nil)
		if err != nil {
			return err
		}
		_, err = pubsub.NewTopicIAMBinding(ctx, "binding", &pubsub.TopicIAMBindingArgs{
			Topic: pulumi.Any(google_pubsub_topic.Topic.Name),
			Role:  pulumi.String("roles/pubsub.publisher"),
			Members: pulumi.StringArray{
				pulumi.String(fmt.Sprintf("%v%v", "serviceAccount:", gcsAccount.EmailAddress)),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
package generated_program;

import java.util.*;
import java.io.*;
import java.nio.*;
import com.pulumi.*;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var gcsAccount = Output.of(StorageFunctions.getProjectServiceAccount());

        var binding = new TopicIAMBinding("binding", TopicIAMBindingArgs.builder()        
            .topic(google_pubsub_topic.topic().name())
            .role("roles/pubsub.publisher")
            .members(String.format("serviceAccount:%s", gcsAccount.apply(getProjectServiceAccountResult -> getProjectServiceAccountResult.emailAddress())))
            .build());

    }
}
import pulumi
import pulumi_gcp as gcp

gcs_account = gcp.storage.get_project_service_account()
binding = gcp.pubsub.TopicIAMBinding("binding",
    topic=google_pubsub_topic["topic"]["name"],
    role="roles/pubsub.publisher",
    members=[f"serviceAccount:{gcs_account.email_address}"])
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const gcsAccount = gcp.storage.getProjectServiceAccount({});
const binding = new gcp.pubsub.TopicIAMBinding("binding", {
    topic: google_pubsub_topic.topic.name,
    role: "roles/pubsub.publisher",
    members: [gcsAccount.then(gcsAccount => `serviceAccount:${gcsAccount.emailAddress}`)],
});
resources:
  binding:
    type: gcp:pubsub:TopicIAMBinding
    properties:
      topic: ${google_pubsub_topic.topic.name}
      role: roles/pubsub.publisher
      members:
        - serviceAccount:${gcsAccount.emailAddress}
variables:
  gcsAccount:
    Fn::Invoke:
      Function: gcp:storage:getProjectServiceAccount
      Arguments: {}

Cloud KMS Keys

using Pulumi;
using Gcp = Pulumi.Gcp;

class MyStack : Stack
{
    public MyStack()
    {
        var gcsAccount = Output.Create(Gcp.Storage.GetProjectServiceAccount.InvokeAsync());
        var binding = new Gcp.Kms.CryptoKeyIAMBinding("binding", new Gcp.Kms.CryptoKeyIAMBindingArgs
        {
            CryptoKeyId = "your-crypto-key-id",
            Role = "roles/cloudkms.cryptoKeyEncrypterDecrypter",
            Members = 
            {
                gcsAccount.Apply(gcsAccount => $"serviceAccount:{gcsAccount.EmailAddress}"),
            },
        });
        var bucket = new Gcp.Storage.Bucket("bucket", new Gcp.Storage.BucketArgs
        {
            Location = "US",
            Encryption = new Gcp.Storage.Inputs.BucketEncryptionArgs
            {
                DefaultKmsKeyName = "your-crypto-key-id",
            },
        }, new CustomResourceOptions
        {
            DependsOn = 
            {
                binding,
            },
        });
    }

}
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/kms"
	"github.com/pulumi/pulumi-gcp/sdk/v6/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		gcsAccount, err := storage.GetProjectServiceAccount(ctx, nil, nil)
		if err != nil {
			return err
		}
		binding, err := kms.NewCryptoKeyIAMBinding(ctx, "binding", &kms.CryptoKeyIAMBindingArgs{
			CryptoKeyId: pulumi.String("your-crypto-key-id"),
			Role:        pulumi.String("roles/cloudkms.cryptoKeyEncrypterDecrypter"),
			Members: pulumi.StringArray{
				pulumi.String(fmt.Sprintf("%v%v", "serviceAccount:", gcsAccount.EmailAddress)),
			},
		})
		if err != nil {
			return err
		}
		_, err = storage.NewBucket(ctx, "bucket", &storage.BucketArgs{
			Location: pulumi.String("US"),
			Encryption: &storage.BucketEncryptionArgs{
				DefaultKmsKeyName: pulumi.String("your-crypto-key-id"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			binding,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
package generated_program;

import java.util.*;
import java.io.*;
import java.nio.*;
import com.pulumi.*;
import com.pulumi.resources.CustomResourceOptions;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var gcsAccount = Output.of(StorageFunctions.getProjectServiceAccount());

        var binding = new CryptoKeyIAMBinding("binding", CryptoKeyIAMBindingArgs.builder()        
            .cryptoKeyId("your-crypto-key-id")
            .role("roles/cloudkms.cryptoKeyEncrypterDecrypter")
            .members(String.format("serviceAccount:%s", gcsAccount.apply(getProjectServiceAccountResult -> getProjectServiceAccountResult.emailAddress())))
            .build());

        var bucket = new Bucket("bucket", BucketArgs.builder()        
            .location("US")
            .encryption(BucketEncryptionArgs.builder()
                .defaultKmsKeyName("your-crypto-key-id")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(binding)
                .build());

    }
}
import pulumi
import pulumi_gcp as gcp

gcs_account = gcp.storage.get_project_service_account()
binding = gcp.kms.CryptoKeyIAMBinding("binding",
    crypto_key_id="your-crypto-key-id",
    role="roles/cloudkms.cryptoKeyEncrypterDecrypter",
    members=[f"serviceAccount:{gcs_account.email_address}"])
bucket = gcp.storage.Bucket("bucket",
    location="US",
    encryption=gcp.storage.BucketEncryptionArgs(
        default_kms_key_name="your-crypto-key-id",
    ),
    opts=pulumi.ResourceOptions(depends_on=[binding]))
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const gcsAccount = gcp.storage.getProjectServiceAccount({});
const binding = new gcp.kms.CryptoKeyIAMBinding("binding", {
    cryptoKeyId: "your-crypto-key-id",
    role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
    members: [gcsAccount.then(gcsAccount => `serviceAccount:${gcsAccount.emailAddress}`)],
});
const bucket = new gcp.storage.Bucket("bucket", {
    location: "US",
    encryption: {
        defaultKmsKeyName: "your-crypto-key-id",
    },
}, {
    dependsOn: [binding],
});
resources:
  binding:
    type: gcp:kms:CryptoKeyIAMBinding
    properties:
      cryptoKeyId: your-crypto-key-id
      role: roles/cloudkms.cryptoKeyEncrypterDecrypter
      members:
        - serviceAccount:${gcsAccount.emailAddress}
  bucket:
    type: gcp:storage:Bucket
    properties:
      location: US
      encryption:
        defaultKmsKeyName: your-crypto-key-id
    options:
      dependson:
        - ${binding}
variables:
  gcsAccount:
    Fn::Invoke:
      Function: gcp:storage:getProjectServiceAccount
      Arguments: {}

Using getProjectServiceAccount

Two invocation forms are available. The direct form accepts plain arguments and either blocks until the result value is available, or returns a Promise-wrapped result. The output form accepts Input-wrapped arguments and returns an Output-wrapped result.

function getProjectServiceAccount(args: GetProjectServiceAccountArgs, opts?: InvokeOptions): Promise<GetProjectServiceAccountResult>
function getProjectServiceAccountOutput(args: GetProjectServiceAccountOutputArgs, opts?: InvokeOptions): Output<GetProjectServiceAccountResult>
def get_project_service_account(project: Optional[str] = None,
                                user_project: Optional[str] = None,
                                opts: Optional[InvokeOptions] = None) -> GetProjectServiceAccountResult
def get_project_service_account_output(project: Optional[pulumi.Input[str]] = None,
                                user_project: Optional[pulumi.Input[str]] = None,
                                opts: Optional[InvokeOptions] = None) -> Output[GetProjectServiceAccountResult]
func GetProjectServiceAccount(ctx *Context, args *GetProjectServiceAccountArgs, opts ...InvokeOption) (*GetProjectServiceAccountResult, error)
func GetProjectServiceAccountOutput(ctx *Context, args *GetProjectServiceAccountOutputArgs, opts ...InvokeOption) GetProjectServiceAccountResultOutput

> Note: This function is named GetProjectServiceAccount in the Go SDK.

public static class GetProjectServiceAccount 
{
    public static Task<GetProjectServiceAccountResult> InvokeAsync(GetProjectServiceAccountArgs args, InvokeOptions? opts = null)
    public static Output<GetProjectServiceAccountResult> Invoke(GetProjectServiceAccountInvokeArgs args, InvokeOptions? opts = null)
}
public static CompletableFuture<GetProjectServiceAccountResult> getProjectServiceAccount(GetProjectServiceAccountArgs args, InvokeOptions options)
// Output-based functions aren't available in Java yet
Fn::Invoke:
  Function: gcp:storage/getProjectServiceAccount:getProjectServiceAccount
  Arguments:
    # Arguments dictionary

The following arguments are supported:

Project string

The project the unique service account was created for. If it is not provided, the provider project is used.

UserProject string

The project the lookup originates from. This field is used if you are making the request from a different account than the one you are finding the service account for.

Project string

The project the unique service account was created for. If it is not provided, the provider project is used.

UserProject string

The project the lookup originates from. This field is used if you are making the request from a different account than the one you are finding the service account for.

project String

The project the unique service account was created for. If it is not provided, the provider project is used.

userProject String

The project the lookup originates from. This field is used if you are making the request from a different account than the one you are finding the service account for.

project string

The project the unique service account was created for. If it is not provided, the provider project is used.

userProject string

The project the lookup originates from. This field is used if you are making the request from a different account than the one you are finding the service account for.

project str

The project the unique service account was created for. If it is not provided, the provider project is used.

user_project str

The project the lookup originates from. This field is used if you are making the request from a different account than the one you are finding the service account for.

project String

The project the unique service account was created for. If it is not provided, the provider project is used.

userProject String

The project the lookup originates from. This field is used if you are making the request from a different account than the one you are finding the service account for.

getProjectServiceAccount Result

The following output properties are available:

EmailAddress string

The email address of the service account. This value is often used to refer to the service account in order to grant IAM permissions.

Id string

The provider-assigned unique ID for this managed resource.

Project string
UserProject string
EmailAddress string

The email address of the service account. This value is often used to refer to the service account in order to grant IAM permissions.

Id string

The provider-assigned unique ID for this managed resource.

Project string
UserProject string
emailAddress String

The email address of the service account. This value is often used to refer to the service account in order to grant IAM permissions.

id String

The provider-assigned unique ID for this managed resource.

project String
userProject String
emailAddress string

The email address of the service account. This value is often used to refer to the service account in order to grant IAM permissions.

id string

The provider-assigned unique ID for this managed resource.

project string
userProject string
email_address str

The email address of the service account. This value is often used to refer to the service account in order to grant IAM permissions.

id str

The provider-assigned unique ID for this managed resource.

project str
user_project str
emailAddress String

The email address of the service account. This value is often used to refer to the service account in order to grant IAM permissions.

id String

The provider-assigned unique ID for this managed resource.

project String
userProject String

Package Details

Repository
https://github.com/pulumi/pulumi-gcp
License
Apache-2.0
Notes

This Pulumi package is based on the google-beta Terraform Provider.