Configure GCP Cloud Logging Buckets

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

GCP automatically creates _Default and _Required buckets for each project; these cannot be deleted. This resource acquires and configures 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 sinks, monitoring, and compliance policies.

Configure retention for the default bucket

GCP automatically creates _Default and _Required buckets for each project. Teams adjust retention periods on these buckets to meet compliance requirements or control storage costs.

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 “_Default” references the automatically-created bucket. The retentionDays property sets how long logs persist before automatic deletion; the minimum is 1 day. Setting location to “global” stores logs across regions.

Create a custom bucket with retention policy

Beyond automatic buckets, teams create custom buckets to organize logs by application, environment, or compliance tier.

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 bucketId except “_Default” or “_Required”. Each bucket can have its own retention policy, allowing you to keep audit logs longer than application logs.

Enable Log Analytics for SQL queries

Log Analytics allows teams to query logs using SQL in the GCP 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

Setting enableAnalytics to true activates SQL-based querying in the Log Analytics page. This cannot be disabled once enabled. Logs in analytics-enabled buckets support filtering, aggregation, and joins using standard SQL syntax.

Encrypt logs with customer-managed keys

Organizations with strict data sovereignty 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 (
	"fmt"

	"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 a KMS key for encrypting new log entries. The logging service account needs the cryptoKeyEncrypterDecrypter role on the key, granted via CryptoKeyIAMBinding. The dependsOn ensures IAM bindings exist before bucket creation. Once CMEK is enabled, it cannot be disabled, though you can change the key.

Index fields for faster query performance

When Log Analytics is enabled, indexing specific JSON fields accelerates queries that filter on those fields.

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 fields to index. Each entry specifies a fieldPath (dot-notation for nested JSON) and a type (INDEX_TYPE_STRING, INDEX_TYPE_INTEGER). Indexing speeds up WHERE clauses on high-cardinality fields like request status codes or user IDs.

Beyond these examples

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

The examples may reference pre-existing infrastructure such as GCP projects with logging enabled, and KMS keyrings and crypto keys for CMEK configurations. They focus on configuring the bucket rather than provisioning log sinks or monitoring.

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

  • Bucket locking (locked property)
  • Bucket descriptions (description property)
  • Log sink routing to buckets
  • Lifecycle state monitoring

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

Lifecycle & Deletion
What happens when I delete a ProjectBucketConfig resource?
Deleting the resource removes it from your Pulumi state but leaves the actual logging bucket unchanged in GCP. Logging buckets are automatically created by GCP and cannot be deleted through this resource.
What's the difference between _Default buckets and custom buckets?
GCP automatically creates _Default and _Required buckets for each project. You can either configure these existing buckets by using their names as bucketId, or create new custom buckets with your own bucketId.
Immutability & Configuration Limits
What properties can't I change after creating the bucket?
The bucketId, location, and project properties are immutable after creation. You’ll need to create a new bucket if you need to change any of these values.
Can I disable Log Analytics or CMEK encryption after enabling them?
No. Both enableAnalytics and cmekSettings are one-way configurations that cannot be disabled once enabled. However, you can change the KMS key used for CMEK encryption.
Encryption & Security
How do I encrypt logs with my own KMS key?
Configure cmekSettings with your KMS key ID. You must also grant the logging service account the roles/cloudkms.cryptoKeyEncrypterDecrypter role on your key. Use dependsOn to ensure the IAM binding is created before the bucket.
Retention & Locking
What's the default retention period for logs?
If you set retentionDays to zero at bucket creation, it defaults to 30 days. The minimum retention period is 1 day.
What does locking a bucket do?
Setting locked to true makes the retention period immutable—it can’t be changed afterward. Locked buckets can only be deleted if they’re empty.
Analytics & Performance
How do I enable SQL queries on my logs?
Set enableAnalytics to true. This allows you to query logs in the Log Analytics page using SQL. Note that this cannot be disabled once enabled.
How do I improve query performance with indexes?
Use indexConfigs to specify field paths and index types. For example, you can index jsonPayload.request.status with type INDEX_TYPE_STRING to speed up queries on that field.

Using a different cloud?

Explore monitoring guides for other cloud providers: