📑 Table of Contents

Google Cloud IAM uses a resource hierarchy model where permissions inherit down from Organization to Folders to Projects. Unlike AWS where permissions are primarily user-centric, GCP IAM binds roles (collections of permissions) to principals at various levels of the hierarchy. This lab teaches you to design and implement GCP IAM from organization setup through service accounts and workload identity federation.

🎯 Lab Overview & GCP IAM Model

GCP IAM follows a different model than AWS. Instead of users having attached policies, GCP binds roles to members at specific resource hierarchy levels. Permissions flow down: if you have a role at the organization level, you have it for all folders and projects below. Understanding this hierarchy is fundamental to GCP security.

📖 GCP IAM Core Concepts

  • Member/Principal: Who (user, group, service account, domain)
  • Role: Collection of permissions (viewer, editor, owner, custom)
  • Policy/Binding: Connects member + role + resource
  • Resource Hierarchy: Organization → Folders → Projects → Resources
  • Inheritance: Permissions flow DOWN the hierarchy

Resource Hierarchy

LevelPurposeExample
OrganizationRoot of hierarchy, tied to Cloud Identity/Workspace domainexample.com
FolderGrouping mechanism for projects (departments, environments)Production, Development
ProjectContainer for resources, billing boundaryweb-app-prod, data-pipeline-dev
ResourceIndividual GCP servicesGCS bucket, GCE instance, BigQuery dataset

Principal Types

👤 Google Account

user:alice@gmail.com - Individual Google account

👥 Google Group

group:devs@example.com - Google Group for team access

🤖 Service Account

serviceAccount:sa@project.iam.gserviceaccount.com

🏢 Domain

domain:example.com - All users in Cloud Identity domain

🌐 All Users

allUsers - Anyone on the internet (public)

✅ All Authenticated

allAuthenticatedUsers - Any Google account

🏗️ Module 1: Organization & Project Setup

Module 1: Configure Your GCP Foundation

Set up organization, folders, and projects.

⏱️ 45-60 minutes🎯 5 steps
1

Access Google Cloud Console

GCP Console
Navigate to: https://console.cloud.google.com Sign in with: - Google Workspace account (for organization) - Or personal Google account (no organization) If you have an organization: → Select organization from dropdown (top left) For organizations, you need: - Google Workspace or Cloud Identity domain - Organization Admin role
2

Create Folder Structure

gcloud CLI
# Set organization ID ORG_ID=$(gcloud organizations list --format="value(ID)") echo "Organization ID: $ORG_ID" # Create folders gcloud resource-manager folders create \ --display-name="Production" \ --organization=$ORG_ID gcloud resource-manager folders create \ --display-name="Development" \ --organization=$ORG_ID gcloud resource-manager folders create \ --display-name="Shared-Services" \ --organization=$ORG_ID # List folders gcloud resource-manager folders list \ --organization=$ORG_ID
3

Create Projects

gcloud CLI
# Get folder IDs PROD_FOLDER=$(gcloud resource-manager folders list \ --organization=$ORG_ID \ --filter="displayName:Production" \ --format="value(ID)") DEV_FOLDER=$(gcloud resource-manager folders list \ --organization=$ORG_ID \ --filter="displayName:Development" \ --format="value(ID)") # Create production project gcloud projects create webapp-prod-$(date +%s) \ --name="WebApp Production" \ --folder=$PROD_FOLDER # Create development project gcloud projects create webapp-dev-$(date +%s) \ --name="WebApp Development" \ --folder=$DEV_FOLDER # Create shared services project SHARED_FOLDER=$(gcloud resource-manager folders list \ --organization=$ORG_ID \ --filter="displayName:Shared-Services" \ --format="value(ID)") gcloud projects create shared-services-$(date +%s) \ --name="Shared Services" \ --folder=$SHARED_FOLDER
4

Enable Required APIs

gcloud CLI
# Set project PROJECT_ID="your-project-id" gcloud config set project $PROJECT_ID # Enable IAM APIs gcloud services enable iam.googleapis.com gcloud services enable iamcredentials.googleapis.com gcloud services enable cloudresourcemanager.googleapis.com gcloud services enable sts.googleapis.com # Verify enabled APIs gcloud services list --enabled
5

View IAM Policy

