Create GCP Regional Secrets

The gcp:secretmanager/regionalSecret:RegionalSecret resource, part of the Pulumi GCP provider, defines a regional secret container whose versions are created and accessed within a single GCP region. This guide focuses on three capabilities: creating secrets with metadata, customer-managed encryption, and rotation scheduling.

Regional secrets are containers for sensitive data; the actual secret values live in separate RegionalSecretVersion resources. The examples are intentionally small. Combine them with your own KMS keys, Pub/Sub topics, and IAM policies.

Create a regional secret with labels and annotations

Most deployments start by creating a secret container in a specific region with metadata for tracking and discovery.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const regional_secret_basic = new gcp.secretmanager.RegionalSecret("regional-secret-basic", {
    secretId: "tf-reg-secret",
    location: "us-central1",
    labels: {
        label: "my-label",
    },
    annotations: {
        key1: "value1",
        key2: "value2",
        key3: "value3",
    },
    deletionProtection: false,
});
import pulumi
import pulumi_gcp as gcp

regional_secret_basic = gcp.secretmanager.RegionalSecret("regional-secret-basic",
    secret_id="tf-reg-secret",
    location="us-central1",
    labels={
        "label": "my-label",
    },
    annotations={
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
    },
    deletion_protection=False)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := secretmanager.NewRegionalSecret(ctx, "regional-secret-basic", &secretmanager.RegionalSecretArgs{
			SecretId: pulumi.String("tf-reg-secret"),
			Location: pulumi.String("us-central1"),
			Labels: pulumi.StringMap{
				"label": pulumi.String("my-label"),
			},
			Annotations: pulumi.StringMap{
				"key1": pulumi.String("value1"),
				"key2": pulumi.String("value2"),
				"key3": pulumi.String("value3"),
			},
			DeletionProtection: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var regional_secret_basic = new Gcp.SecretManager.RegionalSecret("regional-secret-basic", new()
    {
        SecretId = "tf-reg-secret",
        Location = "us-central1",
        Labels = 
        {
            { "label", "my-label" },
        },
        Annotations = 
        {
            { "key1", "value1" },
            { "key2", "value2" },
            { "key3", "value3" },
        },
        DeletionProtection = false,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.RegionalSecret;
import com.pulumi.gcp.secretmanager.RegionalSecretArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

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

    public static void stack(Context ctx) {
        var regional_secret_basic = new RegionalSecret("regional-secret-basic", RegionalSecretArgs.builder()
            .secretId("tf-reg-secret")
            .location("us-central1")
            .labels(Map.of("label", "my-label"))
            .annotations(Map.ofEntries(
                Map.entry("key1", "value1"),
                Map.entry("key2", "value2"),
                Map.entry("key3", "value3")
            ))
            .deletionProtection(false)
            .build());

    }
}
resources:
  regional-secret-basic:
    type: gcp:secretmanager:RegionalSecret
    properties:
      secretId: tf-reg-secret
      location: us-central1
      labels:
        label: my-label
      annotations:
        key1: value1
        key2: value2
        key3: value3
      deletionProtection: false

The secretId provides a unique identifier within the project, while location pins the secret to a specific region (e.g., us-central1). Labels and annotations add organizational metadata: labels for filtering and cost tracking, annotations for tool-specific state. The deletionProtection flag prevents accidental deletion during Pulumi operations.

Encrypt secrets with customer-managed KMS keys

Organizations with compliance requirements often control their own encryption keys rather than using Google-managed encryption.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const project = gcp.organizations.getProject({});
const kms_secret_binding = new gcp.kms.CryptoKeyIAMMember("kms-secret-binding", {
    cryptoKeyId: "kms-key",
    role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
    member: project.then(project => `serviceAccount:service-${project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com`),
});
const regional_secret_with_cmek = new gcp.secretmanager.RegionalSecret("regional-secret-with-cmek", {
    secretId: "tf-reg-secret",
    location: "us-central1",
    customerManagedEncryption: {
        kmsKeyName: "kms-key",
    },
}, {
    dependsOn: [kms_secret_binding],
});
import pulumi
import pulumi_gcp as gcp

project = gcp.organizations.get_project()
kms_secret_binding = gcp.kms.CryptoKeyIAMMember("kms-secret-binding",
    crypto_key_id="kms-key",
    role="roles/cloudkms.cryptoKeyEncrypterDecrypter",
    member=f"serviceAccount:service-{project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com")
regional_secret_with_cmek = gcp.secretmanager.RegionalSecret("regional-secret-with-cmek",
    secret_id="tf-reg-secret",
    location="us-central1",
    customer_managed_encryption={
        "kms_key_name": "kms-key",
    },
    opts = pulumi.ResourceOptions(depends_on=[kms_secret_binding]))
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/kms"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		kms_secret_binding, err := kms.NewCryptoKeyIAMMember(ctx, "kms-secret-binding", &kms.CryptoKeyIAMMemberArgs{
			CryptoKeyId: pulumi.String("kms-key"),
			Role:        pulumi.String("roles/cloudkms.cryptoKeyEncrypterDecrypter"),
			Member:      pulumi.Sprintf("serviceAccount:service-%v@gcp-sa-secretmanager.iam.gserviceaccount.com", project.Number),
		})
		if err != nil {
			return err
		}
		_, err = secretmanager.NewRegionalSecret(ctx, "regional-secret-with-cmek", &secretmanager.RegionalSecretArgs{
			SecretId: pulumi.String("tf-reg-secret"),
			Location: pulumi.String("us-central1"),
			CustomerManagedEncryption: &secretmanager.RegionalSecretCustomerManagedEncryptionArgs{
				KmsKeyName: pulumi.String("kms-key"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			kms_secret_binding,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var project = Gcp.Organizations.GetProject.Invoke();

    var kms_secret_binding = new Gcp.Kms.CryptoKeyIAMMember("kms-secret-binding", new()
    {
        CryptoKeyId = "kms-key",
        Role = "roles/cloudkms.cryptoKeyEncrypterDecrypter",
        Member = $"serviceAccount:service-{project.Apply(getProjectResult => getProjectResult.Number)}@gcp-sa-secretmanager.iam.gserviceaccount.com",
    });

    var regional_secret_with_cmek = new Gcp.SecretManager.RegionalSecret("regional-secret-with-cmek", new()
    {
        SecretId = "tf-reg-secret",
        Location = "us-central1",
        CustomerManagedEncryption = new Gcp.SecretManager.Inputs.RegionalSecretCustomerManagedEncryptionArgs
        {
            KmsKeyName = "kms-key",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            kms_secret_binding,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.kms.CryptoKeyIAMMember;
import com.pulumi.gcp.kms.CryptoKeyIAMMemberArgs;
import com.pulumi.gcp.secretmanager.RegionalSecret;
import com.pulumi.gcp.secretmanager.RegionalSecretArgs;
import com.pulumi.gcp.secretmanager.inputs.RegionalSecretCustomerManagedEncryptionArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

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

    public static void stack(Context ctx) {
        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var kms_secret_binding = new CryptoKeyIAMMember("kms-secret-binding", CryptoKeyIAMMemberArgs.builder()
            .cryptoKeyId("kms-key")
            .role("roles/cloudkms.cryptoKeyEncrypterDecrypter")
            .member(String.format("serviceAccount:service-%s@gcp-sa-secretmanager.iam.gserviceaccount.com", project.number()))
            .build());

        var regional_secret_with_cmek = new RegionalSecret("regional-secret-with-cmek", RegionalSecretArgs.builder()
            .secretId("tf-reg-secret")
            .location("us-central1")
            .customerManagedEncryption(RegionalSecretCustomerManagedEncryptionArgs.builder()
                .kmsKeyName("kms-key")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(kms_secret_binding)
                .build());

    }
}
resources:
  kms-secret-binding:
    type: gcp:kms:CryptoKeyIAMMember
    properties:
      cryptoKeyId: kms-key
      role: roles/cloudkms.cryptoKeyEncrypterDecrypter
      member: serviceAccount:service-${project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com
  regional-secret-with-cmek:
    type: gcp:secretmanager:RegionalSecret
    properties:
      secretId: tf-reg-secret
      location: us-central1
      customerManagedEncryption:
        kmsKeyName: kms-key
    options:
      dependsOn:
        - ${["kms-secret-binding"]}
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The customerManagedEncryption block references a KMS key by name. Before creating the secret, you must grant the Secret Manager service account the cryptoKeyEncrypterDecrypter role on your KMS key. The dependsOn ensures the IAM binding exists before Secret Manager attempts encryption.

Schedule automatic rotation notifications

Applications that rotate credentials need notifications when it’s time to generate new versions.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const project = gcp.organizations.getProject({});
const topic = new gcp.pubsub.Topic("topic", {name: "tf-topic"});
const secretsManagerAccess = new gcp.pubsub.TopicIAMMember("secrets_manager_access", {
    topic: topic.name,
    role: "roles/pubsub.publisher",
    member: project.then(project => `serviceAccount:service-${project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com`),
});
const regional_secret_with_rotation = new gcp.secretmanager.RegionalSecret("regional-secret-with-rotation", {
    secretId: "tf-reg-secret",
    location: "us-central1",
    topics: [{
        name: topic.id,
    }],
    rotation: {
        rotationPeriod: "3600s",
        nextRotationTime: "2045-11-30T00:00:00Z",
    },
}, {
    dependsOn: [secretsManagerAccess],
});
import pulumi
import pulumi_gcp as gcp

project = gcp.organizations.get_project()
topic = gcp.pubsub.Topic("topic", name="tf-topic")
secrets_manager_access = gcp.pubsub.TopicIAMMember("secrets_manager_access",
    topic=topic.name,
    role="roles/pubsub.publisher",
    member=f"serviceAccount:service-{project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com")
regional_secret_with_rotation = gcp.secretmanager.RegionalSecret("regional-secret-with-rotation",
    secret_id="tf-reg-secret",
    location="us-central1",
    topics=[{
        "name": topic.id,
    }],
    rotation={
        "rotation_period": "3600s",
        "next_rotation_time": "2045-11-30T00:00:00Z",
    },
    opts = pulumi.ResourceOptions(depends_on=[secrets_manager_access]))
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		topic, err := pubsub.NewTopic(ctx, "topic", &pubsub.TopicArgs{
			Name: pulumi.String("tf-topic"),
		})
		if err != nil {
			return err
		}
		secretsManagerAccess, err := pubsub.NewTopicIAMMember(ctx, "secrets_manager_access", &pubsub.TopicIAMMemberArgs{
			Topic:  topic.Name,
			Role:   pulumi.String("roles/pubsub.publisher"),
			Member: pulumi.Sprintf("serviceAccount:service-%v@gcp-sa-secretmanager.iam.gserviceaccount.com", project.Number),
		})
		if err != nil {
			return err
		}
		_, err = secretmanager.NewRegionalSecret(ctx, "regional-secret-with-rotation", &secretmanager.RegionalSecretArgs{
			SecretId: pulumi.String("tf-reg-secret"),
			Location: pulumi.String("us-central1"),
			Topics: secretmanager.RegionalSecretTopicArray{
				&secretmanager.RegionalSecretTopicArgs{
					Name: topic.ID(),
				},
			},
			Rotation: &secretmanager.RegionalSecretRotationArgs{
				RotationPeriod:   pulumi.String("3600s"),
				NextRotationTime: pulumi.String("2045-11-30T00:00:00Z"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			secretsManagerAccess,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var project = Gcp.Organizations.GetProject.Invoke();

    var topic = new Gcp.PubSub.Topic("topic", new()
    {
        Name = "tf-topic",
    });

    var secretsManagerAccess = new Gcp.PubSub.TopicIAMMember("secrets_manager_access", new()
    {
        Topic = topic.Name,
        Role = "roles/pubsub.publisher",
        Member = $"serviceAccount:service-{project.Apply(getProjectResult => getProjectResult.Number)}@gcp-sa-secretmanager.iam.gserviceaccount.com",
    });

    var regional_secret_with_rotation = new Gcp.SecretManager.RegionalSecret("regional-secret-with-rotation", new()
    {
        SecretId = "tf-reg-secret",
        Location = "us-central1",
        Topics = new[]
        {
            new Gcp.SecretManager.Inputs.RegionalSecretTopicArgs
            {
                Name = topic.Id,
            },
        },
        Rotation = new Gcp.SecretManager.Inputs.RegionalSecretRotationArgs
        {
            RotationPeriod = "3600s",
            NextRotationTime = "2045-11-30T00:00:00Z",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            secretsManagerAccess,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.pubsub.TopicIAMMember;
import com.pulumi.gcp.pubsub.TopicIAMMemberArgs;
import com.pulumi.gcp.secretmanager.RegionalSecret;
import com.pulumi.gcp.secretmanager.RegionalSecretArgs;
import com.pulumi.gcp.secretmanager.inputs.RegionalSecretTopicArgs;
import com.pulumi.gcp.secretmanager.inputs.RegionalSecretRotationArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

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

    public static void stack(Context ctx) {
        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var topic = new Topic("topic", TopicArgs.builder()
            .name("tf-topic")
            .build());

        var secretsManagerAccess = new TopicIAMMember("secretsManagerAccess", TopicIAMMemberArgs.builder()
            .topic(topic.name())
            .role("roles/pubsub.publisher")
            .member(String.format("serviceAccount:service-%s@gcp-sa-secretmanager.iam.gserviceaccount.com", project.number()))
            .build());

        var regional_secret_with_rotation = new RegionalSecret("regional-secret-with-rotation", RegionalSecretArgs.builder()
            .secretId("tf-reg-secret")
            .location("us-central1")
            .topics(RegionalSecretTopicArgs.builder()
                .name(topic.id())
                .build())
            .rotation(RegionalSecretRotationArgs.builder()
                .rotationPeriod("3600s")
                .nextRotationTime("2045-11-30T00:00:00Z")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(secretsManagerAccess)
                .build());

    }
}
resources:
  topic:
    type: gcp:pubsub:Topic
    properties:
      name: tf-topic
  secretsManagerAccess:
    type: gcp:pubsub:TopicIAMMember
    name: secrets_manager_access
    properties:
      topic: ${topic.name}
      role: roles/pubsub.publisher
      member: serviceAccount:service-${project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com
  regional-secret-with-rotation:
    type: gcp:secretmanager:RegionalSecret
    properties:
      secretId: tf-reg-secret
      location: us-central1
      topics:
        - name: ${topic.id}
      rotation:
        rotationPeriod: 3600s
        nextRotationTime: 2045-11-30T00:00:00Z
    options:
      dependsOn:
        - ${secretsManagerAccess}
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The rotation block defines when Secret Manager sends Pub/Sub notifications: rotationPeriod sets the interval (e.g., every hour), nextRotationTime sets the first notification. The topics array lists Pub/Sub topics that receive these notifications. Your application subscribes to these topics and generates new secret versions in response.

Set automatic expiration with TTL

Temporary credentials benefit from automatic cleanup after a fixed duration.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const regional_secret_with_ttl = new gcp.secretmanager.RegionalSecret("regional-secret-with-ttl", {
    secretId: "tf-reg-secret",
    location: "us-central1",
    labels: {
        label: "my-label",
    },
    annotations: {
        key1: "value1",
        key2: "value2",
        key3: "value3",
    },
    ttl: "36000s",
});
import pulumi
import pulumi_gcp as gcp

regional_secret_with_ttl = gcp.secretmanager.RegionalSecret("regional-secret-with-ttl",
    secret_id="tf-reg-secret",
    location="us-central1",
    labels={
        "label": "my-label",
    },
    annotations={
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
    },
    ttl="36000s")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := secretmanager.NewRegionalSecret(ctx, "regional-secret-with-ttl", &secretmanager.RegionalSecretArgs{
			SecretId: pulumi.String("tf-reg-secret"),
			Location: pulumi.String("us-central1"),
			Labels: pulumi.StringMap{
				"label": pulumi.String("my-label"),
			},
			Annotations: pulumi.StringMap{
				"key1": pulumi.String("value1"),
				"key2": pulumi.String("value2"),
				"key3": pulumi.String("value3"),
			},
			Ttl: pulumi.String("36000s"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var regional_secret_with_ttl = new Gcp.SecretManager.RegionalSecret("regional-secret-with-ttl", new()
    {
        SecretId = "tf-reg-secret",
        Location = "us-central1",
        Labels = 
        {
            { "label", "my-label" },
        },
        Annotations = 
        {
            { "key1", "value1" },
            { "key2", "value2" },
            { "key3", "value3" },
        },
        Ttl = "36000s",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.RegionalSecret;
import com.pulumi.gcp.secretmanager.RegionalSecretArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

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

    public static void stack(Context ctx) {
        var regional_secret_with_ttl = new RegionalSecret("regional-secret-with-ttl", RegionalSecretArgs.builder()
            .secretId("tf-reg-secret")
            .location("us-central1")
            .labels(Map.of("label", "my-label"))
            .annotations(Map.ofEntries(
                Map.entry("key1", "value1"),
                Map.entry("key2", "value2"),
                Map.entry("key3", "value3")
            ))
            .ttl("36000s")
            .build());

    }
}
resources:
  regional-secret-with-ttl:
    type: gcp:secretmanager:RegionalSecret
    properties:
      secretId: tf-reg-secret
      location: us-central1
      labels:
        label: my-label
      annotations:
        key1: value1
        key2: value2
        key3: value3
      ttl: 36000s

The ttl property sets a duration after which the secret expires and becomes inaccessible. Use this for short-lived credentials where you know the lifetime but not the exact end date. Only one of ttl or expireTime can be set.

Schedule expiration at a specific timestamp

Some secrets need to expire at a known future date.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const regional_secret_with_expire_time = new gcp.secretmanager.RegionalSecret("regional-secret-with-expire-time", {
    secretId: "tf-reg-secret",
    location: "us-central1",
    labels: {
        label: "my-label",
    },
    annotations: {
        key1: "value1",
        key2: "value2",
        key3: "value3",
    },
    expireTime: "2055-11-30T00:00:00Z",
});
import pulumi
import pulumi_gcp as gcp

regional_secret_with_expire_time = gcp.secretmanager.RegionalSecret("regional-secret-with-expire-time",
    secret_id="tf-reg-secret",
    location="us-central1",
    labels={
        "label": "my-label",
    },
    annotations={
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
    },
    expire_time="2055-11-30T00:00:00Z")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := secretmanager.NewRegionalSecret(ctx, "regional-secret-with-expire-time", &secretmanager.RegionalSecretArgs{
			SecretId: pulumi.String("tf-reg-secret"),
			Location: pulumi.String("us-central1"),
			Labels: pulumi.StringMap{
				"label": pulumi.String("my-label"),
			},
			Annotations: pulumi.StringMap{
				"key1": pulumi.String("value1"),
				"key2": pulumi.String("value2"),
				"key3": pulumi.String("value3"),
			},
			ExpireTime: pulumi.String("2055-11-30T00:00:00Z"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var regional_secret_with_expire_time = new Gcp.SecretManager.RegionalSecret("regional-secret-with-expire-time", new()
    {
        SecretId = "tf-reg-secret",
        Location = "us-central1",
        Labels = 
        {
            { "label", "my-label" },
        },
        Annotations = 
        {
            { "key1", "value1" },
            { "key2", "value2" },
            { "key3", "value3" },
        },
        ExpireTime = "2055-11-30T00:00:00Z",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.RegionalSecret;
import com.pulumi.gcp.secretmanager.RegionalSecretArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

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

    public static void stack(Context ctx) {
        var regional_secret_with_expire_time = new RegionalSecret("regional-secret-with-expire-time", RegionalSecretArgs.builder()
            .secretId("tf-reg-secret")
            .location("us-central1")
            .labels(Map.of("label", "my-label"))
            .annotations(Map.ofEntries(
                Map.entry("key1", "value1"),
                Map.entry("key2", "value2"),
                Map.entry("key3", "value3")
            ))
            .expireTime("2055-11-30T00:00:00Z")
            .build());

    }
}
resources:
  regional-secret-with-expire-time:
    type: gcp:secretmanager:RegionalSecret
    properties:
      secretId: tf-reg-secret
      location: us-central1
      labels:
        label: my-label
      annotations:
        key1: value1
        key2: value2
        key3: value3
      expireTime: 2055-11-30T00:00:00Z

The expireTime property sets an absolute timestamp in RFC3339 format. Use this when you know the exact expiration date, such as for certificates or time-bound access tokens. Only one of expireTime or ttl can be set.

Beyond these examples

These snippets focus on specific regional secret features: regional secret creation with metadata, customer-managed encryption, and rotation scheduling and lifecycle management. They’re intentionally minimal rather than full secrets management solutions.

The examples may reference pre-existing infrastructure such as KMS keys for customer-managed encryption, Pub/Sub topics for rotation notifications, and IAM bindings for the Secret Manager service account. They focus on configuring the secret container rather than provisioning the surrounding infrastructure.

To keep things focused, common secret patterns are omitted, including:

  • Secret version creation and data storage (requires RegionalSecretVersion resource)
  • Version aliases for stable references (versionAliases)
  • Version destruction delays (versionDestroyTtl)
  • IAM policies for secret access control

These omissions are intentional: the goal is to illustrate how each regional secret feature is wired, not provide drop-in secrets management modules. See the Regional Secret resource reference for all available configuration options.

Let's create GCP Regional Secrets

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Lifecycle
What's the difference between ttl and expireTime?
ttl sets a duration from creation (e.g., “3600s”), while expireTime sets a specific timestamp (e.g., “2055-11-30T00:00:00Z”). You can only use one, not both.
What properties can't I change after creating a regional secret?
The location, secretId, project, and tags properties are immutable. Changing them requires replacing the resource.
How do I prevent accidental deletion of a regional secret?
Set deletionProtection to true. This prevents Pulumi from destroying the secret during updates or destroy operations.
What's the minimum value for versionDestroyTtl?
The minimum is 24 hours (86400 seconds). Use a value like “86400s” or higher.
Encryption & Security
How do I use customer-managed encryption (CMEK) with a regional secret?
Configure customerManagedEncryption.kmsKeyName with your KMS key. First, create a gcp.kms.CryptoKeyIAMMember granting roles/cloudkms.cryptoKeyEncrypterDecrypter to the Secret Manager service account (service-PROJECT_NUMBER@gcp-sa-secretmanager.iam.gserviceaccount.com), then use dependsOn to ensure the IAM binding is created before the secret.
Rotation & Notifications
How do I set up automatic rotation for a regional secret?
Configure rotation with rotationPeriod and nextRotationTime, and add at least one Pub/Sub topic to topics. The Secret Manager service account needs roles/pubsub.publisher on the topic. Use dependsOn to ensure IAM permissions are set before creating the secret.
How many Pub/Sub topics can I configure for notifications?
You can configure up to 10 Pub/Sub topics in the topics array.
Labels & Metadata
Why don't annotations and labels show all values in my configuration?
The annotations and labels fields are non-authoritative, meaning they only manage values you explicitly set in your configuration. To see all annotations and labels (including those set by other clients or services), use effectiveAnnotations and effectiveLabels.
What are the constraints for label keys and values?
Label keys must match the regex [\p{Ll}\p{Lo}][\p{Ll}\p{Lo}\p{N}_-]{0,62} (1-63 chars, start with lowercase letter). Label values must match [\p{Ll}\p{Lo}\p{N}_-]{0,63} (0-63 chars). Maximum 64 labels per secret.
Version Management
What happens when I destroy a secret version with versionDestroyTtl set?
The version enters a disabled state instead of being immediately destroyed. Actual destruction occurs after the TTL expires (minimum 24 hours).
What are the rules for version aliases?
Version aliases must be 1-63 characters, start with a letter, and contain only letters, numbers, hyphens, and underscores. They cannot be “latest” or “NEW”. Maximum 50 aliases per secret.
Can I import an existing regional secret into Pulumi?
Yes, use pulumi import with one of these formats: projects/PROJECT/locations/LOCATION/secrets/SECRET_ID, PROJECT/LOCATION/SECRET_ID, or LOCATION/SECRET_ID.

Using a different cloud?

Explore security guides for other cloud providers: