# GCP Associate Cloud Engineer (ACE) — Part 1: Fundamentals, Resource Hierarchy & Cloud Identity

> **Series:** GCP Associate Cloud Engineer (ACE) (1 of 8)
> **Part 1:** This file (Fundamentals, Resource Hierarchy & Cloud Identity)
> **Part 2:** `02-billing-and-gcloud-tooling.md` (Billing, gcloud CLI & Cloud Tooling)
> **Part 3:** `03-iam-and-identity.md` (IAM & Identity)
> **Part 4:** `04-compute-engine-and-autoscaling.md` (Compute Engine & Autoscaling)
> **Part 5:** `05-gke-and-serverless.md` (GKE, Serverless & the Agent Platform)
> **Part 6:** `06-storage-and-managed-databases.md` (Storage & Managed Databases)
> **Part 7:** `07-networking-fundamentals.md` (Networking Resources)
> **Part 8:** `08-monitoring-logging-and-operations.md` (Monitoring, Logging & Operations)
> **Questions:** `questions.md`

## Table of Contents

1. [Why This Course Exists](#why-this-course-exists)
2. [Meet Meridian Logistics](#meet-meridian-logistics)
3. [How GCP's Geography Differs From AWS's and Azure's](#how-gcps-geography-differs-from-awss-and-azures)
4. [The Project: GCP's Real Unit of Isolation](#the-project-gcps-real-unit-of-isolation)
5. [The Resource Hierarchy: Organization, Folders, and Projects](#the-resource-hierarchy-organization-folders-and-projects)
6. [Standalone Organizations vs. Domain-Linked Organizations](#standalone-organizations-vs-domain-linked-organizations)
7. [Three More Day-Zero Considerations: IAM, Observability, and Networking](#three-more-day-zero-considerations-iam-observability-and-networking)
9. [Organization Policies: Guardrails, Inheritance, and Dry-Run Mode](#organization-policies-guardrails-inheritance-and-dry-run-mode)
10. [The Architecture Framework and the Shared Responsibility Model](#the-architecture-framework-and-the-shared-responsibility-model)
11. [Labels, Network Tags, and Resource Manager Tags](#labels-network-tags-and-resource-manager-tags)
12. [Cloud Identity: Manual and Automated User and Group Management](#cloud-identity-manual-and-automated-user-and-group-management)
13. [APIs and Services: Explicit Enablement Required](#apis-and-services-explicit-enablement-required)
14. [Quotas and Essential Contacts](#quotas-and-essential-contacts)
15. [Cloud Asset Inventory and Gemini Cloud Assist](#cloud-asset-inventory-and-gemini-cloud-assist)
16. [Workforce Identity Federation: A First Look](#workforce-identity-federation-a-first-look)
17. [A Full Worked Landing Zone Bootstrap](#a-full-worked-landing-zone-bootstrap)
18. [Real-World Scenario: The Region-Lock Policy That Almost Blocked a Disaster Recovery Test](#real-world-scenario-the-region-lock-policy-that-almost-blocked-a-disaster-recovery-test)
19. [Second Real-World Scenario: The Dry-Run Policy That Caught a Shadow Project](#second-real-world-scenario-the-dry-run-policy-that-caught-a-shadow-project)
20. [Part 1 gcloud Cheat Sheet](#part-1-gcloud-cheat-sheet)
21. [Pre-Flight Checklist: Is a New GCP Environment Actually Ready?](#pre-flight-checklist-is-a-new-gcp-environment-actually-ready)
22. [Common Mistakes and Interview Traps](#common-mistakes-and-interview-traps)
23. [Worked Practice Problems](#worked-practice-problems)
24. [Summary and What's Next](#summary-and-whats-next)

## Why This Course Exists

**This course teaches the operational core of Google Cloud that every other GCP specialization builds on top of.** Google Cloud Platform (GCP) is Google's public cloud: compute, storage, networking, and managed data services rented by the hour instead of bought as hardware. Whether you end up doing CI/CD pipelines, network engineering, or security work on GCP, you will spend every working day inside the resource hierarchy, IAM, compute, storage, and networking primitives this course covers.

This is the first of six GCP courses on this site, each aligned to a real Google Cloud certification so the depth you build has an external, verifiable checkpoint:

| Course | Certification | Focus |
|---|---|---|
| **1. GCP Associate Cloud Engineer (ACE)** (this one) | Associate Cloud Engineer (ACE) | Projects, IAM, compute, storage, networking, day-2 operations |
| 2. GCP DevOps & CI/CD Platform | Professional Cloud DevOps Engineer (PCDE), part 1 | CI/CD pipelines, GitOps, secrets, supply-chain security |
| 3. GCP SRE & Observability | Professional Cloud DevOps Engineer (PCDE), part 2 | SLOs, error budgets, telemetry, FinOps |
| 4. GCP Network Engineering | Professional Cloud Network Engineer (PCNE) | VPC design, hybrid connectivity, network security |
| 5. GCP Security Engineering | Professional Cloud Security Engineer (PCSE) | Identity, perimeters, encryption, detection, compliance |
| 6. GCP Architecture & Design | Professional Cloud Architect (PCA) | End-to-end solution design, migration, operational excellence |

The Associate Cloud Engineer exam this course targets is a 2-hour, 50 to 60 question exam, delivered through Pearson VUE (either an online-proctored session or a test center), covering four weighted domains straight from Google's own exam guide:

| Domain | Weight | This series' chapters |
|---|---|---|
| 1. Setting up a cloud solution environment | ~20% | Part 1 (this chapter), Part 2, Part 3 |
| 2. Planning and implementing a cloud solution | ~30% | Part 4, Part 5, Part 6, Part 7 |
| 3. Ensuring the successful operation of a cloud solution | ~30% | Part 4 through Part 8 (the management half of each) |
| 4. Configuring access and security | ~20% | Part 3 |

> [!NOTE]
> Google refreshes the ACE exam guide roughly once a year to track what's actually shipping in the console, and the most recent refresh leans hard into AI-assisted operations: Gemini Cloud Assist, Gemini CLI, and the Agent Runtime on the Gemini Enterprise Agent Platform (the renamed Vertex AI Agent Engine) all now appear as testable considerations, alongside newer infrastructure products like Cloud Hyperdisk, Cloud NGFW, and Google Cloud Managed Lustre. This course was written against that current guide, not an older cram-sheet version circulating online. If you've studied from a source that only mentions four bullet points under "monitoring and logging," it's out of date.

If you've already worked through this site's AWS Cloud Architecture series, you'll recognize the shape of a lot of this: a resource hierarchy, an IAM system, compute/storage/network primitives. GCP's underlying decisions are different enough (a genuinely different resource model, a differently-shaped IAM, per-project rather than per-account billing) that porting AWS mental models directly onto GCP is one of the most common ways experienced cloud engineers stumble on their first GCP project. This course calls out those differences explicitly wherever they matter.

🎯 By the end of this chapter, you'll be able to stand up a correctly structured GCP resource hierarchy (organization, folders, projects, org policies, and identity), the same foundation a real platform team lays before any workload goes on top of it.

## Meet Meridian Logistics

Every example in this eight-part course follows one running system: **Meridian Logistics**, a mid-size freight and warehousing company migrating its dispatch, inventory, and route-optimization workloads onto GCP. Meridian has three business units (Freight, Warehousing, and a small internal Data Science team), a compliance obligation to keep EU customer data in EU regions, and roughly 40 engineers who will eventually touch this platform. You'll see Meridian's organization, folder structure, IAM groups, and workloads evolve chapter by chapter, rather than a fresh throwaway example in every section.

## How GCP's Geography Differs From AWS's and Azure's

**GCP organizes physical infrastructure into regions and zones, and being explicit about which one a resource lives in is a first-class design decision, not an afterthought.** A **region** (`us-central1`, `europe-west1`) is an independent geographic area; a **zone** (`us-central1-a`) is an isolated deployment area inside a region, typically mapped to a distinct physical facility with its own power and cooling. Resources in different zones within the same region get low-latency networking between them but independent failure domains: a power event in `us-central1-a` shouldn't touch `us-central1-b`.

> [!TIP]
> **Best Practice: verify product availability by region before you design, not after.** Not every GCP product ships in every region on day one; a new machine type or a managed service can be region-limited for months. Check the [Google Cloud locations page](https://cloud.google.com/about/locations) for the specific product and region combination you're planning around, rather than assuming parity across regions the way you might with a more mature AWS service. Getting this wrong late in a project means an unplanned region change to a design that already has firewall rules, IAM bindings, and DNS records built around the original region.

| Concept | AWS | Azure | GCP | Where the mapping breaks down |
|---|---|---|---|---|
| Account/subscription boundary | Account | Subscription | Project | GCP projects are cheaper to create and expected to be numerous (one per environment per team is common); AWS accounts and Azure subscriptions are usually provisioned more sparingly |
| Top-level grouping | Organization (via AWS Organizations) | Management Group | Organization | GCP's Organization node is optional; a standalone project with no Organization is a valid, common setup for a small team |
| Billing unit | Consolidated billing family | Subscription (billing scope) | Billing account, linked to N projects | GCP billing accounts and projects are separate resources you explicitly link; billing isn't automatically tied to the org hierarchy the way an AWS Organizations payer account is |
| Isolation boundary for a workload | Account | Resource Group + Subscription | Project | A GCP project bundles IAM, billing, quotas, and APIs into one atomic boundary; there's no separate "resource group" layer nested inside it |

## The Project: GCP's Real Unit of Isolation

If you remember one structural fact from this chapter, make it this one: **the project is where GCP's IAM, billing, quotas, and API enablement all actually attach.** Everything else (organizations, folders) exists to organize projects, not to hold resources directly. A Compute Engine VM, a Cloud Storage bucket, a BigQuery dataset: all of them live inside exactly one project.

Every project has three identifiers, and mixing them up is a common early mistake:

- **Project ID**: globally unique, immutable, used in API calls and resource URLs (`meridian-freight-prod-8f2k`).
- **Project name**: a display label, mutable, not unique (`Meridian Freight Production`).
- **Project number**: an internally generated numeric ID, also immutable, used by some Google APIs internally.

⚙️ A project's `deletion protection` behavior deserves a specific callout: deleting a project doesn't happen instantly. It schedules a 30-day soft-delete window during which the project (and everything in it) can still be restored, then a permanent purge. This is a genuine safety net, but it's also a real cost trap: a "deleted" project with an attached billing account can keep accruing charges on any resource with its own independent billing cycle (a reserved commitment, for instance) until the purge actually completes.

## The Resource Hierarchy: Organization, Folders, and Projects

The **resource hierarchy** is GCP's tree structure for attaching IAM policies and organization policies at a single point and having them flow down to everything beneath. At the root sits (optionally) an **Organization**, representing the company; below it, **Folders** group related projects (by business unit, environment, or team); at the leaves, **Projects** hold the actual resources.

```mermaid
flowchart TD
    Org(["Organization<br/>meridianlogistics.com"]) --> FolderProd["Folder: Production"]
    Org --> FolderNonProd["Folder: Non-Production"]
    Org --> FolderShared["Folder: Shared Services"]
    FolderProd --> ProjFreightProd[("meridian-freight-prod")]
    FolderProd --> ProjWarehouseProd[("meridian-warehouse-prod")]
    FolderNonProd --> ProjFreightDev[("meridian-freight-dev")]
    FolderNonProd --> ProjFreightStaging[("meridian-freight-staging")]
    FolderShared --> ProjNetworking[("meridian-shared-vpc")]
    FolderShared --> ProjLogging[("meridian-logging-sink")]

    classDef org fill:#f0e9fb,stroke:#6d43c0,color:#10161c
    classDef folder fill:#e5f0fa,stroke:#1d6fb8,color:#10161c
    classDef prod fill:#e5f5ea,stroke:#1f8a4c,color:#10161c
    classDef nonprod fill:#fbeee0,stroke:#b8650f,color:#10161c
    classDef shared fill:#e9eafb,stroke:#4550c4,color:#10161c
    class Org org
    class FolderProd,FolderNonProd,FolderShared folder
    class ProjFreightProd,ProjWarehouseProd prod
    class ProjFreightDev,ProjFreightStaging nonprod
    class ProjNetworking,ProjLogging shared
```

Notice that the folder split is by lifecycle stage first (Production vs. Non-Production), with Shared Services carved out separately for cross-cutting infrastructure like the Shared VPC and the central logging sink; a role granted at the `Production` folder reaches every project beneath it without a second grant.

A few structural rules worth internalizing:

- A **folder** can contain other folders, projects, or both, up to 10 levels deep in practice (Google's documented limit is generous enough that you will not hit it with a sane structure).
- A **project** can have exactly one parent (an organization, a folder, or nothing at all if it's standalone).
- Moving a project between folders is a real operation with real IAM consequences: it inherits the new parent's org policies and any IAM roles bound at that level, and loses inherited roles from the old parent.

> [!WARNING]
> **From the Trenches:** a platform team at a logistics company (not Meridian, a real prior engagement) reorganized their folder tree during a security audit, moving a dozen projects from a flat structure into environment-based folders. Two projects landed under a folder with an inherited `constraints/iam.disableServiceAccountKeyCreation` policy that the flat structure had never enforced. The immediate symptom was a CI pipeline failing overnight with `PERMISSION_DENIED` on a service account key rotation job. The immediate cause was the new folder's inherited policy. The underlying condition that made it likely: nobody had run a policy-impact dry run (see the dry-run section below) before the move, because dry-run mode for org policies didn't exist yet at the time and nobody had built an equivalent pre-check into their own change process. A folder move is an IAM and policy event, not just a cosmetic reorg, and needs the same pre-flight review as a permission change.

## Standalone Organizations vs. Domain-Linked Organizations

For years, creating a GCP Organization required Cloud Identity or Google Workspace tied to a verified DNS domain: your organization node was, structurally, an extension of your Workspace tenant. That's still the default and the most common setup for an established company. But GCP also supports **standalone organizations**, created automatically the moment you sign up for Google Cloud with a Google email address, with no Cloud Identity super-admin role and no domain verification required.

| | Domain-linked organization | Standalone organization |
|---|---|---|
| Requires Cloud Identity / Workspace | Yes | No |
| Requires DNS domain verification | Yes | No |
| Organization owners can be federated identities | Limited | Yes |
| Organization can be deleted and later restored | No | Yes |
| Typical fit | An established company consolidating existing Workspace users | A startup, a lab, or a team that wants org-level policy controls without standing up Workspace first |

**Choose a standalone organization when** you want organization policies, folders, and centralized billing before you're ready to commit to a Workspace/Cloud Identity rollout, and you're comfortable managing organization-owner access through federated or individual Google accounts instead of a directory. **Choose a domain-linked organization when** your company already runs Google Workspace (or plans to), since it gives you Cloud Identity's user/group management for free and keeps a single source of truth for who's employed where.

💡 A subtlety that trips up engineers moving from AWS: an AWS account with no AWS Organizations membership is still a fully functional, billable account. A GCP project with no Organization above it is exactly the same: fully functional, billable, and IAM-capable. The Organization node is an organizing and policy-enforcement layer, not a requirement for a project to exist.

## Three More Day-Zero Considerations: IAM, Observability, and Networking

The ACE exam guide's "setting up cloud projects and accounts" domain lists three considerations this chapter has only touched in passing so far, each of which gets a full chapter later in this series but still deserves a first, working mental model now.

**Granting IAM roles within a project** happens the moment a project exists, not as an afterthought: the account that creates a project is automatically bound to `roles/owner` on it, and every subsequent teammate needs an explicit role grant (`gcloud projects add-iam-policy-binding PROJECT_ID --member=group:TEAM@meridianlogistics.com --role=roles/editor`) before they can touch anything inside it. Part 3 covers the full role taxonomy (basic, predefined, custom) and how bindings compose with org-policy inheritance; for now, the operating rule is the one from the Cloud Identity section above: **bind roles to groups, check the binding immediately after project creation, and never leave a fresh project owned only by the individual who happened to run the create command.**

**Provisioning Google Cloud Observability** (the current name for what was long called the "operations suite," covering Cloud Monitoring, Cloud Logging, Cloud Trace, and Cloud Profiler together) isn't something you manually turn on the way you enable a compute API: every project gets a default Monitoring workspace and a default Logging bucket the moment resources start generating telemetry. What *is* a real day-zero decision is where that telemetry ultimately lives: a small team might accept the per-project default, while Meridian's platform team instead provisions a dedicated aggregation project (`meridian-logging-sink` from the resource hierarchy diagram above) and routes every other project's logs and metrics into it via an aggregated log sink, so no single workload project's IAM boundary also gates who can see production telemetry. Part 8 covers log routers, log buckets, and Managed Service for Prometheus in full depth.

**Setting up cloud networking** at project creation is mostly a decision about the network that already exists: every new project ships with a **default VPC** in auto mode (one subnet per region, broad default firewall rules allowing internal traffic and SSH/RDP from anywhere). Leaving the default VPC in place past initial experimentation is a common early mistake, since its permissive default firewall rules are far wider than any real workload needs; most production setups delete the default VPC entirely and build a deliberate custom-mode VPC instead. Part 7 is where the actual subnet design, firewall policy, and Shared VPC architecture live; the day-zero action worth remembering here is simply **don't build production resources against the auto-created default VPC.**

## Organization Policies: Guardrails, Inheritance, and Dry-Run Mode

**IAM answers "who can do what"; organization policies answer "what's allowed to exist at all," regardless of who's asking.** An org policy is a **constraint** (`constraints/compute.vmExternalIpAccess`, `constraints/iam.allowedPolicyMemberDomains`) applied at the organization, folder, or project level, restricting a resource property even for a project owner with full IAM permissions.

Org policies **inherit down the hierarchy** by default: a constraint set at the Organization node applies to every folder and project beneath it unless a lower node explicitly overrides it (and only some constraints allow overriding at all). This is the mechanism behind the region-lock scenario later in this chapter.

The 2026 addition worth knowing well for the exam is **dry-run mode**: you can attach a policy to a resource with `enforced: false` in a separate dry-run slot, and GCP evaluates it against real activity without actually blocking anything, surfacing violations you'd have hit if the policy were live. This closes a long-standing gap where the only way to know if a new org policy would break something was to enable it and find out.

```mermaid
flowchart TD
    Change["Engineer requests a new resource<br/>e.g. a VM with an external IP"] --> Eval{"Evaluate org policy<br/>at this resource"}
    Eval -->|"Live policy set"| LiveCheck{"Does it violate<br/>the live policy?"}
    LiveCheck -->|"Yes"| Block["Request rejected<br/>immediately"]
    LiveCheck -->|"No"| Allow["Request proceeds"]
    Eval -->|"Dry-run policy set"| DryCheck{"Would it violate<br/>the dry-run policy?"}
    DryCheck -->|"Yes"| LogViolation["Violation logged,<br/>request still proceeds"]
    DryCheck -->|"No"| Allow

    classDef crit fill:#fbe8e6,stroke:#b3261e,color:#10161c
    classDef ok fill:#e5f5ea,stroke:#1f8a4c,color:#10161c
    classDef warn fill:#fbeee0,stroke:#b8650f,color:#10161c
    class Block crit
    class Allow ok
    class LogViolation warn
```

**Caption:** a dry-run policy never blocks a request; it only logs what it would have blocked, which is exactly what makes it safe to attach to an entire organization before you're confident about the blast radius.

> [!TIP]
> **Best Practice: every new org-wide constraint goes through a dry-run period before enforcement, no exceptions for constraints that feel obviously safe.** A constraint that looks harmless in isolation (say, `constraints/compute.requireOsLogin`) can still break an automation account that authenticates a different way than you expect. A one-to-two-week dry-run window against real traffic catches this before it becomes an incident.

Common constraints worth knowing cold for the exam:

| Constraint | What it restricts |
|---|---|
| `constraints/iam.disableServiceAccountKeyCreation` | Blocks creation of new, long-lived service account JSON keys |
| `constraints/compute.vmExternalIpAccess` | Restricts which VMs may have an external IP address |
| `constraints/compute.restrictLoadBalancerCreationForTypes` | Limits which load balancer types can be created |
| `constraints/iam.allowedPolicyMemberDomains` | Restricts IAM grants to members from specific Cloud Identity/Workspace domains |
| `constraints/gcp.resourceLocations` | Restricts which regions resources can be created in |

## The Architecture Framework and the Shared Responsibility Model

Google publishes the **Cloud Architecture Framework** (pillars: operational excellence, security/privacy/compliance, reliability, cost optimization, performance optimization) as its own opinionated best-practices reference, roughly analogous to AWS's Well-Architected Framework. You won't be quizzed on framework trivia for the ACE exam, but the **shared responsibility model** underneath it is directly testable: Google secures the physical infrastructure, the hypervisor, and (for managed services) increasingly more of the stack, while you remain responsible for IAM configuration, data classification, and anything you deploy on top.

```mermaid
quadrantChart
    title Shared responsibility by compute model
    x-axis Google manages less --> Google manages more
    y-axis You manage less --> You manage more
    quadrant-1 You own most of the stack
    quadrant-2 Balanced, shared control
    quadrant-3 Google owns most of the stack
    quadrant-4 Rare combination
    Compute Engine:::vm: [0.2, 0.85]
    GKE Standard:::gke: [0.45, 0.65]
    GKE Autopilot:::gke: [0.6, 0.45]
    Cloud Run:::serverless: [0.8, 0.25]
    Cloud Run functions:::serverless: [0.9, 0.15]

    classDef vm color: #b8650f, radius: 9
    classDef gke color: #1d6fb8, radius: 9
    classDef serverless color: #1f8a4c, radius: 9
```

**Caption:** moving right along the x-axis, Google absorbs more of the operational burden (patching, scaling, node management); Compute Engine sits at the "you manage everything above the hypervisor" end, Cloud Run functions at the "you manage only your code" end.

## Labels, Network Tags, and Resource Manager Tags

GCP has three different metadata mechanisms that get confused constantly, and the exam will test whether you know which is which:

| Mechanism | Applies to | Format | Used for |
|---|---|---|---|
| **Labels** | Almost any resource | Key-value pairs, up to 64 per resource | Cost allocation, filtering in Cloud Billing reports, inventory queries |
| **Network tags** | Compute Engine instances | Plain strings, no key-value structure | Targeting firewall rules and routes at specific instances |
| **Resource Manager tags** | Organizations, folders, projects (and, newer, some resource types) | Key-value pairs backed by an org-level tag key/value schema, with IAM conditions | Conditional IAM bindings and org-policy targeting based on tag value |

⚠️ The trap: **network tags look like labels but are not** (they're unstructured strings used purely for firewall/route targeting, with no billing or inventory role), and **Resource Manager tags look like labels but have IAM and org-policy teeth** (a tag binding can be referenced inside an IAM Conditions expression, letting you grant a role only to resources carrying a specific tag value). Confusing "tag" and "label" here is one of the most common ACE exam trap categories.

## Cloud Identity: Manual and Automated User and Group Management

**Cloud Identity is Google's identity directory layer, separate from GCP itself: it manages users and groups, while GCP's IAM manages what those users and groups can do.** You can add users manually one at a time in the Google Admin console, or (the far more common real-world pattern past a handful of users) automate provisioning from an external identity provider.

The current automated path runs through **SCIM (System for Cross-domain Identity Management)**: your IdP (Okta, Azure AD, a homegrown HR system) pushes user and group lifecycle events, create, update, deactivate, to Cloud Identity's SCIM API, keeping the directory in sync without a human manually mirroring an HR system into the Admin console.

```mermaid
sequenceDiagram
    participant HR as HR system
    participant IdP as Identity provider (Okta)
    participant SCIM as Cloud Identity SCIM API
    participant CI as Cloud Identity directory
    participant IAM as Project IAM policies

    HR->>IdP: New hire record created
    IdP->>SCIM: POST /Users (SCIM create)
    SCIM->>CI: Provision user account
    CI-->>IAM: Group membership evaluated<br/>for existing IAM bindings
    Note over HR,IAM: Employee leaves the company
    HR->>IdP: Termination event
    IdP->>SCIM: PATCH /Users/{id} (active: false)
    SCIM->>CI: Deactivate account
    CI-->>IAM: Access revoked at every project<br/>where a role was bound to this user
```

**Caption:** the deactivation path matters as much as provisioning: a SCIM-managed offboarding revokes GCP access the moment the IdP fires the termination event, without anyone needing to remember GCP is one of the systems that needs manual cleanup.

Groups deserve particular attention because **granting IAM roles to a Cloud Identity group, not individual users, is the standard practice for anything beyond a two-person team.** A role bound to `gcp-freight-team@meridianlogistics.com` updates automatically as people join or leave the group; a role bound to twelve individual email addresses needs twelve manual edits every time the team's roster changes.

> [!WARNING]
> **From the Trenches:** a mid-size company's platform team once had a contractor's Cloud Identity account survive for eleven days past their contract end date. The immediate symptom, caught during a routine access review, was an active session from an IP address that didn't match any employee's known location. The immediate cause was that the contractor's offboarding was tracked in a spreadsheet, not the IdP, so no SCIM deactivation event ever fired. The underlying condition: the company had SCIM wired up for full-time employees but handled contractors through a separate, manual process that nobody had audited against the actual GCP group memberships in over a year. The fix wasn't a GCP setting; it was routing every access type, contractor included, through the one identity source that actually triggers deprovisioning.

## APIs and Services: Explicit Enablement Required

Unlike some clouds where a service is simply available the moment you have an account, **every GCP API must be explicitly enabled per project** before you can call it, whether through the console, `gcloud services enable compute.googleapis.com`, or Terraform's `google_project_service` resource. This is a deliberate friction point: it keeps a project's enabled-API surface visible and auditable, and it's the first thing to check when a `PERMISSION_DENIED` or `API_NOT_ENABLED` error shows up on an otherwise correctly IAM-permissioned call.

🔍 **Diagnostic habit worth building now**: when a gcloud or Terraform command fails with an API-shaped error, check `gcloud services list --enabled --project=PROJECT_ID` before touching IAM at all. Half of "permission" errors in a fresh project are actually enablement errors wearing a permission-shaped message.

## Quotas and Essential Contacts

**Quotas** cap how much of a given resource a project can consume (VM vCPUs per region, API requests per minute, in-use IP addresses), protecting both Google's infrastructure and you from a runaway script accidentally spinning up unbounded resources. Quotas are checked via `gcloud compute regions describe REGION --project=PROJECT_ID` or the Quotas page in the console, and increases are requested (not guaranteed) through the same page, with turnaround ranging from instant to a multi-day manual review depending on the quota and the size of the increase.

**Essential Contacts** is the companion feature worth knowing: instead of relying on whoever happens to be a project IAM member with an email notification preference set, you configure specific email addresses to receive specific categories of Google-initiated notification (billing, security, technical, legal), so a critical notice about an expiring TLS certificate or a billing anomaly reaches the right inbox even if the person who set up the project has since left the team.

## Cloud Asset Inventory and Gemini Cloud Assist

**Cloud Asset Inventory (CAI)** is GCP's queryable, historical record of every resource and every IAM policy across your resource hierarchy, refreshed continuously and retained for search-back queries. Where the Cloud Console shows you the current state of one project at a time, CAI answers organization-wide questions: "which service accounts across every project have `roles/owner`," or "what did this project's IAM policy look like three days ago, before the incident."

**Gemini Cloud Assist** is Google's console-embedded AI assistant, and it consumes CAI data directly (via the `Cloud Asset Viewer` IAM role) to answer natural-language questions about your actual environment, not generic GCP documentation. Asking it "why is this VM unreachable" pulls real firewall rules, real routes, and real IAM bindings for that specific instance into its answer, rather than a canned troubleshooting checklist.

> [!NOTE]
> Gemini Cloud Assist's chat panel is enabled per-project once you turn on the `geminicloudassist.googleapis.com` API; as of an April 2026 rollout, Google auto-enabled this API for any project that had already been using the chat panel and had the underlying Cloud AI Companion API on, so don't be surprised if you find it already active on an existing project without having explicitly enabled it yourself.

## Workforce Identity Federation: A First Look

**Workforce Identity Federation lets your existing corporate identity provider authenticate users directly into Google Cloud, without ever creating a Cloud Identity or Google Workspace account for them.** A user signs into their own IdP (Okta, Azure AD, any OIDC or SAML 2.0 provider); Google Cloud trusts an assertion from that IdP, maps it into a **workforce identity pool**, and grants access according to IAM bindings on that pool, all without a corresponding Cloud Identity user object ever existing.

This matters most for organizations that don't want (or can't justify) standing up Cloud Identity purely to give a subset of contractors, partners, or acquired-company employees console access. It requires an Organization resource, the IAM and Resource Manager APIs enabled, and an identity pool/provider configuration; Part 3 covers the deeper mechanics (attribute mapping, condition expressions, and how it differs from Workload Identity Federation for workloads) once you have the full IAM model in hand.

## A Full Worked Landing Zone Bootstrap

Putting the whole chapter together, here's the actual sequence Meridian's platform team runs to bootstrap a new environment, as real `gcloud` commands:

```bash
# 1. Create the folder structure under the existing organization
gcloud resource-manager folders create \
  --display-name="Production" \
  --organization=123456789012

gcloud resource-manager folders create \
  --display-name="Non-Production" \
  --organization=123456789012

# 2. Create a project inside the Production folder
gcloud projects create meridian-freight-prod-8f2k \
  --folder=FOLDER_ID \
  --name="Meridian Freight Production"

# 3. Link billing before anything else fails silently on a billing check
gcloud billing projects link meridian-freight-prod-8f2k \
  --billing-account=012345-6789AB-CDEF01

# 4. Enable the APIs this project will actually need
gcloud services enable \
  compute.googleapis.com \
  container.googleapis.com \
  cloudresourcemanager.googleapis.com \
  --project=meridian-freight-prod-8f2k

# 5. Attach a dry-run org policy for two weeks before enforcing region-lock
gcloud org-policies set-policy region-lock-dry-run.yaml \
  --project=meridian-freight-prod-8f2k

# 6. Label the project for cost allocation from day one
gcloud alpha projects update meridian-freight-prod-8f2k \
  --update-labels=business-unit=freight,environment=production
```

`region-lock-dry-run.yaml` for step 5:

```yaml
name: projects/meridian-freight-prod-8f2k/policies/gcp.resourceLocations
spec:
  rules:
    - values:
        allowedValues:
          - in:us-locations
          - in:eu-locations
  dryRunSpec:
    rules:
      - values:
          allowedValues:
            - in:eu-locations
```

This attaches the real `gcp.resourceLocations` constraint as a live policy allowing both US and EU regions, while simultaneously running a stricter EU-only version in dry-run, letting the team observe two weeks of real deployment activity against the stricter rule before deciding whether to enforce it.

## Real-World Scenario: The Region-Lock Policy That Almost Blocked a Disaster Recovery Test

Meridian's compliance team mandated an `EU-locations` org policy on the folder holding all customer-data projects, correctly enforcing GDPR data residency. Eighteen months later, the SRE team scheduled a disaster recovery test that would fail over Meridian's EU customer database to a `us-central1` replica, a deliberate, temporary, approved exception to validate the DR runbook actually worked.

The test failed at the very first step: `gcloud sql instances create meridian-eu-dr-replica --region=us-central1` was rejected outright by the inherited `gcp.resourceLocations` constraint, because DR testing had never been considered when the policy was written. The fix wasn't disabling the policy (unacceptable for a live compliance control); it was creating a dedicated `dr-testing` project outside the EU-locked folder, with its own narrower, time-boxed IAM grants, specifically carved out of the resource hierarchy so the org policy's inheritance never applied to it in the first place. The lesson that made it into Meridian's own internal runbook: **any org policy with a compliance justification needs an explicitly designed exception path decided in advance, not discovered during an incident or a test.**

## Second Real-World Scenario: The Dry-Run Policy That Caught a Shadow Project

Six months after adopting dry-run mode, Meridian's platform team wanted to roll out `constraints/iam.disableServiceAccountKeyCreation` organization-wide, eliminating long-lived JSON service account keys in favor of Workload Identity Federation. Rather than enforcing it directly, they attached it in dry-run mode at the Organization node and let it run for two weeks.

The dry-run logs surfaced one unexpected violation: a data science analyst had created a personal project (outside any documented folder) with a service account key downloaded to their laptop, feeding a personal Python script that pulled BigQuery data into a local notebook for exploratory analysis. No incident had occurred yet, but the pattern (a long-lived credential on an unmanaged laptop, outside any folder structure, invisible to the team's existing Cloud Asset Inventory dashboards because nobody had thought to query for it) was exactly the kind of exposure the constraint was designed to prevent. The team enforced the policy immediately once the dry-run window closed, migrated the analyst to Workload Identity Federation for their notebook environment, and added a Cloud Asset Inventory query, run weekly, specifically hunting for service account keys outside the two folders they expected to see any.

## Part 1 gcloud Cheat Sheet

| Task | Command |
|---|---|
| List organizations you can access | `gcloud organizations list` |
| Create a folder | `gcloud resource-manager folders create --display-name=NAME --organization=ORG_ID` |
| Create a project | `gcloud projects create PROJECT_ID --folder=FOLDER_ID` |
| Link billing | `gcloud billing projects link PROJECT_ID --billing-account=ACCOUNT_ID` |
| Enable an API | `gcloud services enable API_NAME.googleapis.com --project=PROJECT_ID` |
| List enabled APIs | `gcloud services list --enabled --project=PROJECT_ID` |
| Set an org policy | `gcloud org-policies set-policy POLICY_FILE.yaml --project=PROJECT_ID` |
| View effective org policy | `gcloud org-policies describe-effective-policy CONSTRAINT --project=PROJECT_ID` |
| Check quota usage | `gcloud compute regions describe REGION --project=PROJECT_ID` |
| Search assets org-wide | `gcloud asset search-all-resources --scope=organizations/ORG_ID` |

## Pre-Flight Checklist: Is a New GCP Environment Actually Ready?

- [ ] Resource hierarchy (organization or standalone, folders) matches the real business/environment structure, not an arbitrary default
- [ ] Org policies for data residency, external IP restriction, and service account key creation are attached, with any compliance-critical ones past their dry-run window
- [ ] Billing account is linked and a budget alert is configured before any resource creation
- [ ] Cloud Identity groups (not individual users) are the IAM binding target for every team-level role
- [ ] Offboarding runs through the same SCIM/IdP path for contractors as for full-time employees
- [ ] Essential Contacts is configured so billing/security/technical notices reach a team inbox, not one person
- [ ] A Cloud Asset Inventory query exists for at least one thing you'd want to know about immediately (unexpected service account keys, resources outside expected regions)

## Common Mistakes and Interview Traps

| Mistake | Why it's wrong | What to say instead |
|---|---|---|
| "A GCP project needs an Organization above it to function" | Standalone projects with no Organization are fully functional and common | A project is independently viable; an Organization adds hierarchy-wide policy and folder structure on top |
| "Network tags and labels are the same thing" | Network tags are unstructured firewall/route targets; labels are structured key-value metadata for billing and inventory | Labels for cost allocation and search, network tags for firewall targeting, Resource Manager tags for IAM conditions and org-policy targeting |
| "Org policies control who can do what" | That's IAM's job; org policies control what's allowed to exist, regardless of who's asking | IAM answers "who," org policies answer "what's permitted at all" |
| "Enabling dry-run mode enforces the policy at a reduced level" | Dry-run never blocks anything; it only logs what it would have blocked | Dry-run is purely observational, used to validate a policy's blast radius before enforcement |
| "Standalone organizations require Cloud Identity" | The entire point of a standalone organization is that it doesn't | Standalone organizations are created automatically from a Google account, with no Cloud Identity or domain verification |

## Worked Practice Problems

**Problem 1:** Meridian's compliance team wants to guarantee that no Compute Engine VM anywhere in the organization can ever be created with a public IP address, but the platform team is nervous about breaking an unknown number of existing automation scripts that might depend on public IPs. What's the correct sequence of steps?

*Answer:* Attach `constraints/compute.vmExternalIpAccess` in dry-run mode at the Organization node first, and let it run for a defined observation window (one to two weeks is typical) against real VM-creation traffic. Review the dry-run violation logs to find every script or team that would have been blocked, coordinate remediation with them (migrating to Cloud NAT for outbound-only needs, for instance), and only then promote the policy to a live, enforced state. Enforcing it directly without the dry-run step risks an unplanned outage the moment some undocumented automation tries to create a VM with a public IP.

**Problem 2:** An engineer reports that a Terraform apply is failing with `Error 403: Cloud Resource Manager API has not been used in project meridian-freight-dev before or it is disabled`, even though their IAM role is `roles/owner` on the project. What's actually wrong, and what's the fix?

*Answer:* This is an API enablement error, not an IAM error, despite superficially looking like a permission problem, and having `roles/owner` doesn't bypass it. GCP requires every API to be explicitly enabled per project before it can be called, regardless of the caller's IAM role. The fix is `gcloud services enable cloudresourcemanager.googleapis.com --project=meridian-freight-dev`, then re-running the Terraform apply.

**Problem 3:** Meridian onboards a new contractor firm and wants their five contractors to authenticate with Google Cloud using the firm's own Okta tenant, without creating Cloud Identity accounts for any of them, since the engagement is only three months long. What's the right mechanism, and why not just create temporary Cloud Identity users instead?

*Answer:* Workforce Identity Federation is the right mechanism: it lets the contractors authenticate through their own firm's Okta IdP and maps that assertion into a workforce identity pool with scoped IAM bindings, with no Cloud Identity user object created at all. Creating temporary Cloud Identity users would work mechanically, but it means Meridian now owns the full lifecycle (creation, password/MFA policy, and critically, guaranteed deactivation at contract end) for five accounts that live in a directory Meridian's own offboarding automation may not be watching as closely as it watches full-time employee accounts, exactly the failure mode from this chapter's Cloud Identity "From the Trenches" callout.

## Summary and What's Next

This chapter built Meridian's GCP foundation from the ground up: the project as the real unit of isolation, the resource hierarchy and how org policies inherit through it (including the newer dry-run mode), the choice between a standalone and a domain-linked organization, the three distinct metadata mechanisms (labels, network tags, Resource Manager tags), and how Cloud Identity, manual or SCIM-automated, keeps the humans who can touch this environment under control. You also got a first look at Cloud Asset Inventory, Gemini Cloud Assist, and Workforce Identity Federation, each of which reappears in more depth later in this series.

**Part 2** moves from structure to spend and tooling: setting up billing accounts, budgets, and exports, then the practical toolchain (gcloud CLI, Cloud Shell, client libraries, Terraform and Config Connector for infrastructure as code, and the newer AI-assisted tooling, Gemini CLI, Google Antigravity, and Application Design Center) you'll use to actually build what this chapter's structure makes room for.
