CIS Google Cloud Platform Foundations Benchmark

Secure configuration guidelines for Google Cloud Platform

v4.0.0 February 2025

Overview

▶

This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for Google Cloud Platform. It covers identity management, logging, networking, compute, storage, database, and analytics services.

~80Recommendations
7Sections
2Profile Levels
SectionAreaFocus
1Identity and Access ManagementService accounts, IAM policies, key management
2Logging and MonitoringAudit logs, sinks, log-based alerts
3NetworkingFirewall rules, VPC, Private Google Access, DNS
4Virtual MachinesCompute Engine, OS login, serial ports, shielded VMs
5StorageCloud Storage bucket access, encryption, retention
6Cloud SQLDatabase flags, SSL, public IP, backups
7BigQueryDataset access, encryption, audit

Profile Definitions

▶
ProfileDescriptionIntended Use
L1Level 1Practical baseline security for all GCP projects. Minimal operational impact.
L2Level 2Defense-in-depth for security-sensitive workloads. May affect cost or complexity.

1 — Identity and Access Management

▶

Google Cloud IAM configuration covering service accounts, IAM bindings, and key management.

1.1 Service Accounts

▶
1.1.1 Ensure User-Managed Service Account Keys Are Rotated Within 90 Days (Automated)
L1 Auto
Description

Service account keys should be rotated every 90 days or less. Stale keys increase the window of exposure if compromised. Prefer Workload Identity Federation over user-managed keys.

Rationale

Failure to user-Managed Service Account Keys Are Rotated Within 90 Days may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud iam service-accounts keys list --iam-account <sa-email> \
  --managed-by user --format="table(name,validAfterTime,validBeforeTime)"
# Check if any key's validAfterTime is older than 90 days
Remediation
# Create new key
gcloud iam service-accounts keys create ~/new-key.json \
  --iam-account <sa-email>
# Update applications, then delete old key
gcloud iam service-accounts keys delete <key-id> \
  --iam-account <sa-email>
1.1.2 Ensure Service Account Has No Admin Privileges (Automated)
L1 Auto
Description

Service accounts should not be granted Owner, Editor, or other broad admin roles. Use least-privilege custom roles or predefined granular roles instead.

Rationale

Failure to service Account Has No Admin Privileges may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud projects get-iam-policy <project> --format=json | \
  jq '.bindings[] | select(.role=="roles/owner" or .role=="roles/editor") | 
  .members[] | select(startswith("serviceAccount:"))'
# Should return empty
Remediation
gcloud projects remove-iam-policy-binding <project> \
  --member='serviceAccount:<sa-email>' --role='roles/editor'
# Then assign a least-privilege role
1.1.3 Ensure Default Service Account Is Not Used (Automated)
L1 Auto
Description

GCP creates default service accounts (Compute Engine default, App Engine default) with the Editor role. These should not be used — create dedicated service accounts with minimal permissions.

Rationale

If Default Service Account remains used, it presents an unnecessary risk vector that attackers could exploit. Removing or disabling unused components is a fundamental principle of secure system hardening.

Audit
gcloud iam service-accounts list --filter="email:*-compute@developer.gserviceaccount.com OR email:*@appspot.gserviceaccount.com" --format="table(email,disabled)"
# Default service accounts should be disabled
Remediation
gcloud iam service-accounts disable <default-sa-email>

1.2 IAM Policies

▶
1.2.1 Ensure Corporate Login Credentials Are Used Instead of Gmail Accounts (Manual)
L1
Description

Use managed Cloud Identity or Google Workspace accounts (corporate domain) for GCP access instead of personal Gmail accounts. Corporate accounts provide centralized lifecycle management and policy enforcement.

Rationale

Failure to corporate Login Credentials Are Used Instead of Gmail Accounts may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud projects get-iam-policy <project> --format=json | \
  jq '.bindings[].members[] | select(endswith("@gmail.com"))'
# Should return no gmail.com accounts
Remediation

Replace Gmail-based IAM bindings with managed corporate domain accounts and remove the personal Gmail bindings.

1.2.2 Ensure No IAM Bindings Use allUsers or allAuthenticatedUsers (Automated)
L1 Auto
Description

IAM bindings should not include allUsers (anyone on the internet) or allAuthenticatedUsers (any Google account) as members, unless the resource is intentionally public.

Rationale

Failure to no IAM Bindings Use allUsers or allAuthenticatedUsers may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud projects get-iam-policy <project> --format=json | \
  jq '.bindings[] | select(.members[] | contains("allUsers") or contains("allAuthenticatedUsers"))'
# Should return empty for non-public projects
Remediation
gcloud projects remove-iam-policy-binding <project> \
  --member='allUsers' --role='<role>'

2 — Logging and Monitoring

▶

Cloud Audit Logs, log sinks, and alert policy configuration for security event detection.

2.1 Audit Logging

▶
2.1.1 Ensure Cloud Audit Logging is Configured for All Services and All Users (Automated)
L1 Auto
Description

Enable Data Access audit logs for all services. By default, only Admin Activity logs are enabled. Data Access logs capture read/write operations and should be enabled for security-sensitive services.

Rationale

Failure to cloud Audit Logging is Configured for All Services and All Users may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud projects get-iam-policy <project> --format=json | \
  jq '.auditConfigs[]'
# Should include {"service":"allServices"} with all log types enabled
Remediation

Update the project IAM policy to enable DATA_READ, DATA_WRITE, and ADMIN_READ audit log types for allServices with no exempted members.

2.1.2 Ensure Log Sinks Are Configured for All Log Entries (Automated)
L2 Auto
Description

Create a log sink to export all log entries to a long-term storage destination (Cloud Storage, BigQuery, or Pub/Sub). Default log retention is 30 days — a sink ensures logs are preserved longer.

Rationale

Failure to log Sinks Are Configured for All Log Entries may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud logging sinks list --project=<project> \
  --format="table(name,destination,filter)"
# Should have at least one sink with no filter (captures all logs)
Remediation
gcloud logging sinks create <sink-name> \
  storage.googleapis.com/<bucket> --project=<project>

2.2 Log-Based Alerts

▶
2.2.1 Ensure Log Metric Filter and Alert Exist for Project Ownership Changes (Automated)
L1 Auto
Description

Create a log-based metric and alert for project ownership assignment changes. Ownership changes can grant full control of the project to unauthorized users.

Rationale

Failure to log Metric Filter and Alert Exist for Project Ownership Changes may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud logging metrics list --project=<project> --format="table(name,filter)"
# Look for metric with filter:
#   (protoPayload.serviceName="cloudresourcemanager.googleapis.com") AND
#   (ProjectOwnership OR projectOwnerInvitee) OR
#   (protoPayload.serviceData.policyDelta.bindingDeltas.role="roles/owner")
Remediation

Create a log-based metric with the appropriate filter, then create a Monitoring alert policy that triggers on the metric.

2.2.2 Ensure Log Metric Filter and Alert Exist for Audit Configuration Changes (Automated)
L1 Auto
Description

Monitor changes to audit configuration (disabling logs, adding exemptions). Attackers may disable audit logging to cover their tracks.

Rationale

Failure to log Metric Filter and Alert Exist for Audit Configuration Changes may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
# Look for metric with filter:
#   protoPayload.methodName="SetIamPolicy" AND
#   protoPayload.serviceData.policyDelta.auditConfigDeltas:*
gcloud logging metrics list --project=<project>
Remediation

Create a log-based metric for IAM audit config changes and configure a Monitoring alert policy.

2.2.3 Ensure Log Metric Filter and Alert Exist for VPC Firewall Rule Changes (Automated)
L1 Auto
Description

Monitor VPC firewall rule creation, modification, and deletion. Unauthorized firewall changes can expose resources to the internet.

Rationale

Failure to log Metric Filter and Alert Exist for VPC Firewall Rule Changes may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
# Look for metric with filter:
#   resource.type="gce_firewall_rule" AND
#   (protoPayload.methodName:"compute.firewalls.insert" OR
#    protoPayload.methodName:"compute.firewalls.patch" OR
#    protoPayload.methodName:"compute.firewalls.delete")
gcloud logging metrics list --project=<project>
Remediation

Create a log-based metric for firewall rule changes and configure a Monitoring alert policy.

3 — Networking

▶

VPC firewall rules, DNS, SSL policies, and Private Google Access configuration.

3.1 Firewall Rules

▶
3.1.1 Ensure the Default Network Does Not Exist (Automated)
L2 Auto
Description

Delete the default VPC network in every project. The default network includes pre-populated firewall rules that allow broad access. Create custom VPCs with restrictive rules instead.

Rationale

The absence of the Default Network Does Not leaves the Google Cloud Platform cloud platform without an important security control. Verifying its presence ensures the system meets the minimum security baseline required by the CIS benchmark.

Audit
gcloud compute networks list --project=<project> --filter="name=default" --format="table(name)"
# Should return empty
Remediation
# Delete all firewall rules first
gcloud compute firewall-rules list --filter="network:default" --format="value(name)" | \
  xargs -I {} gcloud compute firewall-rules delete {} --quiet
# Then delete the network
gcloud compute networks delete default --quiet
3.1.2 Ensure No Firewall Rule Allows Ingress from 0.0.0.0/0 to SSH (port 22) (Automated)
L1 Auto
Description

