GCP Lesson 70 of 98

GCP Landing Zone: Security & Guardrails — Org Policy Constraints, VPC Service Controls, Security Command Center, CMEK & Assured Workloads

In a nutshell

A landing zone’s security pillar is the layer that turns policy into physics. The first three parts agreed on how the cloud estate is shaped, who may act, and how the network is wired — but agreements can be forgotten, mis-clicked, or ignored. Security & Guardrails is where “we agreed not to do that” becomes “the platform will not let you do that.” It is preventive first (stop the bad thing before it exists) and detective second (catch what still slips through), and it is expressed as configuration, not as a slide deck of good intentions.

Picture a bank, not a single vault door. Organization Policy is the building code — some things simply cannot be built here (no public windows into the vault room), and the inspector rejects the blueprint at permit time, before a single brick is laid. VPC Service Controls is the loading dock with a manifest — even a courier with a valid ID badge cannot wheel a cart of cash out to a truck that isn’t on the approved list; the badge (IAM) got them in, but moving value across the wall needs its own sign-off. CMEK is you holding the only key to the safe-deposit boxes — the bank stores your box, but if you melt your key, nobody opens it, not even the bank. Assured Workloads is a bonded, cleared-staff-only wing — the whole floor is pre-certified to a regulation, and even the building’s own maintenance crew must be vetted and in-country to enter. And Security Command Center is the guard station with every camera feed — it doesn’t lock any door itself, but it sees the whole building at once, raises the alarm on what the locks missed, and proves to the auditor that the locks are working.

Get this pillar right and the identity, network, and operations pillars all inherit a hard, provable, defence-in-depth baseline. Get it wrong and everything above it is expensive scaffolding around an open door.

Level: Advanced · Time: ~38 min · Prerequisites: Part 1 — the resource hierarchy (Organization, folders, projects, and policy inheritance — the tree that guardrails attach to), the identity plane from Part 2 (IAM grants who may act), and the network from Part 3 (the private path VPC-SC rides on). Comfort reading a gcloud command and a YAML block.

After this lesson you can:

GCP landing zone security pillar — Org Policy guardrails to VPC Service Controls perimeter to CMEK keys to Assured Workloads regime, all watched by Security Command Center

Read left → right: Organization Policy blocks disallowed configurations before they can exist; a VPC Service Controls perimeter stops data leaving even when the credential is valid; CMEK puts the encryption keys — and the off-switch — under your control; Assured Workloads pins a whole folder to a sovereignty or compliance regime including controls over Google’s own support staff; and Security Command Center watches the entire org, catching what slips through and proving the guardrails hold. Every preventive layer rolls out in dry-run before it enforces.

Where this fits

Parts 1–3 built the resource hierarchy, the identity plane, and the network of the Google Cloud landing zone. Security & Guardrails is the layer that makes all three enforceable: it turns “we agreed not to do that” into “the platform will not let you do that.” On Google Cloud the guardrail model is preventive first — Organization Policy stops disallowed configurations before they exist, VPC Service Controls draw a data-exfiltration perimeter around your APIs, CMEK puts you in control of the encryption keys under your data, and Assured Workloads pins whole folders to a sovereignty or compliance regime — and detective second, with Security Command Center continuously scoring posture and surfacing threats across the org. This article goes deep on those five sub-components and, critically, on how they compose: an Org Policy that blocks public IPs, a VPC-SC perimeter that blocks the exfiltration path, a CMEK boundary that blocks decryption outside your key ring, an Assured Workloads folder that pins residency, and SCC watching the whole thing — that is defence in depth expressed as landing-zone configuration, not slideware.

Google Cloud Landing Zone Design — animated overview

Organization Policy constraints — preventive guardrails on the hierarchy

What it is. The Organization Policy Service lets you set constraints on the resource hierarchy (Organization, folder, or project) that restrict what configurations are even allowed, regardless of a principal’s IAM permissions. This is the key distinction from IAM: IAM governs who can act; Org Policy governs what may exist. A user with roles/owner on a project still cannot create a VM with an external IP if an Org Policy forbids it. Constraints come in two flavours: list constraints (allow/deny specific values, e.g. which regions, which external IPs, which sharing domains) and boolean constraints (on/off, e.g. disable SA key creation, require OS Login). A constraint set on a node becomes the effective policy for everything beneath it, with child nodes able to inherit, merge, or override depending on how the policy is written.

Why it matters. Org Policy is the preventive backbone of the entire guardrail strategy. Detective controls tell you the barn door is open; preventive controls nail it shut. Because constraints are evaluated at resource-creation and modification time by the API itself, a misconfiguration is rejected, not merely flagged hours later by a scanner. That is the difference between “we found a public bucket in last night’s scan” and “the public bucket could never be created.” For regulated landing zones this is non-negotiable — auditors want to see that residency and exposure controls are enforced, not aspirational.

How to do it well.

Constraint (selected baseline) Type What it prevents
gcp.resourceLocations List Resources created outside approved regions (residency)
compute.vmExternalIpAccess List VMs getting public IPs (default-deny, allow-list exceptions)
compute.requireOsLogin Boolean SSH outside centrally-managed OS Login identities
compute.requireShieldedVm Boolean VMs without Secure/Measured Boot + vTPM
iam.disableServiceAccountKeyCreation Boolean Exportable, long-lived SA JSON keys
iam.allowedPolicyMemberDomains List IAM grants to identities outside your Cloud Identity domain(s)
iam.automaticIamGrantsForDefaultServiceAccounts Boolean Default SAs silently receiving roles/editor
storage.publicAccessPrevention Boolean Buckets/objects becoming publicly readable
storage.uniformBucketLevelAccess Boolean Legacy per-object ACLs that bypass IAM
sql.restrictPublicIp Boolean Cloud SQL instances exposed on a public IP
gcp.restrictNonCmekServices List Services creating resources without CMEK

Worked example — enforce a baseline, dry-run a risky one, and write a custom constraint. Three patterns you use constantly. First, a boolean constraint enforced at the Org node so every project inherits it, and a list constraint that pins residency:

# publicaccess.yaml — a boolean constraint. Enforced at the Org, inherited everywhere.
name: organizations/ORG_ID/policies/storage.publicAccessPrevention
spec:
  rules:
    - enforce: true
# locations.yaml — a list constraint. Only EU locations may host resources.
name: organizations/ORG_ID/policies/gcp.resourceLocations
spec:
  rules:
    - values:
        allowedValues:
          - in:eu-locations   # a Google-curated value group; also us-locations, asia-locations, or exact regions
gcloud org-policies set-policy publicaccess.yaml
gcloud org-policies set-policy locations.yaml

Second, never flip a risky constraint straight to enforce on a live estate — introduce it in dry-run so violations are logged, not blocked. In Terraform the same policy carries a dry_run_spec you later graduate to spec:

# Introduce external-IP deny in AUDIT mode first. When the dry-run audit logs
# (type OrgPolicyViolationInfo) are clean, move the same rule into spec { } to enforce.
resource "google_org_policy_policy" "external_ip" {
  name   = "organizations/ORG_ID/policies/compute.vmExternalIpAccess"
  parent = "organizations/ORG_ID"

  dry_run_spec {
    rules { deny_all = "TRUE" }
  }
}

Third, when no built-in constraint fits, author a custom constraint in CEL — here “every GKE cluster must enable Shielded Nodes,” then enforce it like any other constraint:

# shielded-nodes.yaml — a CUSTOM constraint. ALLOW == permit the op ONLY when the condition is true.
name: organizations/ORG_ID/customConstraints/custom.gkeRequireShieldedNodes
resourceTypes:
  - container.googleapis.com/Cluster
methodTypes:
  - CREATE
  - UPDATE
condition: "resource.shieldedNodes.enabled == true"
actionType: ALLOW
displayName: Require Shielded GKE nodes
description: All GKE clusters must enable Shielded Nodes.
gcloud org-policies set-custom-constraint shielded-nodes.yaml
# then enforce it — a policy file whose name references custom.gkeRequireShieldedNodes, enforce: true
gcloud org-policies set-policy enforce-shielded.yaml

Key artifacts: an Org Policy baseline document mapping each constraint to a control objective; the Terraform module that applies it at Org/folder scope; a dry-run rollout plan for any constraint added to a live estate; and a register of approved exceptions (which folder, which constraint, why, expiry).

VPC Service Controls — a data-exfiltration perimeter around your APIs

What it is. VPC Service Controls (VPC-SC) create a service perimeter — a virtual boundary around a set of projects within which Google-managed APIs (Cloud Storage, BigQuery, Cloud KMS, Pub/Sub, and dozens more) can be called, and across which data cannot move unless an explicit rule allows it. The crucial insight is that VPC-SC does not control identity (that’s IAM) — it controls context and data movement. Even a principal holding valid, correct IAM permissions on a BigQuery dataset is blocked from reading it if the request originates outside the perimeter, or from copying it to a project outside the perimeter. VPC-SC closes the gap that IAM alone cannot: a leaked credential or a malicious insider with legitimate access still cannot exfiltrate data out of the boundary.

Why it matters. This is GCP’s principal defence against data exfiltration via the API surface. The classic attack — stolen service-account credential, then gsutil cp the data to an attacker-controlled bucket in their own project — is exactly what a perimeter stops, because the destination project is outside the perimeter and the egress rule denies it. VPC-SC is also how you ensure that data which must stay inside the company cannot be reached from the public internet even with valid keys, and how you stop the subtler “service-to-service” exfiltration where data hops between Google services. For any landing zone handling regulated or high-value data, VPC-SC is the control that makes “valid credentials are not enough” literally true.

How to do it well.

Design element Tool / mechanism Decision in the landing zone
The boundary Service Perimeter One prod perimeter to start; bridges only on demand
Trusted context Access Levels (Access Context Manager) Corporate CIDRs, region, device trust, identities
Who may enter Ingress policies Admins from corp net + named CI principals
What may leave Egress policies Named partner/export projects only
Private API path restricted.googleapis.com + PGA/PSC + DNS All API traffic stays off the public internet
Safe rollout Dry-run perimeter + audit logs Weeks of dry-run before enforce

Worked example — a dry-run perimeter with a trusted access level and one ingress rule. Build the boundary in audit mode, define trusted context, allow one narrow entry, then promote. Note VPC-SC’s own dry-run: a perimeter has an enforced status and a proposed spec, and “enforce” copies specstatus:

# 1. One org-scoped access policy (skip if you already have one).
gcloud access-context-manager policies create \
  --organization=ORG_ID --title="corp-policy"

# 2. An access level describing TRUSTED context — corporate egress CIDRs.
gcloud access-context-manager levels create corp_network \
  --policy=POLICY_ID --title="Corp network" \
  --basic-level-spec=access-level.yaml
# access-level.yaml — the trusted-context definition (a list of conditions).
- ipSubnetworks:
    - 203.0.113.0/24
    - 198.51.100.0/24
# 3. Create the perimeter in DRY-RUN first: restricted services, nothing blocked yet.
gcloud access-context-manager perimeters dry-run create prod_data \
  --policy=POLICY_ID --title="Prod data perimeter" \
  --perimeter-type=regular \
  --resources=projects/PROJECT_NUMBER \
  --restricted-services=storage.googleapis.com,bigquery.googleapis.com,cloudkms.googleapis.com

# 4. Allow a narrow ingress: SecOps, from the corp network only, into BigQuery.
gcloud access-context-manager perimeters dry-run update prod_data \
  --policy=POLICY_ID --set-ingress-policies=ingress.yaml
# ingress.yaml — who may ENTER the perimeter, from where, to do what.
- ingressFrom:
    sources:
      - accessLevel: accessPolicies/POLICY_ID/accessLevels/corp_network
    identities:
      - group:gcp-secops@example.com
  ingressTo:
    operations:
      - serviceName: bigquery.googleapis.com
        methodSelectors:
          - method: "*"
    resources:
      - "*"
# 5. After weeks of clean dry-run logs, promote the SAME config to ENFORCED.
gcloud access-context-manager perimeters dry-run enforce prod_data --policy=POLICY_ID

For the full exfiltration-prevention walkthrough — bridges, egress rules to partner projects, and the DNS that pins the restricted VIP — see the dedicated VPC Service Controls deep-dive lesson.

Key artifacts: a perimeter topology diagram; the Access Context Manager access-level definitions; the ingress/egress rule catalogue with justification per rule; the dry-run violation report and remediation log; and the DNS/PGA configuration that routes APIs to the restricted VIP.

Security Command Center — the detective and posture plane

What it is. Security Command Center (SCC) is Google Cloud’s centralized security and risk-management platform — the single pane that aggregates misconfiguration findings, vulnerabilities, and threats across the whole organization. It runs three broad classes of capability: posture/CSPM (built-in detectors like Security Health Analytics flag misconfigurations such as public buckets, open firewall rules, disabled audit logs, or non-CMEK resources against benchmarks like CIS GCP); threat detection (Event Threat Detection mines Cloud Audit and other logs for IOC patterns and anomalous IAM grants; Container Threat Detection and VM Threat Detection watch runtime behaviour); and attack-path and exposure analysis (the Attack Path Simulation and Toxic Combination features in the premium/Enterprise tiers show how an internet-exposed resource could chain to a high-value asset). Everything lands as a normalized Finding in the SCC inventory, scored by severity.

Why it matters. Org Policy and VPC-SC are preventive, but no preventive control is complete — new services ship, exceptions get granted, drift happens. SCC is the detective net that catches what slips through, plus the inventory (Cloud Asset Inventory under the hood) that answers “what do we even have and how exposed is it?” Critically, SCC is org-scoped: it sees every project, so it is the right place to measure whether the landing-zone guardrails are actually holding. It is also the integration point that pushes findings to your SIEM/SOAR so security operations runs from one normalized feed rather than per-product consoles.

How to do it well.

SCC capability Detector / feature What it catches
Misconfiguration (CSPM) Security Health Analytics Public buckets, open firewalls, disabled logging, non-CMEK
App vulns Web Security Scanner XSS, mixed content, outdated libs on public apps
Threats from logs Event Threat Detection Anomalous IAM grants, malware IOCs, data-exfil signals
Runtime threats Container / VM Threat Detection Suspicious binaries, crypto-mining, reverse shells
Exposure Attack Path Simulation / Toxic Combinations Internet → high-value-asset attack chains
Inventory Cloud Asset Inventory “What do we have, where, how exposed”

Worked example — stream findings to your SIEM, export for evidence, and mute accepted risk. Activation is an org-level action done once; from there the operating model is notification, export, and muting. Every command is org-scoped because SCC is org-scoped:

# Stream ACTIVE, high-severity findings to Pub/Sub → your SIEM (Google SecOps/Splunk).
gcloud scc notifications create scc-high-findings \
  --organization=ORG_ID \
  --description="Active HIGH/CRITICAL findings to SecOps" \
  --pubsub-topic=projects/SECOPS_PROJECT/topics/scc-findings \
  --filter='state="ACTIVE" AND severity="HIGH"'

# Land every active finding in BigQuery for long-term analytics and audit evidence.
gcloud scc bqexports create scc-bq-export \
  --organization=ORG_ID \
  --dataset=projects/SECOPS_PROJECT/datasets/scc_findings \
  --filter='state="ACTIVE"'

# Mute an accepted-risk class so the queue shows only ACTIONABLE items (mute ≠ resolve).
gcloud scc muteconfigs create mute-sandbox-buckets \
  --organization=ORG_ID \
  --description="Accepted risk: intentional public demo buckets in sandbox" \
  --filter='category="PUBLIC_BUCKET_ACL" AND resource.project_display_name="sandbox-demo"'

Key artifacts: the SCC tier decision and org-level activation; the Pub/Sub→SIEM export configuration; the mute-rule catalogue with justifications; a finding-triage runbook with severity-based SLAs; and the compliance-dashboard mapping used as audit evidence.

Customer-managed encryption keys (CMEK) — owning the keys under your data

What it is. Every byte at rest in Google Cloud is encrypted by default with Google-managed keys — that is automatic and free. CMEK changes who controls the key-encryption key: instead of Google managing it opaquely, you create and own a CryptoKey in Cloud KMS (or Cloud HSM, or Cloud External Key Manager / EKM) and point your services — Cloud Storage, BigQuery, Persistent Disk, Cloud SQL, Pub/Sub, Spanner, and many more — at that key via a CMEK setting. The service then calls KMS to wrap/unwrap data-encryption keys using your key. Because you govern the key’s IAM, rotation, and lifecycle, you gain a powerful lever: disabling or destroying the key cryptographically renders the data inaccessible — a hard, provable control that Google-managed keys cannot give you.

Why it matters. CMEK matters for three concrete reasons. First, separation of duties / cryptographic shredding: the ability to revoke access to data by disabling a key — independent of the data service’s own IAM — is exactly what many regulators and risk teams require. Second, key residency and HSM/external control: Cloud HSM keeps keys in FIPS 140-2 Level 3 hardware in a chosen region; Cloud EKM keeps the key material outside Google entirely, in a partner key manager (Thales, Fortanix, etc.) or your own, so Google never holds the key — the basis for “hold your own key” sovereignty stories. Third, auditability: every key use is logged, so you can prove what decrypted what, when. The landing-zone decision is which data classes get CMEK, in which protection level, in which region — and how you stop resources being created without CMEK.

How to do it well.

Decision Options Landing-zone guidance
Protection level SOFTWARE / HSM / EXTERNAL (EKM) By data class; HSM for regulated, EKM for sovereignty
Key location Per region per env Key rings in a dedicated key-mgmt project
Rotation Manual vs scheduled Scheduled rotation_period (e.g. 90 days)
Who can encrypt/decrypt Service agents vs humans Per-service agent on the specific key only
Enforcement Optional vs mandatory restrictNonCmekServices + restrictCmekCryptoKeyProjects
Shredding N/A vs key-disable runbook Documented disable/destroy procedure

Worked example — a rotating HSM key, a scoped service-agent grant, a CMEK dataset, and enforcement. The full loop: create the key in the key-management project, grant only the service agent, create data that defaults to it, then make CMEK mandatory so nobody bypasses it:

# 1. In the DEDICATED key-management project: a regional key ring + an HSM key that rotates.
gcloud kms keyrings create hhg-eu-prod \
  --location=europe-west1 --project=KEYMGMT_PROJECT

gcloud kms keys create bq-cmek \
  --location=europe-west1 --keyring=hhg-eu-prod --project=KEYMGMT_PROJECT \
  --purpose=encryption --protection-level=hsm \
  --rotation-period=90d --next-rotation-time=2026-10-01T00:00:00Z

# 2. Grant ONLY the BigQuery service agent encrypt/decrypt on THAT key — never a human.
gcloud kms keys add-iam-policy-binding bq-cmek \
  --location=europe-west1 --keyring=hhg-eu-prod --project=KEYMGMT_PROJECT \
  --member="serviceAccount:bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com" \
  --role="roles/cloudkms.cryptoKeyEncrypterDecrypter"

# 3. Create a BigQuery dataset that DEFAULTS to the CMEK key.
bq mk --dataset \
  --default_kms_key=projects/KEYMGMT_PROJECT/locations/europe-west1/keyRings/hhg-eu-prod/cryptoKeys/bq-cmek \
  WORKLOAD_PROJECT:clinical_eu
# restrict-noncmek.yaml — these services may NOT create resources without CMEK.
name: organizations/ORG_ID/policies/gcp.restrictNonCmekServices
spec:
  rules:
    - values:
        deniedValues:
          - bigquery.googleapis.com
          - storage.googleapis.com
          - sqladmin.googleapis.com
# restrict-keyprojects.yaml — CMEK keys may ONLY come from the key-management project.
name: organizations/ORG_ID/policies/gcp.restrictCmekCryptoKeyProjects
spec:
  rules:
    - values:
        allowedValues:
          - under:projects/KEYMGMT_PROJECT

The envelope-encryption mechanics (your key wraps a data-encryption key), EKM/Key Access Justifications, and the destroy-versus-disable lifecycle are covered end-to-end in the Cloud KMS / CMEK deep-dive lesson.

Key artifacts: a data-classification-to-protection-level matrix; the KMS key-ring / key-management-project Terraform; the per-service-agent IAM bindings; the rotation and destruction runbooks; and the CMEK-enforcement Org Policies.

Assured Workloads — pinning a folder to a compliance and sovereignty regime

What it is. Assured Workloads lets you create a folder (the Assured Workloads workload) that is bound to a specific compliance or sovereignty regime — for example FedRAMP Moderate/High, IL4/IL5, CJIS, HIPAA, ITAR, EU Regions & Support / EU Sovereign Controls, Canada Regions & Support, and others. Once a workload is created under a regime, Google automatically applies and continuously enforces the controls that regime requires: data residency (resources can only be created in approved regions), personnel access controls (support and operations restricted to vetted personnel in approved geographies — the sovereign / support-access dimension), encryption requirements (often CMEK mandatory, sometimes EKM), and product restrictions (only services that meet the regime are permitted in the folder). It is, in effect, a pre-packaged, Google-enforced bundle of Org Policies, residency rules, personnel controls, and key requirements wrapped around a folder — plus continuous monitoring that flags drift from the regime.

Why it matters. Assembling FedRAMP-High or EU-sovereignty controls by hand — every region constraint, every CMEK rule, every support-access restriction, every product allow-list — is enormous, error-prone, and hard to prove. Assured Workloads collapses that to a regime selection and delivers continuous, auditable enforcement plus the personnel/operational controls (data residency and who-can-touch-the-data) that you fundamentally cannot build yourself with Org Policy alone, because they govern Google’s own support staff. For organizations under government, defence, healthcare, or data-sovereignty mandates, this is the difference between a multi-quarter compliance project and a configured folder. It is the landing zone’s answer to “this entire workload domain must provably stay within these legal and operational boundaries.”

How to do it well.

Regime family Example use case Core controls it enforces
US Government (FedRAMP Mod/High, IL4/IL5) Federal / defence workloads US-region residency, US-personnel support access, CMEK
Criminal Justice (CJIS) Law-enforcement data Residency + vetted-personnel access
Healthcare (HIPAA) PHI workloads Restricted products + encryption posture
EU Sovereignty (EU Regions & Support, EU Sovereign Controls) EU data-residency / sovereignty EU residency, EU-personnel access, CMEK/EKM
Regional (Canada, others) In-country residency mandates In-region residency + support access

Worked example — create a FedRAMP Moderate workload folder. One command binds a new folder to a regime; Google then applies and continuously enforces residency, personnel/support access, the product allow-list, and mandatory CMEK beneath it. The regime is fixed at creation — choose deliberately:

# Creates the Assured Workloads folder + its enforced control bundle under the regime.
gcloud assured workloads create \
  --organization=ORG_ID \
  --location=us-central1 \
  --display-name="federal-research" \
  --compliance-regime=FEDRAMP_MODERATE \
  --billing-account=billingAccounts/0X0X0X-0X0X0X-0X0X0X

Key artifacts: the regulated-folder design and the Assured Workloads workload definition (regime + region); the documented region/product allow-list for that regime; the CMEK/EKM keys mandated by the regime; and the continuous-monitoring view wired into the security operating model.

Real-world enterprise scenario

Helvetia HealthGrid (fictional) is a Swiss-headquartered digital-health platform, 2,400 employees, processing patient data across the EU and a growing US federal-research line of business. It is subject to GDPR, Swiss data-protection law, HIPAA for the US research data, and a contractual EU data-sovereignty requirement from several hospital customers. Its landing zone, built in Parts 1–3, has a folder hierarchy with a Platform folder, an EU clinical domain (dev/staging/prod), and a new US federal-research domain.

Organization Policy. The Platform team applies a baseline at the Org node: gcp.resourceLocations restricted to europe-* for the clinical domain (overridden to us-* only in the federal folder), compute.vmExternalIpAccess default-deny, storage.publicAccessPrevention and uniformBucketLevelAccess enforced, iam.disableServiceAccountKeyCreation on, iam.automaticIamGrantsForDefaultServiceAccounts disabled, and sql.restrictPublicIp enforced. Two Custom Org Policies (CEL) require Shielded GKE nodes and forbid Cloud SQL public IP estate-wide. Every constraint was rolled out via dry_run_spec for three weeks first; the dry-run logs surfaced 11 legacy public-IP VMs and 4 non-uniform buckets, all remediated before enforcement. All policy is Terraform (google_org_policy_policy, google_org_policy_custom_constraint).

VPC Service Controls. A single production service perimeter wraps the EU clinical prod projects plus the KMS key-management project. Access Context Manager access levels permit the corporate CIDRs and the SecOps device-trust posture; ingress rules admit the named GitHub Actions deployer principals and on-call admins; egress rules allow exactly one approved analytics-export project. API traffic is forced through restricted.googleapis.com via Private Google Access and a DNS override. The perimeter ran in dry-run for six weeks — the violation logs caught a nightly BigQuery export to an out-of-perimeter project, which was rebuilt as an egress rule before enforcement.

Security Command Center. SCC is activated at the Organization level at the Enterprise tier for Event Threat Detection, Container Threat Detection, and Attack Path Simulation. Findings stream via Pub/Sub into Google SecOps (Chronicle) and to Jira; Continuous Exports land in BigQuery for audit evidence. Mute rules suppress accepted sandbox findings. The team prioritizes off Attack Path Simulation, which flagged a medium-severity over-permissive firewall on a path to the clinical database as the top item that quarter.

CMEK. Data classified restricted (patient records) uses Cloud HSM keys; the EU-sovereignty hospital contracts mandate Cloud EKM with a Swiss-hosted Fortanix key manager so key material never resides in Google. Key rings live per region per env in a dedicated hhg-keymgmt project; per-service agents hold cryptoKeyEncrypterDecrypter on the specific keys; rotation is set to 90 days. gcp.restrictNonCmekServices mandates CMEK for Storage, BigQuery, and Cloud SQL, and gcp.restrictCmekCryptoKeyProjects locks CMEK keys to hhg-keymgmt. A documented key-disable runbook provides cryptographic shredding for offboarding a hospital tenant.

Assured Workloads. The US federal-research domain is created as an Assured Workloads workload under FedRAMP Moderate (with a path to HIPAA controls for the PHI subset). This auto-enforces US-region residency, US-personnel support access, and mandatory CMEK, and continuously monitors for drift. The EU clinical prod folder is additionally pinned with EU Regions & Support / EU Sovereign Controls so EU residency and EU-personnel access are Google-enforced, satisfying the hospital sovereignty clauses without the Platform team hand-building those personnel controls.

Measurable outcome (first two quarters). Preventive guardrails meant zero public buckets and zero public-IP Cloud SQL instances could be created (down from 9 such resources in the legacy estate). The VPC-SC perimeter blocked 3 real exfiltration attempts in dry-run analysis (misrouted exports + one stolen-credential test by the red team) before enforcement. SCC MTTR for high-severity findings fell to under 24 hours, and the CIS GCP compliance score rose from 71% to 96%. CMEK with EKM let them sign the two largest hospital sovereignty contracts, and the Assured Workloads FedRAMP folder turned an estimated two-quarter compliance build into a configured folder, passing the customer’s federal audit on first submission.

Going deeper

This section is for the reader who already knows the five sub-components and wants the internals, edge cases, and the caveats that bite in production.

The four enforcement planes — and why you need all of them

Newcomers picture “security” as one control. A GCP landing zone stacks four different kinds of enforcement that fail independently, so you run them together — plus a fifth, detective, plane over the top:

IAM (from Part 2) is the sixth plane — who may call the API at all. The most common design error is confusing planes: trying to “IAM-deny away” a resource shape (that’s Org Policy), or “org-policy away” a data-exfiltration path (that’s VPC-SC), or assuming CMEK makes data “more secure” (it changes control, not the cipher).

Org Policy internals — inheritance, merge, and the CEL edge

VPC-SC internals — spec vs status, bridges, and the DNS that makes it real

CMEK internals — envelope encryption, rotation, and the destroy window

SCC internals — inventory, finding lifecycle, and the tiers

Assured Workloads internals — what “sovereignty” actually constrains

Cost, quota, and latency edges

Practice challenges

Work these in a sandbox org, folder, or project you control. Placeholders (ORG_ID, POLICY_ID, PROJECT_NUMBER, KEYMGMT_PROJECT, service-account emails) are illustrative — substitute your own. Several controls (VPC-SC enforce, Assured Workloads) have real blast radius, so keep them in dry-run / a throwaway folder. Each solution notes the one idea it proves.

1. (Beginner) See which org policies actually apply to a project. Constraints inherit down the hierarchy, so the effective policy on a project is rarely what’s set on the project itself. List them.

<details> <summary>Solution</summary>

# All constraints in effect on the project (inherited + local):
gcloud org-policies list --project=PROJECT_ID

# Drill into one to see the effective value and where it came from:
gcloud org-policies describe storage.publicAccessPrevention \
  --project=PROJECT_ID --effective

Why: Org Policy is an inherited control — --effective shows the merged result after Org → folder → project, which is what the API actually enforces, not just the binding on the leaf. </details>

2. (Beginner) Enforce a boolean baseline constraint. Turn on storage.publicAccessPrevention at the org so no bucket anywhere can be made public.

<details> <summary>Solution</summary>

# publicaccess.yaml
name: organizations/ORG_ID/policies/storage.publicAccessPrevention
spec:
  rules:
    - enforce: true
gcloud org-policies set-policy publicaccess.yaml

Why: this is prevention at the configuration plane — the public bucket becomes impossible to create, rather than something SCC flags after the fact. Prevention first; detection catches the residue. </details>

3. (Intermediate) Roll out a residency constraint the safe way — dry-run, inspect, then enforce. Restrict resources to EU locations, but audit first so you find non-compliant resources before blocking anything.

<details> <summary>Solution</summary>

# locations-dryrun.yaml — AUDIT only: log would-be violations, block nothing.
name: organizations/ORG_ID/policies/gcp.resourceLocations
dryRunSpec:
  rules:
    - values:
        allowedValues:
          - in:eu-locations
gcloud org-policies set-policy locations-dryrun.yaml
# ...run for weeks, review OrgPolicyViolationInfo audit-log entries, remediate,
# then move the SAME rules from dryRunSpec: into spec: and re-apply to ENFORCE.

Why: dryRunSpec decouples “find what would break” from “start breaking things.” Every constraint added to a live estate goes through this — flipping straight to enforce is how you cause an outage. </details>

4. (Intermediate) Stream security findings to a SIEM and to BigQuery. Wire SCC so active high-severity findings reach Pub/Sub and every active finding lands in BigQuery for evidence.

<details> <summary>Solution</summary>

gcloud scc notifications create scc-high-findings \
  --organization=ORG_ID \
  --pubsub-topic=projects/SECOPS_PROJECT/topics/scc-findings \
  --filter='state="ACTIVE" AND severity="HIGH"'

gcloud scc bqexports create scc-bq-export \
  --organization=ORG_ID \
  --dataset=projects/SECOPS_PROJECT/datasets/scc_findings \
  --filter='state="ACTIVE"'

Why: SCC is org-scoped and its value is realized through export — a single normalized feed into SecOps/Splunk plus a durable BigQuery record is what turns detection into an operational and audit capability. </details>

5. (Advanced) Build a dry-run VPC-SC perimeter with a trusted access level. Wrap a project with restricted Storage/BigQuery/KMS, define a corporate-network access level, and allow one narrow ingress — all in dry-run.

<details> <summary>Solution</summary>

gcloud access-context-manager policies create --organization=ORG_ID --title="corp-policy"

gcloud access-context-manager levels create corp_network \
  --policy=POLICY_ID --title="Corp network" --basic-level-spec=access-level.yaml
# access-level.yaml: a list with one item →  - ipSubnetworks: [203.0.113.0/24]

gcloud access-context-manager perimeters dry-run create prod_data \
  --policy=POLICY_ID --title="Prod data perimeter" --perimeter-type=regular \
  --resources=projects/PROJECT_NUMBER \
  --restricted-services=storage.googleapis.com,bigquery.googleapis.com,cloudkms.googleapis.com

gcloud access-context-manager perimeters dry-run update prod_data \
  --policy=POLICY_ID --set-ingress-policies=ingress.yaml
# ...weeks of clean dry-run logs, then:  perimeters dry-run enforce prod_data --policy=POLICY_ID

Why: the perimeter blocks data movement, not identity — even valid IAM can’t exfiltrate across it. Building in dry-run first is mandatory because VPC-SC breaks cross-project API calls (CI, exports) you didn’t know existed. </details>

6. (Advanced) Make CMEK mandatory and prove it end-to-end. Create a rotating HSM key in a key-management project, grant only the BigQuery service agent, create a CMEK dataset, then enforce restrictNonCmekServices so a non-CMEK dataset can’t be created.

<details> <summary>Solution</summary>

gcloud kms keyrings create hhg-eu-prod --location=europe-west1 --project=KEYMGMT_PROJECT
gcloud kms keys create bq-cmek --location=europe-west1 --keyring=hhg-eu-prod \
  --project=KEYMGMT_PROJECT --purpose=encryption --protection-level=hsm \
  --rotation-period=90d --next-rotation-time=2026-10-01T00:00:00Z

gcloud kms keys add-iam-policy-binding bq-cmek \
  --location=europe-west1 --keyring=hhg-eu-prod --project=KEYMGMT_PROJECT \
  --member="serviceAccount:bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com" \
  --role="roles/cloudkms.cryptoKeyEncrypterDecrypter"

bq mk --dataset --default_kms_key=projects/KEYMGMT_PROJECT/locations/europe-west1/keyRings/hhg-eu-prod/cryptoKeys/bq-cmek \
  WORKLOAD_PROJECT:clinical_eu
# restrict-noncmek.yaml — then set-policy this to make CMEK mandatory for these services.
name: organizations/ORG_ID/policies/gcp.restrictNonCmekServices
spec:
  rules:
    - values:
        deniedValues: [bigquery.googleapis.com, storage.googleapis.com, sqladmin.googleapis.com]

Why: this is where CMEK and Org Policy compose — the key gives you the cryptographic off-switch, and restrictNonCmekServices makes bypassing it impossible. Only the service agent, never a human, holds encrypt/decrypt, preserving separation of duties. </details>

Common beginner mistakes

These are misconceptions, not typos — each is a wrong mental model that leads to a wrong design.

Deliverables & checklist

Common pitfalls

Glossary

Term Plain-language meaning
Organization Policy Service The plane that governs what configuration may exist on the hierarchy (Org/folder/project), enforced at resource create/modify time — independent of IAM.
Constraint A single Org Policy rule. List constraints allow/deny specific values (regions, domains); boolean constraints are on/off (e.g. disable SA keys).
Custom constraint An Org Policy rule you author in CEL (resource.<field> == …) against a supported resource type when no built-in constraint fits. ALLOW permits only when true; DENY rejects when true.
Effective policy The merged result of a constraint after Org → folder → project inheritance — what the API actually enforces on a given node.
Dry-run policy (dryRunSpec / dry_run_spec) An Org Policy mode that logs would-be violations without blocking, so you find non-compliant resources before enforcing.
VPC Service Controls (VPC-SC) A boundary around a set of projects across which data cannot move on the Google API surface unless a rule allows it — defence against exfiltration even with valid IAM.
Service perimeter The VPC-SC boundary itself; has an enforced status config and a proposed dry-run spec.
Perimeter bridge A link that lets two perimeters share member projects wholesale (wider blast radius than an ingress/egress rule).
Access Context Manager The service that defines access levels (trusted context) used by VPC-SC ingress rules and by context-aware access.
Access level A named description of trusted context — IP CIDRs, region, device posture, or identities — attached as a VPC-SC ingress condition.
Ingress / egress policy VPC-SC rules for who/what may enter the perimeter and what may leave, keyed on identity + project + service + method.
restricted.googleapis.com The restricted VIP (199.36.153.4/30) that resolves only to VPC-SC-aware APIs; with Private Google Access + DNS it keeps API traffic off the public path.
Security Command Center (SCC) The org-scoped detective/posture platform aggregating misconfigurations, vulnerabilities, and threats as normalized findings.
Security Health Analytics SCC’s built-in CSPM detector — flags public buckets, open firewalls, disabled logging, non-CMEK resources against benchmarks like CIS GCP.
Event / Container / VM Threat Detection SCC threat detectors that mine audit logs (ETD) and runtime behaviour (CTD/VMTD) for IOCs, anomalous grants, crypto-mining, reverse shells.
Attack Path Simulation A Premium/Enterprise SCC feature that walks the asset graph from internet-exposed nodes to high-value assets and scores exposure, for prioritization.
Finding A single normalized SCC issue with a severity and a lifecycle: ACTIVE, INACTIVE (resolved), or muted (accepted-risk, hidden but not fixed).
Mute rule An SCC rule that suppresses a class of accepted-risk findings from the default view — muting is not resolving.
Cloud Asset Inventory (CAI) The near-real-time asset graph under SCC that answers “what do we have, where, and how exposed.”
CMEK Customer-Managed Encryption Keys — you own the key-encryption key in Cloud KMS/HSM/EKM and control its IAM, rotation, and lifecycle.
Cloud KMS Google’s key-management service that holds your CryptoKeys and performs wrap/unwrap on behalf of CMEK-using services.
Key ring / CryptoKey / key version KMS containers: a key ring (regional) holds CryptoKeys; each key has versions; rotation makes a new version for new writes without re-encrypting old data.
Protection level SOFTWARE (KMS), HSM (Cloud HSM, FIPS 140-2 L3), or EXTERNAL/EKM (key material outside Google) — chosen per data class.
Cloud EKM External Key Manager — CMEK where the key material lives at a partner (Fortanix, Thales) or your own manager; Google never holds the key.
Envelope encryption Your CMEK (a KEK) wraps per-object data-encryption keys (DEKs); the service unwraps the DEK via KMS on read.
Cryptographic shredding Rendering data permanently inaccessible by disabling/destroying the key — a control independent of the data service’s own IAM.
Service agent A Google-managed per-service identity (e.g. …@bigquery-encryption.iam.gserviceaccount.com) that must hold cryptoKeyEncrypterDecrypter on the specific CMEK key.
restrictNonCmekServices / restrictCmekCryptoKeyProjects Org Policy list constraints that make CMEK mandatory for named services, and restrict which projects may supply CMEK keys.
Assured Workloads A folder bound at creation to a compliance/sovereignty regime; Google continuously enforces residency, products, encryption, and personnel controls beneath it.
Compliance regime The standard a workload is pinned to — FedRAMP Mod/High, IL4/IL5, CJIS, HIPAA, ITAR, EU Regions & Support / EU Sovereign Controls, Canada, etc.
Data residency The requirement that resources only be created/stored in approved regions — enforced by gcp.resourceLocations and by Assured Workloads.
Personnel / support access The sovereignty control over which Google support staff (by geography/vetting) may access data — enforceable only via Assured Workloads, not Org Policy.
Access Approval / Key Access Justifications Controls that make you approve each Google support access, and that can require a signed justification for every key-unwrap.
Defence in depth Layering independent controls (config, context, crypto, regime, detection) so no single failure exposes the data.

What’s next

With preventive guardrails, the data-exfiltration perimeter, posture detection, customer-controlled keys, and sovereignty regimes in place, Part 5 — Logging, Monitoring & Operations designs the org-wide log sinks, the security/audit log architecture, monitoring, and the operational runbooks that keep the landing zone observable and accountable.

GCPLanding ZoneSecurity & GuardrailsEnterprise
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments