Configure GCP Cloud Logging Buckets

The gcp:logging/projectBucketConfig:ProjectBucketConfig resource, part of the Pulumi GCP provider, configures project-level logging buckets: their retention periods, encryption settings, analytics capabilities, and field indexing. This guide focuses on five capabilities: retention policy configuration, custom bucket creation, Log Analytics enablement, customer-managed encryption, and field indexing.

Google Cloud automatically creates _Default and _Required buckets for each project. This resource acquires and configures those existing buckets or creates custom ones. CMEK configurations require KMS keys and IAM bindings. The examples are intentionally small. Combine them with your own log routing and monitoring infrastructure.

Configure retention for the default bucket

Google Cloud automatically creates _Default and _Required buckets for each project. Teams often adjust retention periods to meet compliance or cost requirements.

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

const _default = new gcp.organizations.Project("default", {
    projectId: "your-project-id",
    name: "your-project-id",
    orgId: "123456789",
});
const basic = new gcp.logging.ProjectBucketConfig("basic", {
    project: _default.projectId,
    location: "global",
    retentionDays: 30,
    bucketId: "_Default",
});
import pulumi
import pulumi_gcp as gcp

default = gcp.organizations.Project("default",
    project_id="your-project-id",
    name="your-project-id",
    org_id="123456789")
basic = gcp.logging.ProjectBucketConfig("basic",
    project=default.project_id,
    location="global",
    retention_days=30,
    bucket_id="_Default")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := organizations.NewProject(ctx, "default", &organizations.ProjectArgs{
			ProjectId: pulumi.String("your-project-id"),
			Name:      pulumi.String("your-project-id"),
			OrgId:     pulumi.String("123456789"),
		})
		if err != nil {
			return err
		}
		_, err = logging.NewProjectBucketConfig(ctx, "basic", &logging.ProjectBucketConfigArgs{
			Project:       _default.ProjectId,
			Location:      pulumi.String("global"),
			RetentionDays: pulumi.Int(30),
			BucketId:      pulumi.String("_Default"),
		})
		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 @default = new Gcp.Organizations.Project("default", new()
    {
        ProjectId = "your-project-id",
        Name = "your-project-id",
        OrgId = "123456789",
    });

    var basic = new Gcp.Logging.ProjectBucketConfig("basic", new()
    {
        Project = @default.ProjectId,
        Location = "global",
        RetentionDays = 30,
        BucketId = "_Default",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import com.pulumi.gcp.logging.ProjectBucketConfig;
import com.pulumi.gcp.logging.ProjectBucketConfigArgs;
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 default_ = new Project("default", ProjectArgs.builder()
            .projectId("your-project-id")
            .name("your-project-id")
            .orgId("123456789")
            .build());

        var basic = new ProjectBucketConfig("basic", ProjectBucketConfigArgs.builder()
            .project(default_.projectId())
            .location("global")
            .retentionDays(30)
            .bucketId("_Default")
            .build());

    }
}
resources:
  default:
    type: gcp:organizations:Project
    properties:
      projectId: your-project-id
      name: your-project-id
      orgId: '123456789'
  basic:
    type: gcp:logging:ProjectBucketConfig
    properties:
      project: ${default.projectId}
      location: global
      retentionDays: 30
      bucketId: _Default

The bucketId property references the automatically-created _Default bucket. The retentionDays property controls how long logs are stored before automatic deletion; the minimum is 1 day, and zero defaults to 30 days. The location property determines where logs are physically stored.

Create a custom bucket with retention policy

Beyond automatic buckets, teams create custom buckets to organize logs by application, environment, or retention needs.

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

const basic = new gcp.logging.ProjectBucketConfig("basic", {
    project: "project_id",
    location: "global",
    retentionDays: 30,
    bucketId: "custom-bucket",
});
import pulumi
import pulumi_gcp as gcp

basic = gcp.logging.ProjectBucketConfig("basic",
    project="project_id",
    location="global",
    retention_days=30,
    bucket_id="custom-bucket")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewProjectBucketConfig(ctx, "basic", &logging.ProjectBucketConfigArgs{
			Project:       pulumi.String("project_id"),
			Location:      pulumi.String("global"),
			RetentionDays: pulumi.Int(30),
			BucketId:      pulumi.String("custom-bucket"),
		})
		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 basic = new Gcp.Logging.ProjectBucketConfig("basic", new()
    {
        Project = "project_id",
        Location = "global",
        RetentionDays = 30,
        BucketId = "custom-bucket",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.ProjectBucketConfig;
import com.pulumi.gcp.logging.ProjectBucketConfigArgs;
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 basic = new ProjectBucketConfig("basic", ProjectBucketConfigArgs.builder()
            .project("project_id")
            .location("global")
            .retentionDays(30)
            .bucketId("custom-bucket")
            .build());

    }
}
resources:
  basic:
    type: gcp:logging:ProjectBucketConfig
    properties:
      project: project_id
      location: global
      retentionDays: 30
      bucketId: custom-bucket

Custom buckets use any name except _Default or _Required. The bucketId becomes part of the bucket’s resource path. Unlike automatic buckets, custom buckets can be deleted when empty.

Enable Log Analytics for SQL queries

Log Analytics allows teams to query logs using SQL in the Google Cloud Console, enabling complex analysis without exporting to BigQuery.

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

const analytics_enabled_bucket = new gcp.logging.ProjectBucketConfig("analytics-enabled-bucket", {
    project: "project_id",
    location: "global",
    retentionDays: 30,
    enableAnalytics: true,
    bucketId: "custom-bucket",
});
import pulumi
import pulumi_gcp as gcp

analytics_enabled_bucket = gcp.logging.ProjectBucketConfig("analytics-enabled-bucket",
    project="project_id",
    location="global",
    retention_days=30,
    enable_analytics=True,
    bucket_id="custom-bucket")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewProjectBucketConfig(ctx, "analytics-enabled-bucket", &logging.ProjectBucketConfigArgs{
			Project:         pulumi.String("project_id"),
			Location:        pulumi.String("global"),
			RetentionDays:   pulumi.Int(30),
			EnableAnalytics: pulumi.Bool(true),
			BucketId:        pulumi.String("custom-bucket"),
		})
		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 analytics_enabled_bucket = new Gcp.Logging.ProjectBucketConfig("analytics-enabled-bucket", new()
    {
        Project = "project_id",
        Location = "global",
        RetentionDays = 30,
        EnableAnalytics = true,
        BucketId = "custom-bucket",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.ProjectBucketConfig;
import com.pulumi.gcp.logging.ProjectBucketConfigArgs;
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 analytics_enabled_bucket = new ProjectBucketConfig("analytics-enabled-bucket", ProjectBucketConfigArgs.builder()
            .project("project_id")
            .location("global")
            .retentionDays(30)
            .enableAnalytics(true)
            .bucketId("custom-bucket")
            .build());

    }
}
resources:
  analytics-enabled-bucket:
    type: gcp:logging:ProjectBucketConfig
    properties:
      project: project_id
      location: global
      retentionDays: 30
      enableAnalytics: true
      bucketId: custom-bucket

The enableAnalytics property activates SQL query capabilities in the Log Analytics page. Once enabled, this cannot be disabled. This extends the custom bucket pattern with analytics capability.

Encrypt logs with customer-managed keys

Organizations with strict security requirements encrypt logs using their own KMS keys rather than Google-managed encryption.

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

const cmekSettings = gcp.logging.getProjectCmekSettings({
    project: "project_id",
});
const keyring = new gcp.kms.KeyRing("keyring", {
    name: "keyring-example",
    location: "us-central1",
});
const key = new gcp.kms.CryptoKey("key", {
    name: "crypto-key-example",
    keyRing: keyring.id,
    rotationPeriod: "7776000s",
});
const cryptoKeyBinding = new gcp.kms.CryptoKeyIAMBinding("crypto_key_binding", {
    cryptoKeyId: key.id,
    role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
    members: [cmekSettings.then(cmekSettings => `serviceAccount:${cmekSettings.serviceAccountId}`)],
});
const example_project_bucket_cmek_settings = new gcp.logging.ProjectBucketConfig("example-project-bucket-cmek-settings", {
    project: "project_id",
    location: "us-central1",
    retentionDays: 30,
    bucketId: "custom-bucket",
    cmekSettings: {
        kmsKeyName: key.id,
    },
}, {
    dependsOn: [cryptoKeyBinding],
});
import pulumi
import pulumi_gcp as gcp

cmek_settings = gcp.logging.get_project_cmek_settings(project="project_id")
keyring = gcp.kms.KeyRing("keyring",
    name="keyring-example",
    location="us-central1")
key = gcp.kms.CryptoKey("key",
    name="crypto-key-example",
    key_ring=keyring.id,
    rotation_period="7776000s")
crypto_key_binding = gcp.kms.CryptoKeyIAMBinding("crypto_key_binding",
    crypto_key_id=key.id,
    role="roles/cloudkms.cryptoKeyEncrypterDecrypter",
    members=[f"serviceAccount:{cmek_settings.service_account_id}"])
example_project_bucket_cmek_settings = gcp.logging.ProjectBucketConfig("example-project-bucket-cmek-settings",
    project="project_id",
    location="us-central1",
    retention_days=30,
    bucket_id="custom-bucket",
    cmek_settings={
        "kms_key_name": key.id,
    },
    opts = pulumi.ResourceOptions(depends_on=[crypto_key_binding]))
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		cmekSettings, err := logging.GetProjectCmekSettings(ctx, &logging.GetProjectCmekSettingsArgs{
			Project: "project_id",
		}, nil)
		if err != nil {
			return err
		}
		keyring, err := kms.NewKeyRing(ctx, "keyring", &kms.KeyRingArgs{
			Name:     pulumi.String("keyring-example"),
			Location: pulumi.String("us-central1"),
		})
		if err != nil {
			return err
		}
		key, err := kms.NewCryptoKey(ctx, "key", &kms.CryptoKeyArgs{
			Name:           pulumi.String("crypto-key-example"),
			KeyRing:        keyring.ID(),
			RotationPeriod: pulumi.String("7776000s"),
		})
		if err != nil {
			return err
		}
		cryptoKeyBinding, err := kms.NewCryptoKeyIAMBinding(ctx, "crypto_key_binding", &kms.CryptoKeyIAMBindingArgs{
			CryptoKeyId: key.ID(),
			Role:        pulumi.String("roles/cloudkms.cryptoKeyEncrypterDecrypter"),
			Members: pulumi.StringArray{
				pulumi.Sprintf("serviceAccount:%v", cmekSettings.ServiceAccountId),
			},
		})
		if err != nil {
			return err
		}
		_, err = logging.NewProjectBucketConfig(ctx, "example-project-bucket-cmek-settings", &logging.ProjectBucketConfigArgs{
			Project:       pulumi.String("project_id"),
			Location:      pulumi.String("us-central1"),
			RetentionDays: pulumi.Int(30),
			BucketId:      pulumi.String("custom-bucket"),
			CmekSettings: &logging.ProjectBucketConfigCmekSettingsArgs{
				KmsKeyName: key.ID(),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			cryptoKeyBinding,
		}))
		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 cmekSettings = Gcp.Logging.GetProjectCmekSettings.Invoke(new()
    {
        Project = "project_id",
    });

    var keyring = new Gcp.Kms.KeyRing("keyring", new()
    {
        Name = "keyring-example",
        Location = "us-central1",
    });

    var key = new Gcp.Kms.CryptoKey("key", new()
    {
        Name = "crypto-key-example",
        KeyRing = keyring.Id,
        RotationPeriod = "7776000s",
    });

    var cryptoKeyBinding = new Gcp.Kms.CryptoKeyIAMBinding("crypto_key_binding", new()
    {
        CryptoKeyId = key.Id,
        Role = "roles/cloudkms.cryptoKeyEncrypterDecrypter",
        Members = new[]
        {
            $"serviceAccount:{cmekSettings.Apply(getProjectCmekSettingsResult => getProjectCmekSettingsResult.ServiceAccountId)}",
        },
    });

    var example_project_bucket_cmek_settings = new Gcp.Logging.ProjectBucketConfig("example-project-bucket-cmek-settings", new()
    {
        Project = "project_id",
        Location = "us-central1",
        RetentionDays = 30,
        BucketId = "custom-bucket",
        CmekSettings = new Gcp.Logging.Inputs.ProjectBucketConfigCmekSettingsArgs
        {
            KmsKeyName = key.Id,
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            cryptoKeyBinding,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.LoggingFunctions;
import com.pulumi.gcp.logging.inputs.GetProjectCmekSettingsArgs;
import com.pulumi.gcp.kms.KeyRing;
import com.pulumi.gcp.kms.KeyRingArgs;
import com.pulumi.gcp.kms.CryptoKey;
import com.pulumi.gcp.kms.CryptoKeyArgs;
import com.pulumi.gcp.kms.CryptoKeyIAMBinding;
import com.pulumi.gcp.kms.CryptoKeyIAMBindingArgs;
import com.pulumi.gcp.logging.ProjectBucketConfig;
import com.pulumi.gcp.logging.ProjectBucketConfigArgs;
import com.pulumi.gcp.logging.inputs.ProjectBucketConfigCmekSettingsArgs;
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 cmekSettings = LoggingFunctions.getProjectCmekSettings(GetProjectCmekSettingsArgs.builder()
            .project("project_id")
            .build());

        var keyring = new KeyRing("keyring", KeyRingArgs.builder()
            .name("keyring-example")
            .location("us-central1")
            .build());

        var key = new CryptoKey("key", CryptoKeyArgs.builder()
            .name("crypto-key-example")
            .keyRing(keyring.id())
            .rotationPeriod("7776000s")
            .build());

        var cryptoKeyBinding = new CryptoKeyIAMBinding("cryptoKeyBinding", CryptoKeyIAMBindingArgs.builder()
            .cryptoKeyId(key.id())
            .role("roles/cloudkms.cryptoKeyEncrypterDecrypter")
            .members(String.format("serviceAccount:%s", cmekSettings.serviceAccountId()))
            .build());

        var example_project_bucket_cmek_settings = new ProjectBucketConfig("example-project-bucket-cmek-settings", ProjectBucketConfigArgs.builder()
            .project("project_id")
            .location("us-central1")
            .retentionDays(30)
            .bucketId("custom-bucket")
            .cmekSettings(ProjectBucketConfigCmekSettingsArgs.builder()
                .kmsKeyName(key.id())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(cryptoKeyBinding)
                .build());

    }
}
resources:
  keyring:
    type: gcp:kms:KeyRing
    properties:
      name: keyring-example
      location: us-central1
  key:
    type: gcp:kms:CryptoKey
    properties:
      name: crypto-key-example
      keyRing: ${keyring.id}
      rotationPeriod: 7776000s
  cryptoKeyBinding:
    type: gcp:kms:CryptoKeyIAMBinding
    name: crypto_key_binding
    properties:
      cryptoKeyId: ${key.id}
      role: roles/cloudkms.cryptoKeyEncrypterDecrypter
      members:
        - serviceAccount:${cmekSettings.serviceAccountId}
  example-project-bucket-cmek-settings:
    type: gcp:logging:ProjectBucketConfig
    properties:
      project: project_id
      location: us-central1
      retentionDays: 30
      bucketId: custom-bucket
      cmekSettings:
        kmsKeyName: ${key.id}
    options:
      dependsOn:
        - ${cryptoKeyBinding}
variables:
  cmekSettings:
    fn::invoke:
      function: gcp:logging:getProjectCmekSettings
      arguments:
        project: project_id

The cmekSettings block specifies the KMS key for encryption. The logging service account needs the cryptoKeyEncrypterDecrypter role on the key, granted via CryptoKeyIAMBinding. Once CMEK is enabled, it cannot be disabled; only the key can be changed. The dependsOn ensures IAM bindings exist before bucket creation.

Index fields for faster query performance

When querying large log volumes, indexing specific JSON fields improves performance by allowing the system to skip irrelevant entries.

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

const example_project_bucket_index_configs = new gcp.logging.ProjectBucketConfig("example-project-bucket-index-configs", {
    project: "project_id",
    location: "global",
    retentionDays: 30,
    bucketId: "custom-bucket",
    indexConfigs: [{
        fieldPath: "jsonPayload.request.status",
        type: "INDEX_TYPE_STRING",
    }],
});
import pulumi
import pulumi_gcp as gcp

example_project_bucket_index_configs = gcp.logging.ProjectBucketConfig("example-project-bucket-index-configs",
    project="project_id",
    location="global",
    retention_days=30,
    bucket_id="custom-bucket",
    index_configs=[{
        "field_path": "jsonPayload.request.status",
        "type": "INDEX_TYPE_STRING",
    }])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewProjectBucketConfig(ctx, "example-project-bucket-index-configs", &logging.ProjectBucketConfigArgs{
			Project:       pulumi.String("project_id"),
			Location:      pulumi.String("global"),
			RetentionDays: pulumi.Int(30),
			BucketId:      pulumi.String("custom-bucket"),
			IndexConfigs: logging.ProjectBucketConfigIndexConfigArray{
				&logging.ProjectBucketConfigIndexConfigArgs{
					FieldPath: pulumi.String("jsonPayload.request.status"),
					Type:      pulumi.String("INDEX_TYPE_STRING"),
				},
			},
		})
		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 example_project_bucket_index_configs = new Gcp.Logging.ProjectBucketConfig("example-project-bucket-index-configs", new()
    {
        Project = "project_id",
        Location = "global",
        RetentionDays = 30,
        BucketId = "custom-bucket",
        IndexConfigs = new[]
        {
            new Gcp.Logging.Inputs.ProjectBucketConfigIndexConfigArgs
            {
                FieldPath = "jsonPayload.request.status",
                Type = "INDEX_TYPE_STRING",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.ProjectBucketConfig;
import com.pulumi.gcp.logging.ProjectBucketConfigArgs;
import com.pulumi.gcp.logging.inputs.ProjectBucketConfigIndexConfigArgs;
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 example_project_bucket_index_configs = new ProjectBucketConfig("example-project-bucket-index-configs", ProjectBucketConfigArgs.builder()
            .project("project_id")
            .location("global")
            .retentionDays(30)
            .bucketId("custom-bucket")
            .indexConfigs(ProjectBucketConfigIndexConfigArgs.builder()
                .fieldPath("jsonPayload.request.status")
                .type("INDEX_TYPE_STRING")
                .build())
            .build());

    }
}
resources:
  example-project-bucket-index-configs:
    type: gcp:logging:ProjectBucketConfig
    properties:
      project: project_id
      location: global
      retentionDays: 30
      bucketId: custom-bucket
      indexConfigs:
        - fieldPath: jsonPayload.request.status
          type: INDEX_TYPE_STRING

The indexConfigs array defines which fields to index. The fieldPath property specifies the JSON path (e.g., jsonPayload.request.status), and type indicates the field’s data type. Indexing works best with fields that appear frequently in queries.

Beyond these examples

These snippets focus on specific bucket-level features: retention policies and custom bucket creation, Log Analytics and field indexing, and customer-managed encryption keys. They’re intentionally minimal rather than full logging solutions.

The examples may reference pre-existing infrastructure such as Google Cloud projects, KMS keyrings and crypto keys for CMEK, and IAM permissions for the logging service account. They focus on configuring the bucket rather than provisioning the surrounding infrastructure.

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

  • Bucket locking (locked property)
  • Bucket descriptions (description property)
  • Log sinks and routing configuration
  • Multiple index configurations per bucket

These omissions are intentional: the goal is to illustrate how each bucket feature is wired, not provide drop-in logging modules. See the ProjectBucketConfig resource reference for all available configuration options.

Let's configure GCP Cloud Logging Buckets

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Bucket Lifecycle & Deletion
What happens when I delete a logging bucket?
Deleting this resource only removes it from your Pulumi state; the actual logging bucket remains in GCP. Logging buckets cannot be deleted through the API.
What are the automatically created buckets?
GCP automatically creates _Default and _Required buckets for each project. These buckets already exist and cannot be deleted.
How do I update an existing auto-created bucket like _Default?
Create a ProjectBucketConfig resource with bucketId set to _Default. Pulumi will acquire and update the existing bucket rather than creating a new one.
Encryption & CMEK
How do I encrypt logs with my own KMS key?
Configure cmekSettings with kmsKeyName pointing to your KMS key. You must grant the logging service account the roles/cloudkms.cryptoKeyEncrypterDecrypter role and use dependsOn to ensure the IAM binding is created first.
Can I disable CMEK encryption after enabling it?
No, CMEK settings cannot be disabled once configured. However, you can change the KMS key by updating kmsKeyName.
Retention & Locking
What's the default retention period for logs?
If you set retentionDays to zero at bucket creation, logs are retained for 30 days by default. The minimum retention period is 1 day.
What happens when I lock a bucket?
Setting locked to true makes the retention period immutable. Locked buckets can only be deleted if they’re empty, and you cannot change the retention period afterward.
Log Analytics & Indexing
Can I disable Log Analytics after enabling it?
No, setting enableAnalytics to true is irreversible. Once enabled, you cannot disable Log Analytics for that bucket.
What are index configs used for?
Index configs optimize query performance by indexing specific log fields. Configure indexConfigs with fieldPath and type to enable SQL queries on those fields in the Log Analytics page.
Configuration Basics
What properties are immutable after bucket creation?
The bucketId, location, and project properties cannot be changed after creation. Modifying these requires recreating the bucket.
Can I create a custom bucket ID instead of using _Default?
Yes, set bucketId to any custom name (like custom-bucket). Custom buckets follow the same lifecycle rules as auto-created buckets.
What's the difference between global and regional bucket locations?
The location property determines where logs are stored. Use global for multi-region storage or specify a region like us-central1 for regional storage (required for CMEK).

Using a different cloud?

Explore monitoring guides for other cloud providers: