GCP / Guide 2

Resource hierarchy and access

Organization, folders and projects, organisation policies, IAM, service accounts, and protecting the super admins.

In Google Cloud, the project is where resources live and where APIs, quotas and billing are attached, and the organisation, folders and projects above it are where policy and access are set once and inherited. A good structure uses one project per workload and environment, folders for the things that share rules, and groups for every permission.

The hierarchy

LevelWhat it isUsed for
OrganizationThe root, tied to your Cloud Identity or Google Workspace domainOrganisation policies, organisation-wide IAM, billing ownership
FoldersGroups of projects (and other folders), up to 10 levels deepPolicy and access for a business unit or environment
ProjectsThe container for resourcesAPIs, quotas, billing account link, IAM for one workload
ResourcesVMs, buckets, databasesLabels group them for cost and ownership

IAM policies and organisation policies set at one level are inherited by everything below. IAM is additive: a role granted on a folder can't be taken away on a project inside it (except with an IAM deny policy).

A project has three identifiers: a name you can change, a project ID that is globally unique and permanent, and a project number that Google assigns. Scripts and service accounts use the ID, so choose it carefully: prj-notes-test reads better in five years than my-project-8812.

A practical layout

ravindran.in (organization)
├── fldr-common                shared services
│   ├── prj-logging            log sinks, audit log buckets, locked down
│   ├── prj-security           Security Command Center, KMS keys, secrets for platform tools
│   ├── prj-network-hub        Shared VPC host project, Cloud NAT, interconnect, DNS
│   └── prj-billing-export     BigQuery dataset for the billing export
├── fldr-prod
│   ├── prj-payroll-prod
│   └── prj-web-prod
├── fldr-nonprod
│   ├── prj-payroll-test
│   └── prj-notes-test
└── fldr-sandbox               personal experiments, with budgets and a stricter org policy
  • One project per workload per environment. Production and test in one project means test credentials reach production data, and cost reports can't tell them apart.
  • Shared VPC lets a central network team own the VPC in a host project while workload projects (service projects) create VMs in its subnets. Networking stays consistent; workload teams don't need network admin rights.
  • Google's security foundations blueprint (and the Cloud Foundation Toolkit's Terraform) creates this kind of layout with sensible defaults. Use it, or at least read it, before building your own.

Organisation policies

An organisation policy sets a limit that nobody in the projects below can exceed, not even an Owner. Organisations created since 3 May 2024 start "secure by default" with these enforced:

ConstraintEffect
iam.managed.disableServiceAccountKeyCreationNo downloadable service account keys
iam.disableServiceAccountKeyUploadNo uploading your own public keys to service accounts
iam.automaticIamGrantsForDefaultServiceAccountsDefault service accounts don't get the Editor role automatically
iam.allowedPolicyMemberDomainsOnly identities from your own domains can be granted roles
essentialcontacts.managed.allowedContactDomainsPlatform notifications only go to your own domains
compute.managed.restrictProtocolForwardingCreationForTypesProtocol forwarding on internal IPs only
storage.uniformBucketLevelAccessBuckets use IAM only, no per-object ACLs

Older organisations should set the same ones. Guide 3 covers the other constraints worth adding and how to test them with dry run.

# Which organisation policies are set on a project (inherited ones included)
gcloud org-policies list --project=prj-notes-test --show-unset=false

# The effective value of one constraint
gcloud org-policies describe iam.allowedPolicyMemberDomains --project=prj-notes-test --effective

Access with IAM

An IAM grant is principal + role + resource. Rules worth writing down:

  • Grant to groups, never to individual users. Joiners and leavers then happen in your identity system, not in dozens of projects.
  • Avoid the basic roles (Owner, Editor, Viewer) for day-to-day access. Editor can change almost anything in a project; Owner can also change who has access. Use predefined roles such as roles/compute.instanceAdmin.v1 or roles/storage.objectViewer, and custom roles where none fits.
  • Grant at the lowest level that works: a bucket rather than the project, a project rather than the folder.
  • Use IAM Conditions for time-bound or scoped access, for example a grant that expires at the end of a project.
  • Use Privileged Access Manager for admin roles: people request roles/owner or a production admin role for a few hours, with a justification and optional approval, and it's logged.
  • Act on IAM Recommender. It flags roles that haven't been used in 90 days and suggests smaller ones. Get-GcpIamReport.ps1 lists the risky grants across projects.
# Who has what on a project
gcloud projects get-iam-policy prj-notes-test --format=json | ConvertFrom-Json |
    Select-Object -ExpandProperty bindings | ForEach-Object {
        $b = $_; $b.members | ForEach-Object { [pscustomobject]@{ Role = $b.role; Member = $_ } }
    } | Sort-Object Role | Format-Table

# Grant a group a predefined role
gcloud projects add-iam-policy-binding prj-notes-test `
    --member="group:gcp-notes-operators@ravindran.in" --role="roles/compute.instanceAdmin.v1"

Service accounts

Service accounts are identities for workloads, and they're the most common way access leaks in Google Cloud. Rules:

  • One service account per workload, with only the roles it needs. Don't use the Compute Engine default service account (number-compute@developer.gserviceaccount.com): in older projects it has Editor on the whole project.
  • No keys. Attach service accounts to resources, use Workload Identity Federation from outside Google Cloud, and impersonation for people (Guide 1).
  • Be careful who can act as a service account. roles/iam.serviceAccountUser and roles/iam.serviceAccountTokenCreator granted at project level let someone use every service account in the project, including powerful ones. Grant them on the specific account instead.
  • Disable, then delete. Disable unused service accounts first; if nothing breaks in a few weeks, delete them. Deleted accounts can be restored for 30 days.

Protect the super admins

The super admin accounts of your Cloud Identity or Workspace domain can grant themselves anything in the organisation. Keep two, used for nothing else, with hardware security keys, and don't give them day-to-day Google Cloud roles. Grant the organisation administrator role (roles/resourcemanager.organizationAdmin) to a small group instead, and alert on every super admin sign-in.