GCP / Guide 6

Security baseline: identity, detection and encryption

2-step verification, service accounts without keys, Security Command Center, audit logs, Cloud KMS and Secret Manager.

Network controls limit where an attacker can go. Most Google Cloud incidents, though, start with an identity: a leaked service account key, a phished administrator, a personal Gmail account that still has Owner on a project. This guide covers the baseline that sits alongside the network: identity, Security Command Center, audit logs, encryption with Cloud KMS, Secret Manager and the logs you'll need on the day something happens.

Identity comes first

  • 2-step verification is required. Google is enforcing 2SV for Google Cloud console and Firebase console access in phases: personal Google accounts first (from May 2025), then Cloud Identity accounts that don't use single sign-on. Federated users satisfy it through their own identity provider's MFA. Don't wait for the deadline: enforce it in the Admin console now, with security keys or passkeys for administrators.
  • Sign in through your identity provider. Federate Cloud Identity or Workspace with Microsoft Entra ID, Okta or similar, so joiners, leavers and MFA are handled in one place. Workforce Identity Federation gives console and gcloud access to users from an external identity provider without syncing them into Cloud Identity at all.
  • Keep outsiders out. The iam.allowedPolicyMemberDomains organisation policy stops roles being granted to personal Gmail accounts and other domains.
  • No standing admin access. Privileged Access Manager for Owner and admin roles; two protected super admins (Guide 2).
  • Review access quarterly. Get-GcpIamReport.ps1 lists public grants, basic roles, grants to outside domains, powerful default service accounts and user-managed keys across projects.

Service accounts without keys

A downloaded service account key is a password that never expires on its own, works from anywhere, and ends up in repositories and laptops. New organisations block key creation by default; for older ones, set iam.managed.disableServiceAccountKeyCreation and remove the keys you have:

  • Workloads on Google Cloud: attach a dedicated service account (never the Compute Engine default one).
  • GKE: Workload Identity Federation for GKE maps Kubernetes service accounts to IAM.
  • Outside Google Cloud: Workload Identity Federation with the platform's own tokens (GitHub Actions, Azure DevOps, AWS, Azure, or any OIDC or SAML identity provider on-premises).
  • People: impersonation, with --impersonate-service-account.
# User-managed keys on every service account in a project, oldest first
$sas = gcloud iam service-accounts list --project=prj-notes-test --format=json | ConvertFrom-Json
foreach ($sa in $sas) {
    gcloud iam service-accounts keys list --iam-account=$($sa.email) --managed-by=user --format=json |
        ConvertFrom-Json | Select-Object @{n='Account';e={$sa.email}}, @{n='Key';e={($_.name -split '/')[-1]}}, validAfterTime
}

Security Command Center

Security Command Center (SCC) is Google Cloud's built-in security posture and threat detection service. Activate it at the organisation level so every project is covered.

TierCostWhat you get
StandardNo extra chargeBasic posture findings (Security Health Analytics for common misconfigurations such as public buckets, open firewall ports and keys), for Google Cloud
PremiumPay as you go or subscriptionStandard plus all Security Health Analytics detectors, Event Threat Detection (from logs), Container and VM Threat Detection, attack path simulation, compliance reports (CIS, PCI DSS, NIST and more)
EnterpriseDeprecatedThe multi-cloud tier is being retired (shutting down 21 May 2027) and migrated to Premium

A sensible start: Standard everywhere today; Premium for the organisation once the Standard findings are under control, or straight away if you hold regulated data. Route high and critical findings to people with notification configs (Pub/Sub to chat or ticketing), and mute findings that don't apply with a documented mute rule rather than ignoring them.

# Active high and critical findings across the organisation, grouped by category
gcloud scc findings list organizations/123456789012 --location=global `
    --filter="state=\"ACTIVE\" AND (severity=\"HIGH\" OR severity=\"CRITICAL\") AND mute!=\"MUTED\"" --format=json |
    ConvertFrom-Json | Group-Object { $_.finding.category } | Sort-Object Count -Descending | Select-Object Count, Name

Audit logs

Cloud Audit Logs record who did what, where and when:

LogRecordsDefault
Admin ActivityConfiguration changes: creating a VM, changing IAMAlways on, free, kept 400 days
System EventGoogle's own actions on your resources (live migration)Always on, free, kept 400 days
Data AccessReads of configuration and data: who read a secret or an objectOff (except BigQuery); charged when on
Policy DeniedCalls blocked by VPC Service Controls or organisation policiesOn, can be excluded
  • Turn on Data Access logs where it matters: Secret Manager, Cloud KMS, IAM, and Cloud Storage buckets holding sensitive data. Not everywhere: they're billed by volume.
  • Keep a copy centrally: an aggregated log sink at the organisation sends audit logs from every project to a locked log bucket (with a retention lock) or to BigQuery in the logging project.
# Organisation-wide sink of all audit logs to a central log bucket
gcloud logging sinks create sink-org-audit `
    logging.googleapis.com/projects/prj-logging/locations/us/buckets/org-audit `
    --organization=123456789012 --include-children `
    --log-filter='logName:"cloudaudit.googleapis.com"'

Encryption and secrets

Everything in Google Cloud is encrypted at rest by default with Google-managed keys. For data where you need control over who can decrypt, or proof that you can revoke access, use customer-managed encryption keys (CMEK) in Cloud KMS:

  • Keep keys in a separate project (prj-security), so project Owners of the workload can't manage their own keys.
  • Set a rotation period (90 days to a year); old key versions still decrypt old data.
  • Grant roles/cloudkms.cryptoKeyEncrypterDecrypter to the service agent of the service that uses the key, on that key only.
  • Key destruction is delayed (30 days by default) and permanent after that. Alert on DestroyCryptoKeyVersion.

Secrets (database passwords, API keys) belong in Secret Manager, not in metadata, environment variables baked into images, or code. Grant roles/secretmanager.secretAccessor on each secret to the service account that needs it, set up rotation with Pub/Sub notifications, and turn on Data Access logs for Secret Manager so every read is recorded.

Harden the VMs

  • Shielded VM (secure boot, vTPM, integrity monitoring) on every VM: enforce with compute.requireShieldedVm.
  • OS Login and IAP, not SSH keys in metadata and open ports (Guide 5).
  • No external IPs except where you've decided otherwise; Cloud NAT for outbound.
  • Patch with VM Manager and scan with SCC's VM vulnerability findings (Guide 7).
  • Confidential VMs for workloads that need memory encrypted in use.

A security baseline checklist

AreaBaselineHow to check
Identity2SV for everyone; federated sign-in; no basic roles for people; outside domains blockedGet-GcpIamReport
Service accountsNo user-managed keys; no default service accounts with EditorGet-GcpIamReport
Management portsNo SSH or RDP from the internet; IAP and OS Login insteadGet-GcpFirewallReport
Data exposurePublic access prevention enforced; no public Cloud SQL IPs; VPC Service Controls for sensitive dataGet-GcpBucketPublicAccessReport
Organisation policiesSecure-by-default set plus locations, external IPs, OS Login, Shielded VMgcloud org-policies list
DetectionSecurity Command Center on at organisation level; findings routed to peopleSCC console
LoggingOrganisation audit log sink to a locked bucket; Data Access logs for secrets and keysgcloud logging sinks list --organization
BackupBackup vaults with enforced retention for productionGuide 8; Get-GcpBackupCoverage