Pulumi Best Practices - Google Cloud
This page lists all 35 policies in the Pulumi Best Practices pack for Google Cloud, as published in pulumi-best-practices-google-cloud version 1.1.1.
Policies by control
1. Least Privilege — Ensure all identities and services have only the minimum permissions required to perform their tasks.
2. Resource Encryption at Rest — Encrypt all stored data using approved encryption mechanisms to protect against unauthorized access.
- bucket-customer-managed-kms
- compute-instance-encrypted-attached-disk
- compute-instance-encrypted-boot-disk
- gke-secrets-encryption
3. Transport Layer Encryption — Require secure protocols (e.g., TLS) for all data in transit to prevent interception or tampering.
4. No Public Access — Prohibit direct public exposure of resources unless explicitly approved and required.
5. Tagging — Enforce standardized resource tags for ownership, environment, and compliance tracking.
6. Enforce Logging — Enable and retain audit logs for all security-relevant actions and events.
7. High Availability — Deploy resources in redundant, fault-tolerant configurations to ensure service continuity.
8. Require DLQ — Ensure all asynchronous messaging systems are configured with a dead-letter queue to handle failures.
9. Resource Availability — Define and enforce timeouts, quotas, and capacity limits to prevent resource exhaustion.
11. Networking — Only allow required inbound and outbound traffic through network security groups, firewalls, or ACLs.
12. Documentation — Maintain up-to-date documentation of architectures, configurations, policies, and procedures to ensure clarity, consistency, and auditability.
13. Data Backup and Recovery — Regularly back up critical data and systems, store backups securely, and test recovery procedures to ensure timely restoration after failures or disasters.
14. Key Management & Rotation — Manage encryption keys securely and enforce periodic key rotation to reduce the risk of compromise.
Policy details
bucket-access-logging
Severity: medium · Enforcement: advisory
Require Cloud Storage buckets to have access logging enabled for audit trails
- 6. Enforce Logging — Enable and retain audit logs for all security-relevant actions and events.
Remediation
Fix: Enable Access Logging
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "US",
logging: {
logBucket: "my-logging-bucket", // Specify the bucket for access logs
logObjectPrefix: "bucket-logs/", // Optional prefix for log objects
},
// ... other config
});
bucket-customer-managed-kms
Severity: high · Enforcement: advisory
Require Cloud Storage buckets to use customer-managed Cloud KMS keys for encryption
- 2. Resource Encryption at Rest — Encrypt all stored data using approved encryption mechanisms to protect against unauthorized access.
Remediation
Fix: Configure Customer-Managed KMS Key
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "US",
encryption: {
defaultKmsKeyName: "projects/my-project/locations/us/keyRings/my-keyring/cryptoKeys/my-key", // Specify customer-managed KMS key
},
// ... other config
});
bucket-iam-least-privilege
Severity: high · Enforcement: advisory
Enforce least privilege access for Cloud Storage bucket IAM policies
- 1. Least Privilege — Ensure all identities and services have only the minimum permissions required to perform their tasks.
Remediation
Fix: Use Specific Least Privilege Roles
// Instead of overly broad roles like storage.admin or storage.objectAdmin
// Use specific roles based on actual needs:
// For read-only access
const viewerBinding = new gcp.storage.BucketIAMBinding("viewer-binding", {
bucket: bucket.name,
role: "roles/storage.objectViewer", // Read-only access to objects
members: ["user:viewer@example.com"],
});
// For write-only access
const creatorBinding = new gcp.storage.BucketIAMBinding("creator-binding", {
bucket: bucket.name,
role: "roles/storage.objectCreator", // Write-only access (no read)
members: ["serviceAccount:app@project.iam.gserviceaccount.com"],
});
// Avoid these overly broad roles:
// - roles/storage.admin
// - roles/storage.objectAdmin
// - roles/owner
// - roles/editor
bucket-multi-region
Severity: medium · Enforcement: advisory
Require Cloud Storage buckets to have multi-region replication for business continuity
- 7. High Availability — Deploy resources in redundant, fault-tolerant configurations to ensure service continuity.
Remediation
Fix: Configure Multi-Region Replication
// Option 1: Use multi-region location
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "US", // Multi-region location (US, EU, or ASIA)
// ... other config
});
// Option 2: Use dual-region location
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "NAM4", // Dual-region location
// ... other config
});
// Option 3: Use custom placement with multiple data locations
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "US",
customPlacementConfig: {
dataLocations: ["US-EAST1", "US-WEST1"], // Specify at least 2 regions
},
// ... other config
});
bucket-no-public-read
Severity: critical · Enforcement: advisory
Require Cloud Storage buckets to disallow public read access
- 4. No Public Access — Prohibit direct public exposure of resources unless explicitly approved and required.
Remediation
Fix: Enforce Public Access Prevention
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "US",
publicAccessPrevention: "enforced", // Prevent all public access
// ... other config
});
bucket-versioning
Severity: medium · Enforcement: advisory
Ensure Cloud Storage bucket versioning is enabled
- 13. Data Backup and Recovery — Regularly back up critical data and systems, store backups securely, and test recovery procedures to ensure timely restoration after failures or disasters.
Remediation
Enable versioning on Cloud Storage buckets by setting versioning.enabled to true to protect against accidental deletion or modification.
Example Pulumi TypeScript:
import * as gcp from "@pulumi/gcp";
const bucket = new gcp.storage.Bucket("versioned-bucket", {
location: "US",
versioning: {
enabled: true,
},
});
Example Pulumi TypeScript:
import * as gcp from "@pulumi/gcp";
const bucket = new gcp.storage.Bucket("my-bucket", {
location: "US",
versioning: {
enabled: true,
},
});
cloud-build-logging
Severity: medium · Enforcement: advisory
Require Cloud Build triggers to have secure logging configurations
- 6. Enforce Logging — Enable and retain audit logs for all security-relevant actions and events.
Remediation
Fix: Configure Secure Logging
const trigger = new cloudbuild.Trigger("my-trigger", {
build: {
logsBucket: "gs://my-logs-bucket/build-logs", // Configure centralized logs bucket
options: {
logging: "CLOUD_LOGGING_ONLY", // Use Cloud Logging for audit trails
},
// ... other config
},
// ... other config
});
cloud-cdn-origin-tls
Severity: high · Enforcement: advisory
Require Cloud CDN to use secure TLS to origin
- 3. Transport Layer Encryption — Require secure protocols (e.g., TLS) for all data in transit to prevent interception or tampering.
Remediation
Fix: Enable HTTPS Protocol for CDN Backend Service
const backendService = new gcp.compute.BackendService("cdn-backend", {
enableCdn: true,
protocol: "HTTPS", // Use HTTPS for secure communication to origin
// ... other config
});
cloud-tasks-retry-configuration
Severity: medium · Enforcement: advisory
Require Cloud Tasks queues to have proper retry configuration for business continuity
- 9. Resource Availability — Define and enforce timeouts, quotas, and capacity limits to prevent resource exhaustion.
Remediation
Fix: Configure Retry Policy with Max Attempts
const queue = new gcp.cloudtasks.Queue("my-queue", {
retryConfig: {
maxAttempts: 10, // Set reasonable max retry attempts
maxRetryDuration: "3600s", // Set max retry duration (1 hour)
minBackoff: "0.1s",
maxBackoff: "3600s",
},
// ... other config
});
cloudfunctions-documentation
Severity: low · Enforcement: advisory
Require Cloud Functions to have adequate documentation
- 12. Documentation — Maintain up-to-date documentation of architectures, configurations, policies, and procedures to ensure clarity, consistency, and auditability.
Remediation
Fix: Add Function Documentation
const func = new gcp.cloudfunctions.Function("my-function", {
description: "Processes customer orders from Pub/Sub and stores results in BigQuery", // Add descriptive documentation
labels: {
purpose: "order-processing", // Document function purpose
team: "backend-team", // Document ownership
// ... other labels
},
// ... other config
});
cloudsql-backup
Severity: medium · Enforcement: advisory
Require Cloud SQL instances to have backup retention enabled
- 13. Data Backup and Recovery — Regularly back up critical data and systems, store backups securely, and test recovery procedures to ensure timely restoration after failures or disasters.
Remediation
Fix: Enable Backup Configuration
const sqlInstance = new gcp.sql.DatabaseInstance("my-sql-instance", {
databaseVersion: "POSTGRES_15",
settings: {
backupConfiguration: {
enabled: true, // Enable backups
pointInTimeRecoveryEnabled: true, // Enable PITR for PostgreSQL/MySQL
},
// ... other config
},
});
cloudsql-high-availability
Severity: medium · Enforcement: advisory
Ensure Cloud SQL instances have regional high availability enabled
- 7. High Availability — Deploy resources in redundant, fault-tolerant configurations to ensure service continuity.
Remediation
Enable regional high availability for Cloud SQL instances by setting availabilityType to ‘REGIONAL’. This provides automatic failover and data replication across zones within a region.
Example Pulumi TypeScript:
import * as gcp from "@pulumi/gcp";
const instance = new gcp.sql.DatabaseInstance("my-db-instance", {
databaseVersion: "POSTGRES_15",
region: "us-central1",
settings: {
tier: "db-f1-micro",
availabilityType: "REGIONAL",
},
});
cloudsql-private-ip
Severity: critical · Enforcement: advisory
Restrict public access for Cloud SQL instances
- 4. No Public Access — Prohibit direct public exposure of resources unless explicitly approved and required.
Remediation
Disable public IP by setting ipv4Enabled to false and configure privateNetwork in ipConfiguration. Remove authorized networks that allow 0.0.0.0/0 access.
Example Pulumi TypeScript:
import * as gcp from "@pulumi/gcp";
const instance = new gcp.sql.DatabaseInstance("my-db-instance", {
databaseVersion: "POSTGRES_15",
region: "us-central1",
settings: {
tier: "db-f1-micro",
ipConfiguration: {
ipv4Enabled: false,
privateNetwork: "projects/my-project/global/networks/my-vpc",
},
},
});
cloudsql-ssl
Severity: high · Enforcement: advisory
Require Cloud SQL connections to use SSL/TLS encryption
- 3. Transport Layer Encryption — Require secure protocols (e.g., TLS) for all data in transit to prevent interception or tampering.
Remediation
Fix: Require SSL/TLS for All Connections
const sqlInstance = new gcp.sql.DatabaseInstance("my-sql-instance", {
databaseVersion: "POSTGRES_15",
settings: {
ipConfiguration: {
sslMode: "ENCRYPTED_ONLY", // Require SSL/TLS for all connections
// ... other config
},
},
});
compute-instance-encrypted-attached-disk
Severity: medium · Enforcement: advisory
Require Compute Engine instances to have encrypted attached disks
- 2. Resource Encryption at Rest — Encrypt all stored data using approved encryption mechanisms to protect against unauthorized access.
Remediation
Fix: Encrypt Attached Disks with CMEK
const instance = new compute.Instance("my-instance", {
attachedDisks: [{
source: myDisk.selfLink,
kmsKeySelfLink: "projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key", // Use CMEK for attached disk encryption
}],
// ... other config
});
compute-instance-encrypted-boot-disk
Severity: medium · Enforcement: advisory
Require Compute Engine instances to have encrypted boot disks
- 2. Resource Encryption at Rest — Encrypt all stored data using approved encryption mechanisms to protect against unauthorized access.
Remediation
Fix: Enable Boot Disk Encryption with CMEK
const instance = new compute.Instance("my-instance", {
bootDisk: {
initializeParams: {
image: "debian-cloud/debian-11",
},
kmsKeySelfLink: "projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key", // Use customer-managed encryption key
},
// ... other config
});
compute-no-public-ip
Severity: high · Enforcement: advisory
Ensure Compute Engine instances are not publicly accessible
- 4. No Public Access — Prohibit direct public exposure of resources unless explicitly approved and required.
Remediation
Remove accessConfigs from networkInterfaces to disable external IP assignment:
new gcp.compute.Instance("my-instance", {
networkInterfaces: [{
network: "my-vpc",
subnetwork: "my-subnet",
// accessConfigs: [], // Remove or set to empty array
}],
canIpForward: false,
});
Use Cloud NAT or load balancers for controlled external access.
environment-label
Severity: low · Enforcement: advisory
Require all labelable resources to have an environment label
- 5. Tagging — Enforce standardized resource tags for ownership, environment, and compliance tracking.
Remediation
Fix: Add Valid Environment Label
Add an environment label with a valid value (development, staging, or production) to your GCP resources:
const instance = new gcp.compute.Instance("my-instance", {
labels: {
environment: "production", // Required: valid environment label
// ... other labels
},
// ... other config
});
// For Cloud SQL instances, use userLabels within settings
const sqlInstance = new gcp.sql.DatabaseInstance("my-database", {
settings: {
userLabels: {
environment: "staging", // Required: valid environment label
},
// ... other settings
},
// ... other config
});
// For GKE clusters, use resourceLabels
const cluster = new gcp.container.Cluster("my-cluster", {
resourceLabels: {
environment: "development", // Required: valid environment label
},
// ... other config
});
firewall-no-http-ingress
Severity: critical · Enforcement: advisory
Require firewall rules to disallow inbound HTTP traffic from unauthorized sources
- 11. Networking — Only allow required inbound and outbound traffic through network security groups, firewalls, or ACLs.
Remediation
Fix: Use HTTPS Instead of HTTP
const firewallRule = new gcp.compute.Firewall("allow-https", {
network: network.id,
direction: "INGRESS",
allows: [{
protocol: "tcp",
ports: ["443"], // Use HTTPS (port 443) instead of HTTP (port 80)
}],
sourceRanges: ["0.0.0.0/0"],
// ... other config
});
firewall-no-public-ingress
Severity: critical · Enforcement: advisory
Require firewall rules to disallow public internet ingress unless specifically authorized
- 11. Networking — Only allow required inbound and outbound traffic through network security groups, firewalls, or ACLs.
Remediation
Fix: Use Private Network Ranges or Source Tags
const firewallRule = new gcp.compute.Firewall("allow-private-ingress", {
network: network.id,
direction: "INGRESS",
allows: [{
protocol: "tcp",
ports: ["443"],
}],
sourceRanges: ["10.0.0.0/8", "192.168.0.0/16"], // Use private ranges instead of 0.0.0.0/0
// Or use source tags for internal traffic control:
// sourceTags: ["web-tier"],
// ... other config
});
firewall-ssh-rdp
Severity: high · Enforcement: advisory
Enforce firewall rule restrictions for SSH and RDP access
- 11. Networking — Only allow required inbound and outbound traffic through network security groups, firewalls, or ACLs.
Remediation
Fix: Restrict SSH/RDP Access to Specific Sources
const firewallRule = new gcp.compute.Firewall("allow-ssh-restricted", {
network: network.id,
direction: "INGRESS",
allows: [{
protocol: "tcp",
ports: ["22"],
}],
sourceRanges: ["10.0.0.0/8", "192.168.1.0/24"], // Restrict to specific IP ranges, not 0.0.0.0/0
targetTags: ["ssh-access"],
// ... other config
});
firewall-strict
Severity: high · Enforcement: advisory
Enforce strict firewall rules with explicit allow/deny configuration
- 11. Networking — Only allow required inbound and outbound traffic through network security groups, firewalls, or ACLs.
Remediation
Fix: Configure Explicit and Restrictive Firewall Rules
const firewallRule = new gcp.compute.Firewall("strict-firewall-rule", {
network: network.id,
direction: "INGRESS", // Explicitly specify direction
allows: [{
protocol: "tcp",
ports: ["443"], // Specify explicit ports, not all ports
}],
sourceRanges: ["10.0.0.0/24"], // Use restrictive source ranges for sensitive ports
targetTags: ["web-servers"], // Specify explicit targets
// ... other config
});
gke-private-endpoints
Severity: high · Enforcement: advisory
Require GKE cluster API endpoints to be private
- 4. No Public Access — Prohibit direct public exposure of resources unless explicitly approved and required.
Remediation
Fix: Enable Private Cluster Configuration
const cluster = new gcp.container.Cluster("my-cluster", {
privateClusterConfig: {
enablePrivateEndpoint: true, // Restrict control plane access to private networks
enablePrivateNodes: true, // Assign only private IPs to cluster nodes
masterIpv4CidrBlock: "172.16.0.0/28", // CIDR block for the master
},
// ... other config
});
gke-secrets-encryption
Severity: high · Enforcement: advisory
Require GKE clusters to have Application-layer Secrets Encryption enabled
- 2. Resource Encryption at Rest — Encrypt all stored data using approved encryption mechanisms to protect against unauthorized access.
Remediation
Fix: Enable Application-layer Secrets Encryption
const cluster = new gcp.container.Cluster("my-cluster", {
databaseEncryption: {
state: "ENCRYPTED", // Enable secrets encryption
keyName: "projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key", // Specify KMS key
},
// ... other config
});
iam-no-broad-roles
Severity: critical · Enforcement: advisory
Enforce least privilege access control by prohibiting overly broad roles
- 1. Least Privilege — Ensure all identities and services have only the minimum permissions required to perform their tasks.
Remediation
Fix: Use Specific Least-Privilege Roles
const binding = new gcp.projects.IAMBinding("service-binding", {
project: "my-project",
role: "roles/storage.objectViewer", // Use specific roles instead of broad ones
members: [
"serviceAccount:my-app@my-project.iam.gserviceaccount.com",
],
// Avoid overly broad roles like:
// - roles/owner (full project access)
// - roles/editor (write access to most resources)
// Use specific roles: roles/storage.objectViewer, roles/pubsub.publisher, etc.
});
kms-key-configuration
Severity: low · Enforcement: advisory
Require proper Cloud KMS key creation and configuration
- 14. Key Management & Rotation — Manage encryption keys securely and enforce periodic key rotation to reduce the risk of compromise.
Remediation
Fix: Configure KMS Key with Version Template
const cryptoKey = new gcp.kms.CryptoKey("my-crypto-key", {
name: "my-key",
keyRing: keyRing.id,
versionTemplate: {
algorithm: "GOOGLE_SYMMETRIC_ENCRYPTION", // Specify cryptographic algorithm
protectionLevel: "HSM", // Set protection level (SOFTWARE, HSM, EXTERNAL, EXTERNAL_VPC)
},
rotationPeriod: "7776000s", // Optional: Configure 90-day rotation period
purpose: "ENCRYPT_DECRYPT", // Optional: Explicitly set key purpose
// ... other config
});
kms-key-lifecycle
Severity: low · Enforcement: advisory
Require proper Cloud KMS key deletion and lifecycle management
- 14. Key Management & Rotation — Manage encryption keys securely and enforce periodic key rotation to reduce the risk of compromise.
Remediation
Fix: Configure Key Lifecycle Management
const cryptoKey = new kms.CryptoKey("my-crypto-key", {
name: "my-key",
keyRing: keyRing.id,
destroyScheduledDuration: "2592000s", // Set 30-day scheduled destruction period
skipInitialVersionCreation: false, // Create initial key version
versionTemplate: {
algorithm: "GOOGLE_SYMMETRIC_ENCRYPTION",
protectionLevel: "SOFTWARE",
},
// ... other config
});
kms-key-rotation
Severity: high · Enforcement: advisory
Require Cloud KMS keys to have key rotation enabled
- 14. Key Management & Rotation — Manage encryption keys securely and enforce periodic key rotation to reduce the risk of compromise.
Remediation
Fix: Enable Automatic Key Rotation
const cryptoKey = new kms.CryptoKey("my-crypto-key", {
name: "my-key",
keyRing: keyRing.id,
rotationPeriod: "7776000s", // Enable rotation every 90 days
versionTemplate: {
algorithm: "GOOGLE_SYMMETRIC_ENCRYPTION",
protectionLevel: "SOFTWARE",
},
// ... other config
});
load-balancer-health-checks
Severity: medium · Enforcement: advisory
Require Cloud Load Balancers to enable health checks for monitoring backend instance health
- 7. High Availability — Deploy resources in redundant, fault-tolerant configurations to ensure service continuity.
Remediation
Fix: Configure Health Checks for Backend Service
// Create a health check
const healthCheck = new gcp.compute.HealthCheck("backend-health-check", {
httpHealthCheck: {
port: 80,
requestPath: "/health",
},
checkIntervalSec: 10,
timeoutSec: 5,
});
// Attach health check to backend service
const backendService = new gcp.compute.BackendService("my-backend", {
healthChecks: [healthCheck.id], // Configure health checks for monitoring
backends: [/* ... */],
// ... other config
});
load-balancer-logging
Severity: low · Enforcement: advisory
Enable Load Balancer logging for monitoring
- 6. Enforce Logging — Enable and retain audit logs for all security-relevant actions and events.
Remediation
Enable logging on backend services by configuring logConfig.enable: true and set logConfig.sampleRate (1.0 for full logging, lower values for sampling). Ensure logs are retained in Cloud Logging for security analysis and troubleshooting.
Pulumi TypeScript Example:
import * as gcp from "@pulumi/gcp";
// For global backend service
const backendService = new gcp.compute.BackendService("my-backend", {
logConfig: {
enable: true,
sampleRate: 1.0 // 1.0 = 100% logging, 0.5 = 50% sampling
},
// ... other configuration
});
// For regional backend service
const regionBackendService = new gcp.compute.RegionBackendService("my-region-backend", {
logConfig: {
enable: true,
sampleRate: 1.0
},
// ... other configuration
});
load-balancer-multi-zone
Severity: medium · Enforcement: advisory
Require Cloud Load Balancers to be configured across multiple zones for high availability
- 7. High Availability — Deploy resources in redundant, fault-tolerant configurations to ensure service continuity.
Remediation
Fix: Configure Backends Across Multiple Zones
// Create instance groups in multiple zones
const instanceGroup1 = new gcp.compute.InstanceGroup("backend-zone-a", {
zone: "us-central1-a",
instances: [/* ... */],
});
const instanceGroup2 = new gcp.compute.InstanceGroup("backend-zone-b", {
zone: "us-central1-b",
instances: [/* ... */],
});
// Configure backend service with multi-zone backends
const backendService = new gcp.compute.BackendService("multi-zone-backend", {
backends: [
{ group: instanceGroup1.id }, // Backend in zone A
{ group: instanceGroup2.id }, // Backend in zone B for high availability
],
// ... other config
});
load-balancer-tls
Severity: high · Enforcement: advisory
Ensure Load Balancer uses TLS/HTTPS listeners only
- 3. Transport Layer Encryption — Require secure protocols (e.g., TLS) for all data in transit to prevent interception or tampering.
Remediation
Configure forwarding rules to use port 443 for HTTPS traffic. Use TargetHttpsProxy instead of TargetHttpProxy. For HTTP listeners, ensure they redirect to HTTPS via URL map configuration. Remove standalone HTTP listeners without HTTPS redirection.
Pulumi TypeScript Example:
import * as gcp from "@pulumi/gcp";
// Create SSL certificate (or use existing)
const sslCert = new gcp.compute.ManagedSslCertificate("my-cert", {
managed: {
domains: ["example.com"]
}
});
// Create HTTPS target proxy
const httpsProxy = new gcp.compute.TargetHttpsProxy("https-proxy", {
urlMap: urlMap.id,
sslCertificates: [sslCert.id]
});
// Create forwarding rule on port 443
const httpsForwardingRule = new gcp.compute.GlobalForwardingRule("https-rule", {
target: httpsProxy.id,
portRange: "443",
ipProtocol: "TCP",
loadBalancingScheme: "EXTERNAL"
});
// Optional: HTTP to HTTPS redirect
const httpProxy = new gcp.compute.TargetHttpProxy("http-proxy", {
urlMap: redirectUrlMap.id // URL map configured for redirect
});
const httpForwardingRule = new gcp.compute.GlobalForwardingRule("http-rule", {
target: httpProxy.id,
portRange: "80",
ipProtocol: "TCP",
loadBalancingScheme: "EXTERNAL"
});
pubsub-dead-letter-queue
Severity: medium · Enforcement: advisory
Require Pub/Sub subscriptions to have dead letter queue configuration
- 8. Require DLQ — Ensure all asynchronous messaging systems are configured with a dead-letter queue to handle failures.
Remediation
Fix: Configure Dead Letter Queue
const deadLetterTopic = new gcp.pubsub.Topic("dead-letter-topic", {});
const subscription = new gcp.pubsub.Subscription("my-subscription", {
topic: topic.name,
deadLetterPolicy: {
deadLetterTopic: deadLetterTopic.id, // Specify dead letter topic
maxDeliveryAttempts: 5, // Set max delivery attempts before moving to DLQ
},
// ... other config
});
pubsub-topic-iam-least-privilege
Severity: high · Enforcement: advisory
Enforce least privilege IAM policies for Pub/Sub topics
- 1. Least Privilege — Ensure all identities and services have only the minimum permissions required to perform their tasks.
Remediation
Fix: Use Least Privilege IAM Roles
const topicIamBinding = new gcp.pubsub.TopicIAMBinding("topic-publisher-binding", {
topic: topic.id,
role: "roles/pubsub.publisher", // Use specific role instead of admin/owner/editor
members: [
"serviceAccount:app-service@project.iam.gserviceaccount.com", // Use specific service accounts instead of allUsers
],
});
resource-labeling
Severity: low · Enforcement: advisory
Require all GCP resources to have proper labeling for change tracking
- 5. Tagging — Enforce standardized resource tags for ownership, environment, and compliance tracking.
Remediation
Fix: Add Required Labels for Change Tracking
Add the required labels (environment, team, owner) to your GCP resources:
const instance = new gcp.compute.Instance("my-instance", {
labels: {
environment: "production", // Required: environment label
team: "platform", // Required: team label
owner: "john-doe", // Required: owner label
// ... other labels
},
// ... other config
});
// For Cloud SQL instances, use userLabels within settings
const sqlInstance = new gcp.sql.DatabaseInstance("my-database", {
settings: {
userLabels: {
environment: "production", // Required: environment label
team: "data", // Required: team label
owner: "jane-smith", // Required: owner label
},
// ... other settings
},
// ... other config
});
// For GKE clusters, use resourceLabels
const cluster = new gcp.container.Cluster("my-cluster", {
resourceLabels: {
environment: "production", // Required: environment label
team: "infrastructure", // Required: team label
owner: "ops-team", // Required: owner label
},
// ... other config
});