gcloud CLI
# View project IAM policy gcloud projects get-iam-policy $PROJECT_ID # View organization IAM policy gcloud organizations get-iam-policy $ORG_ID # View folder IAM policy gcloud resource-manager folders get-iam-policy $PROD_FOLDER # Output shows bindings: # bindings: # - members: # - user:alice@example.com # role: roles/owner # - members: # - serviceAccount:service@project.iam.gserviceaccount.com # role: roles/editor

🎭 Module 2: IAM Roles & Bindings

Module 2: Understand and Assign IAM Roles

Work with predefined roles and IAM bindings.

⏱️ 45-60 minutes🎯 5 steps

📖 Role Types

  • Basic Roles: Owner, Editor, Viewer (broad, legacy - avoid in production)
  • Predefined Roles: Service-specific roles created by Google (roles/storage.admin)
  • Custom Roles: User-defined collections of permissions
6

List Available Roles

gcloud CLI
# List all predefined roles gcloud iam roles list # Search for specific service roles gcloud iam roles list --filter="name:storage" gcloud iam roles list --filter="name:compute" gcloud iam roles list --filter="name:bigquery" # Describe a specific role gcloud iam roles describe roles/storage.admin # Shows: # - description # - includedPermissions (list of permissions) # - name # - stage (GA, BETA, ALPHA) # - title
7

Grant Role at Project Level

gcloud CLI
# Grant viewer role to user at project level gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="user:bob@example.com" \ --role="roles/viewer" # Grant storage admin to a group gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="group:developers@example.com" \ --role="roles/storage.admin" # Grant BigQuery user to specific user gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="user:analyst@example.com" \ --role="roles/bigquery.user" # Verify the binding gcloud projects get-iam-policy $PROJECT_ID \ --flatten="bindings[].members" \ --filter="bindings.members:bob@example.com"
8

Grant Role at Organization Level

gcloud CLI
# Grant organization-wide viewer (inherits to all projects!) gcloud organizations add-iam-policy-binding $ORG_ID \ --member="group:security-team@example.com" \ --role="roles/iam.securityReviewer" # Grant folder-level role (inherits to projects in folder) gcloud resource-manager folders add-iam-policy-binding $PROD_FOLDER \ --member="group:sre-team@example.com" \ --role="roles/compute.admin" # ⚠️ BE CAREFUL: Organization and folder roles # apply to ALL resources below in hierarchy!
9

Grant Role on Specific Resource

gcloud CLI
# Create a GCS bucket for testing gsutil mb gs://iam-lab-bucket-$PROJECT_ID # Grant access to specific bucket only gsutil iam ch user:alice@example.com:objectViewer \ gs://iam-lab-bucket-$PROJECT_ID # Or using gcloud gcloud storage buckets add-iam-policy-binding \ gs://iam-lab-bucket-$PROJECT_ID \ --member="user:alice@example.com" \ --role="roles/storage.objectViewer" # View bucket IAM policy gcloud storage buckets get-iam-policy \ gs://iam-lab-bucket-$PROJECT_ID
10

Remove IAM Binding

gcloud CLI
# Remove role from user gcloud projects remove-iam-policy-binding $PROJECT_ID \ --member="user:bob@example.com" \ --role="roles/viewer" # Remove from bucket gcloud storage buckets remove-iam-policy-binding \ gs://iam-lab-bucket-$PROJECT_ID \ --member="user:alice@example.com" \ --role="roles/storage.objectViewer" # Verify removal gcloud projects get-iam-policy $PROJECT_ID

🛠️ Module 3: Custom Roles

Module 3: Create Least-Privilege Custom Roles

Design custom roles with only required permissions.

⏱️ 45-60 minutes🎯 4 steps
11

List Permissions for Service

gcloud CLI
# List all permissions available gcloud iam list-testable-permissions \ //cloudresourcemanager.googleapis.com/projects/$PROJECT_ID # Filter for storage permissions gcloud iam list-testable-permissions \ //cloudresourcemanager.googleapis.com/projects/$PROJECT_ID \ --filter="name:storage" # List permissions in a role gcloud iam roles describe roles/storage.objectViewer \ --format="yaml(includedPermissions)"
12

Create Custom Role via CLI

gcloud CLI
# Create custom role at project level gcloud iam roles create StorageReadOnly \ --project=$PROJECT_ID \ --title="Storage Read Only" \ --description="Read-only access to GCS objects" \ --permissions="storage.objects.get,storage.objects.list,storage.buckets.get,storage.buckets.list" \ --stage=GA # Create custom role at organization level gcloud iam roles create ComputeInstanceRestart \ --organization=$ORG_ID \ --title="Compute Instance Restart" \ --description="Can only restart compute instances" \ --permissions="compute.instances.get,compute.instances.list,compute.instances.start,compute.instances.stop,compute.instances.reset" \ --stage=BETA
13

Create Custom Role via YAML

JSON/YAML
# Create role definition file: developer-role.yaml title: "Application Developer" description: "Custom role for application developers" stage: "GA" includedPermissions: - compute.instances.get - compute.instances.list - compute.instances.start - compute.instances.stop - storage.objects.get - storage.objects.create - storage.objects.delete - storage.buckets.get - storage.buckets.list - logging.logEntries.list - logging.logs.list - monitoring.timeSeries.list - cloudfunctions.functions.get - cloudfunctions.functions.list - cloudfunctions.functions.call
# Create the role from YAML gcloud iam roles create AppDeveloper \ --project=$PROJECT_ID \ --file=developer-role.yaml # Assign custom role gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="user:developer@example.com" \ --role="projects/$PROJECT_ID/roles/AppDeveloper"
14

Manage Custom Roles

gcloud CLI
# List custom roles gcloud iam roles list --project=$PROJECT_ID # Describe custom role gcloud iam roles describe AppDeveloper --project=$PROJECT_ID # Update custom role (add permission) gcloud iam roles update AppDeveloper \ --project=$PROJECT_ID \ --add-permissions="cloudfunctions.functions.create" # Disable custom role gcloud iam roles update AppDeveloper \ --project=$PROJECT_ID \ --stage=DISABLED # Delete custom role (soft delete - can undelete within 7 days) gcloud iam roles delete AppDeveloper --project=$PROJECT_ID # Undelete within 7 days gcloud iam roles undelete AppDeveloper --project=$PROJECT_ID

🤖 Module 4: Service Accounts

Module 4: Create and Manage Service Accounts

Configure machine identities for applications and automation.

⏱️ 60-90 minutes🎯 6 steps
15

Create Service Account

gcloud CLI
# Create service account gcloud iam service-accounts create app-backend \ --display-name="Application Backend Service" \ --description="Service account for backend application" # Service account email format: # app-backend@PROJECT_ID.iam.gserviceaccount.com # List service accounts gcloud iam service-accounts list # Describe service account gcloud iam service-accounts describe \ app-backend@$PROJECT_ID.iam.gserviceaccount.com
16

Grant Roles to Service Account

gcloud CLI
# Grant roles to service account SA_EMAIL="app-backend@$PROJECT_ID.iam.gserviceaccount.com" # Grant storage access gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/storage.objectAdmin" # Grant BigQuery access gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/bigquery.dataEditor" # Grant logging access gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/logging.logWriter"
17

Create Service Account Key (Avoid If Possible)

gcloud CLI
# ⚠️ AVOID service account keys when possible! # Use Workload Identity Federation or attached service accounts instead. # If you MUST create a key (legacy systems): gcloud iam service-accounts keys create key.json \ --iam-account=$SA_EMAIL # The key.json file contains sensitive credentials! # - Never commit to source control # - Store in Secret Manager if needed # - Set expiration and rotation policies # List keys for service account gcloud iam service-accounts keys list \ --iam-account=$SA_EMAIL # Delete a key gcloud iam service-accounts keys delete KEY_ID \ --iam-account=$SA_EMAIL
18

Service Account Impersonation

gcloud CLI
# Grant user ability to impersonate service account gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \ --member="user:developer@example.com" \ --role="roles/iam.serviceAccountTokenCreator" # User can now impersonate the service account: gcloud auth print-access-token \ --impersonate-service-account=$SA_EMAIL # Run command as service account gcloud storage ls gs://my-bucket \ --impersonate-service-account=$SA_EMAIL # This is preferred over key files! # - Short-lived tokens # - Auditable (who impersonated) # - No key file management
19

Attach Service Account to GCE

gcloud CLI
# Create VM with attached service account gcloud compute instances create my-vm \ --zone=us-central1-a \ --machine-type=e2-micro \ --service-account=$SA_EMAIL \ --scopes=cloud-platform # The VM can now use the service account's permissions # WITHOUT any key files - credentials are automatic! # From inside the VM: # gcloud storage ls # Uses attached service account # Update existing VM's service account gcloud compute instances set-service-account my-vm \ --zone=us-central1-a \ --service-account=$SA_EMAIL \ --scopes=cloud-platform
20

Service Account for GKE Workloads

gcloud CLI
# Create service account for GKE pods gcloud iam service-accounts create gke-workload \ --display-name="GKE Workload Identity" GKE_SA="gke-workload@$PROJECT_ID.iam.gserviceaccount.com" # Grant needed permissions gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$GKE_SA" \ --role="roles/storage.objectViewer" # Allow Kubernetes service account to use GCP service account gcloud iam service-accounts add-iam-policy-binding $GKE_SA \ --member="serviceAccount:$PROJECT_ID.svc.id.goog[default/my-ksa]" \ --role="roles/iam.workloadIdentityUser" # In Kubernetes, annotate the service account: # kubectl annotate serviceaccount my-ksa \ # iam.gke.io/gcp-service-account=$GKE_SA

📜 Module 5: Organization Policies

Module 5: Implement Organization-Wide Guardrails

Use organization policies to enforce security constraints.

⏱️ 45-60 minutes🎯 4 steps
21

List Available Constraints

gcloud CLI
# List all organization policy constraints gcloud org-policies list --organization=$ORG_ID # Describe specific constraint gcloud org-policies describe \ constraints/compute.disableSerialPortAccess \ --organization=$ORG_ID # Common security constraints: # - compute.disableSerialPortAccess # - compute.requireOsLogin # - compute.vmExternalIpAccess # - iam.disableServiceAccountKeyCreation # - storage.uniformBucketLevelAccess # - sql.restrictPublicIp
22

Apply Organization Policy

gcloud CLI
# Disable service account key creation (org-wide) gcloud org-policies set-policy \ --organization=$ORG_ID << EOF name: organizations/$ORG_ID/policies/iam.disableServiceAccountKeyCreation spec: rules: - enforce: true EOF # Require uniform bucket-level access gcloud org-policies set-policy \ --organization=$ORG_ID << EOF name: organizations/$ORG_ID/policies/storage.uniformBucketLevelAccess spec: rules: - enforce: true EOF # Restrict VM external IPs to none gcloud org-policies set-policy \ --organization=$ORG_ID << EOF name: organizations/$ORG_ID/policies/compute.vmExternalIpAccess spec: rules: - denyAll: true EOF
23

Apply Policy at Folder/Project Level

gcloud CLI
# Allow external IPs only in development folder gcloud org-policies set-policy \ --folder=$DEV_FOLDER << EOF name: folders/$DEV_FOLDER/policies/compute.vmExternalIpAccess spec: inheritFromParent: false rules: - allowAll: true EOF # Restrict allowed regions for a project gcloud org-policies set-policy \ --project=$PROJECT_ID << EOF name: projects/$PROJECT_ID/policies/gcp.resourceLocations spec: rules: - values: allowedValues: - in:us-locations - in:eu-locations EOF
24

View Effective Policy

gcloud CLI
# View effective policy (considering inheritance) gcloud org-policies describe \ constraints/compute.vmExternalIpAccess \ --effective \ --project=$PROJECT_ID # View all policies for a resource gcloud org-policies list --project=$PROJECT_ID # Delete/reset policy (inherit from parent) gcloud org-policies reset \ constraints/compute.vmExternalIpAccess \ --project=$PROJECT_ID

🔗 Module 6: Workload Identity Federation

Module 6: Keyless Authentication from External Providers

Configure federation with AWS, Azure, GitHub, and more.

⏱️ 45-60 minutes🎯 4 steps
25

Create Workload Identity Pool

gcloud CLI
# Create workload identity pool gcloud iam workload-identity-pools create "github-pool" \ --location="global" \ --display-name="GitHub Actions Pool" \ --description="Pool for GitHub Actions CI/CD" # Get pool name POOL_ID="github-pool" POOL_NAME="projects/$PROJECT_ID/locations/global/workloadIdentityPools/$POOL_ID"
26

Add OIDC Provider (GitHub)

gcloud CLI
# Add GitHub as OIDC provider gcloud iam workload-identity-pools providers create-oidc "github" \ --location="global" \ --workload-identity-pool="github-pool" \ --display-name="GitHub" \ --issuer-uri="https://token.actions.githubusercontent.com" \ --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" # Provider name PROVIDER_NAME="projects/$PROJECT_ID/locations/global/workloadIdentityPools/github-pool/providers/github"
27

Grant Service Account Access

gcloud CLI
# Create service account for GitHub Actions gcloud iam service-accounts create github-actions \ --display-name="GitHub Actions Deployer" GITHUB_SA="github-actions@$PROJECT_ID.iam.gserviceaccount.com" # Grant SA the needed permissions gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$GITHUB_SA" \ --role="roles/storage.admin" # Allow GitHub repo to impersonate the service account REPO="myorg/myrepo" gcloud iam service-accounts add-iam-policy-binding $GITHUB_SA \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/attribute.repository/$REPO"
28

Configure GitHub Actions Workflow

YAML
# .github/workflows/deploy.yml name: Deploy to GCP on: push: branches: [main] permissions: id-token: write contents: read jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - id: auth uses: google-github-actions/auth@v1 with: workload_identity_provider: 'projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/providers/github' service_account: 'github-actions@PROJECT_ID.iam.gserviceaccount.com' - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@v1 - name: Deploy run: | gcloud storage cp app.jar gs://my-bucket/ # No service account key needed!

🔍 Module 7: IAM Recommender & Security

Module 7: Analyze and Optimize IAM Configuration

Use GCP tools to find and fix IAM issues.

⏱️ 30-45 minutes🎯 4 steps
29

View IAM Recommendations

GCP Console
Navigate to: IAM & Admin → IAM Look for recommendation icons next to principals. Google analyzes actual usage and recommends: - Remove unused roles - Replace broad roles with specific ones - Revoke access for inactive accounts Click recommendation to see details: - What role to remove/change - Why (based on actual usage) - Impact assessment Apply or dismiss recommendations.
30

Use Policy Analyzer

gcloud CLI
# Analyze who has access to a resource gcloud asset analyze-iam-policy \ --organization=$ORG_ID \ --identity="user:alice@example.com" # Find all principals with specific permission gcloud asset analyze-iam-policy \ --organization=$ORG_ID \ --permissions="storage.objects.delete" # Find all roles with specific permission gcloud asset analyze-iam-policy \ --organization=$ORG_ID \ --permissions="iam.serviceAccountKeys.create"
31

Audit IAM Changes

gcloud CLI
# View IAM audit logs gcloud logging read \ 'protoPayload.serviceName="iam.googleapis.com"' \ --project=$PROJECT_ID \ --limit=50 # Filter for specific actions gcloud logging read \ 'protoPayload.methodName="SetIamPolicy"' \ --project=$PROJECT_ID # Filter for service account key creation gcloud logging read \ 'protoPayload.methodName="google.iam.admin.v1.CreateServiceAccountKey"' \ --project=$PROJECT_ID
32

Security Command Center

GCP Console
Navigate to: Security → Security Command Center IAM-related findings: - Overly permissive service accounts - Service account key usage - Public resources - Unused service accounts - Over-privileged users For each finding: - View details and affected resources - Get remediation guidance - Track over time Enable Security Health Analytics for continuous monitoring.

🛡️ Security Best Practices

CRITICAL

Service Account Key Exposure

Service account keys in code, repos, or unsecured locations.

🛡️ Mitigation
  • Use Workload Identity instead of keys
  • Disable key creation via org policy
  • Use Secret Manager for necessary keys
  • Monitor key usage in audit logs
CRITICAL

Overprivileged Access

Using Owner/Editor roles or organization-level permissions.

🛡️ Mitigation
  • Use predefined roles over basic roles
  • Create custom roles for specific needs
  • Apply permissions at lowest hierarchy level
  • Review IAM Recommender suggestions
HIGH

Public Access

Resources exposed to allUsers or allAuthenticatedUsers.

🛡️ Mitigation
  • Use org policy to prevent public access
  • Audit all bindings with allUsers
  • Use uniform bucket-level access

✅ GCP IAM Best Practices

  • ✅ Use predefined roles instead of basic roles (Owner/Editor/Viewer)
  • ✅ Apply permissions at the lowest hierarchy level possible
  • ✅ Use groups for access management, not individual users
  • ✅ Avoid service account keys - use Workload Identity
  • ✅ Enable organization policies for security guardrails
  • ✅ Use IAM Conditions for context-aware access
  • ✅ Review IAM Recommender suggestions regularly
  • ✅ Enable audit logging and monitor IAM changes
  • ✅ Use Security Command Center for IAM security findings
  • ✅ Document and justify all organization-level bindings