No VPC firewall rule should allow unrestricted SSH access from 0.0.0.0/0. Use Identity-Aware Proxy (IAP) TCP forwarding or OS Login with specific source ranges.

Rationale

Failure to no Firewall Rule Allows Ingress from 0.0.0.0/0 to SSH (port 22) may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud compute firewall-rules list --filter="direction=INGRESS AND allowed[].ports:22 AND sourceRanges:0.0.0.0/0" \
  --format="table(name,network,allowed,sourceRanges)"
# Should return empty
Remediation
gcloud compute firewall-rules update <rule-name> \
  --source-ranges=<trusted-cidr>
# Or use IAP:
gcloud compute firewall-rules create allow-ssh-iap \
  --allow tcp:22 --source-ranges 35.235.240.0/20 --direction INGRESS
3.1.3 Ensure No Firewall Rule Allows Ingress from 0.0.0.0/0 to RDP (port 3389) (Automated)
L1 Auto
Description

No VPC firewall rule should allow unrestricted RDP access from 0.0.0.0/0. Restrict to specific source ranges or use IAP TCP forwarding.

Rationale

Failure to no Firewall Rule Allows Ingress from 0.0.0.0/0 to RDP (port 3389) may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud compute firewall-rules list --filter="direction=INGRESS AND allowed[].ports:3389 AND sourceRanges:0.0.0.0/0" \
  --format="table(name,network,allowed,sourceRanges)"
# Should return empty
Remediation

Update firewall rules to restrict RDP to trusted source IP ranges or use IAP TCP forwarding.

3.2 VPC & DNS

▶
3.2.1 Ensure Private Google Access is Enabled on Subnets (Automated)
L2 Auto
Description

Enable Private Google Access on VPC subnets so instances without external IP addresses can reach Google APIs and services via internal IP addresses.

Rationale

Failure to private Google Access is Enabled on Subnets may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud compute networks subnets list --format="table(name,region,privateIpGoogleAccess)"
# privateIpGoogleAccess should be True for all subnets
Remediation
gcloud compute networks subnets update <subnet> --region=<region> \
  --enable-private-ip-google-access
3.2.2 Ensure DNSSEC is Enabled for Cloud DNS Managed Zones (Automated)
L1 Auto
Description

Enable DNSSEC on Cloud DNS managed zones to provide authentication of DNS responses and protect against DNS spoofing attacks.

Rationale

Failure to dNSSEC is Enabled for Cloud DNS Managed Zones may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud dns managed-zones list --format="table(name,dnsName,dnssecConfig.state)"
# dnssecConfig.state should be "on" for all public zones
Remediation
gcloud dns managed-zones update <zone> --dnssec-state on

4 — Virtual Machines

▶

4.1 Compute Engine

▶
4.1.1 Ensure OS Login is Enabled for Compute Instances (Automated)
L1 Auto
Description

Enable OS Login at the project level to manage SSH keys via IAM instead of metadata SSH keys. OS Login provides centralized key management, automatic key lifecycle management, and 2FA support.

Rationale

Failure to oS Login is Enabled for Compute Instances may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud compute project-info describe --format="value(commonInstanceMetadata.items[key='enable-oslogin'].value)"
# Should be TRUE
Remediation
gcloud compute project-info add-metadata --metadata enable-oslogin=TRUE
4.1.2 Ensure Shielded VM is Enabled for Compute Instances (Automated)
L2 Auto
Description

Enable Shielded VM features (Secure Boot, vTPM, Integrity Monitoring) for all Compute Engine instances to protect against rootkits and bootkits.

Rationale

Failure to shielded VM is Enabled for Compute Instances may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud compute instances list --format="table(name,shieldedInstanceConfig.enableSecureBoot,shieldedInstanceConfig.enableVtpm,shieldedInstanceConfig.enableIntegrityMonitoring)"
Remediation
gcloud compute instances update <instance> --zone=<zone> \
  --shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring
4.1.3 Ensure VM Serial Port Logging is Disabled (Automated)
L1 Auto
Description

Disable interactive serial console access to VM instances. The serial console does not support IP-based access restrictions and could provide an additional attack surface if credentials are compromised.

Rationale

Leaving VM Serial Port Logging enabled when it is not required unnecessarily expands the attack surface. An attacker could leverage this feature to gain unauthorized access or escalate privileges on the Google Cloud Platform cloud platform.

Audit
gcloud compute instances describe <instance> --zone=<zone> \
  --format="value(metadata.items[key='serial-port-enable'].value)"
# Should be empty or FALSE
Remediation
# Disable at org policy level
gcloud resource-manager org-policies enable-enforce \
  compute.disableSerialPortAccess --project=<project>
4.1.4 Ensure Compute Instances Do Not Have Public IP Addresses (Automated)
L2 Auto
Description

Compute instances should not have external (public) IP addresses unless required. Use Cloud NAT for outbound internet access and IAP TCP forwarding or load balancers for inbound access.

Rationale

Failure to compute Instances Do Not Have Public IP Addresses may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud compute instances list --format="table(name,zone,networkInterfaces[0].accessConfigs[0].natIP)"
# natIP column should be empty for instances that don't need public access
Remediation

Remove the external IP from instances: gcloud compute instances delete-access-config <instance> --access-config-name "External NAT" --zone=<zone>

5 — Storage

▶

5.1 Cloud Storage

▶
5.1.1 Ensure Cloud Storage Buckets Are Not Publicly Accessible (Automated)
L1 Auto
Description

Ensure buckets do not grant access to allUsers or allAuthenticatedUsers. Public buckets can lead to data exposure. Enable the organization policy constraints/storage.publicAccessPrevention.

Rationale

Failure to cloud Storage Buckets Are Not Publicly Accessible may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gsutil iam get gs://<bucket> | \
  jq '.bindings[] | select(.members[] | contains("allUsers") or contains("allAuthenticatedUsers"))'
# Should return empty
Remediation
gsutil iam ch -d allUsers gs://<bucket>
gsutil iam ch -d allAuthenticatedUsers gs://<bucket>
5.1.2 Ensure Uniform Bucket-Level Access is Enabled (Automated)
L2 Auto
Description

Enable Uniform bucket-level access (formerly Bucket Policy Only) to disable per-object ACLs. This simplifies access management by using only IAM policies for all access control.

Rationale

Without Uniform Bucket-Level Access enabled, the Google Cloud Platform cloud platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.

Audit
gsutil uniformbucketlevelaccess get gs://<bucket>
# Enabled value should be True
Remediation
gsutil uniformbucketlevelaccess set on gs://<bucket>

6 — Cloud SQL

▶

6.1 Database Instances

▶
6.1.1 Ensure Cloud SQL Does Not Have a Public IP (Automated)
L2 Auto
Description

Cloud SQL instances should use private IP addresses only. Public IP addresses expose the database to potential internet-based attacks even with authorized networks configured.

Rationale

Failure to cloud SQL Does Not Have a Public IP may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud sql instances list --format="table(name,ipAddresses)"
# Should not have type:PRIMARY external IP addresses
Remediation

Configure private IP for the instance, update applications to connect via private IP, then remove the public IP address.

6.1.2 Ensure Cloud SQL Instances Require SSL Connections (Automated)
L1 Auto
Description

Configure Cloud SQL instances to require SSL/TLS for all connections. This prevents data interception and ensures encrypted communication between applications and the database.

Rationale

Failure to cloud SQL Instances Require SSL Connections may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud sql instances describe <instance> --format="value(settings.ipConfiguration.requireSsl)"
# Should be True
Remediation
gcloud sql instances patch <instance> --require-ssl
6.1.3 Ensure Automated Backups Are Configured for Cloud SQL (Automated)
L1 Auto
Description

Enable automated backups for all Cloud SQL instances to ensure data recovery in case of accidental deletion, corruption, or security incidents.

Rationale

Failure to automated Backups Are Configured for Cloud SQL may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
gcloud sql instances describe <instance> \
  --format="value(settings.backupConfiguration.enabled,settings.backupConfiguration.pointInTimeRecoveryEnabled)"
# Both should be True
Remediation
gcloud sql instances patch <instance> \
  --backup-start-time 02:00 --enable-point-in-time-recovery

7 — BigQuery

▶

7.1 Datasets

▶
7.1.1 Ensure BigQuery Datasets Are Not Publicly Accessible (Automated)
L1 Auto
Description

BigQuery datasets should not be shared with allUsers or allAuthenticatedUsers. Public datasets can expose sensitive analytical data.

Rationale

Failure to bigQuery Datasets Are Not Publicly Accessible may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
bq show --format=prettyjson <project:dataset> | \
  jq '.access[] | select(.specialGroup=="allAuthenticatedUsers" or .iamMember=="allUsers")'
# Should return empty
Remediation

Remove public access from the dataset using the BigQuery console or bq update command.

7.1.2 Ensure BigQuery Datasets Use Customer-Managed Encryption Keys (Automated)
L2 Auto
Description

Use Customer-Managed Encryption Keys (CMEK) from Cloud KMS for BigQuery datasets instead of Google-managed encryption. CMEK provides control over encryption key lifecycle and access auditing.

Rationale

Failure to bigQuery Datasets Use Customer-Managed Encryption Keys may leave the Google Cloud Platform cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
bq show --format=prettyjson <project:dataset> | jq '.defaultEncryptionConfiguration'
# Should show a kmsKeyName
Remediation
bq update --default_kms_key <kms-key-name> <project:dataset>