Skip to content

1. IAM Fundamentals

Understanding the core concepts of Google Cloud Identity and Access Management.


Overview

┌────────────────────────────────────────────────────────┐
│  IAM Core Model: WHO can do WHAT on WHICH resource    │
├────────────────────────────────────────────────────────┤
│                                                         │
│  WHO (Identity/Member)                                 │
│  • Google Account (user)                               │
│  • Google Group                                        │
│  • Service Account                                     │
│  • Cloud Identity domain                               │
│                                                         │
│  WHAT (Role)                                           │
│  • Collection of permissions                           │
│  • Basic, Predefined, or Custom                        │
│  • Defines allowed actions                             │
│                                                         │
│  WHICH (Resource)                                      │
│  • Organization, Folder, Project                       │
│  • Specific resources (VM, bucket, etc.)               │
│  • Hierarchy determines scope                          │
└────────────────────────────────────────────────────────┘

IAM Components

1. Members (Identity)

┌────────────────────────────────────────────────────────┐
│  Member Types                                          │
└────────────────────────────────────────────────────────┘

Google Account (user:)
├─ Format: user:alice@company.com
├─ Individual person
├─ Gmail or Cloud Identity
└─ Human user authentication

Google Group (group:)
├─ Format: group:developers@company.com
├─ Collection of users
├─ Managed in Google Groups
└─ Recommended for team access

Service Account (serviceAccount:)
├─ Format: serviceAccount:app@project.iam.gserviceaccount.com
├─ Non-human identity
├─ For applications and workloads
└─ Programmatic access

Cloud Identity Domain (domain:)
├─ Format: domain:company.com
├─ All users in organization
├─ Requires Cloud Identity/Workspace
└─ Organization-wide grants

Special Identifiers:
├─ allUsers (anyone on internet)
├─ allAuthenticatedUsers (any Google Account)
└─ Use with extreme caution!

2. Roles (Permissions)

┌────────────────────────────────────────────────────────┐
│  Role Structure                                        │
└────────────────────────────────────────────────────────┘

Role: roles/compute.instanceAdmin.v1
│
├─ Title: Compute Instance Admin (v1)
│
├─ Description: Full control of Compute Engine instances
│
├─ Permissions: (100+ permissions)
│  ├─ compute.instances.create
│  ├─ compute.instances.delete
│  ├─ compute.instances.get
│  ├─ compute.instances.list
│  ├─ compute.instances.start
│  ├─ compute.instances.stop
│  └─ ... (and many more)
│
├─ Stage: GA (General Availability)
│
└─ Included In:
   ├─ roles/compute.admin
   └─ roles/editor

3. Permissions

┌────────────────────────────────────────────────────────┐
│  Permission Format                                     │
└────────────────────────────────────────────────────────┘

service.resource.verb

Examples:
  compute.instances.create
  │       │         │
  │       │         └─ Action (create, delete, get, list)
  │       └─ Resource type (instances, disks, networks)
  └─ Service (compute, storage, iam)

More Examples:
  storage.buckets.create
  storage.objects.get
  iam.serviceAccounts.create
  bigquery.datasets.get
  pubsub.topics.publish

Permission Characteristics:
  • Granular (specific actions)
  • Service-specific
  • Cannot be granted directly
  • Must be part of a role
  • 10,000+ permissions available

IAM Policy

Policy Structure

{
  "version": 3,
  "etag": "BwXhFJ5H8nY=",
  "bindings": [
    {
      "role": "roles/compute.admin",
      "members": [
        "user:alice@company.com",
        "group:devops@company.com"
      ]
    },
    {
      "role": "roles/storage.objectViewer",
      "members": [
        "serviceAccount:app@project.iam.gserviceaccount.com"
      ],
      "condition": {
        "title": "Expires end of 2026",
        "description": "Temporary access for migration",
        "expression": "request.time < timestamp('2026-12-31T23:59:59Z')"
      }
    },
    {
      "role": "roles/viewer",
      "members": [
        "group:everyone@company.com"
      ]
    }
  ]
}

Policy Components

┌────────────────────────────────────────────────────────┐
│  Policy Anatomy                                        │
├────────────────────────────────────────────────────────┤
│                                                         │
│  version: Policy schema version                        │
│  • 1: Basic policies                                   │
│  • 3: Policies with conditions (recommended)           │
│                                                         │
│  etag: Concurrency control                             │
│  • Prevents concurrent modifications                   │
│  • Must match for updates                              │
│                                                         │
│  bindings: Array of role assignments                   │
│  • role: The role being granted                        │
│  • members: Who gets the role                          │
│  • condition: Optional access constraints              │
│                                                         │
│  auditConfigs: Audit logging configuration             │
│  • Service-specific audit settings                     │
│  • Log types (ADMIN_READ, DATA_READ, DATA_WRITE)      │
└────────────────────────────────────────────────────────┘

Policy Inheritance

Hierarchy Example

┌────────────────────────────────────────────────────────────┐
│  Policy Inheritance in Action                              │
└────────────────────────────────────────────────────────────┘

Organization: company.com
Policy:
  - alice@company.com → roles/viewer
  - security@company.com → roles/securityReviewer
│
├─ Folder: Production
│  Policy:
│    - devops@company.com → roles/editor
│    - bob@company.com → roles/compute.admin
│  │
│  ├─ Project: web-prod
│  │  Policy:
│  │    - charlie@company.com → roles/owner
│  │    - app@web-prod.iam.gserviceaccount.com → roles/storage.objectViewer
│  │  │
│  │  └─ Resource: VM Instance (web-server-1)
│  │     Policy:
│  │       - dave@company.com → roles/compute.instanceAdmin.v1

Effective Permissions on web-server-1:
┌──────────────────────────────────────────────────────┐
│ User                  │ Effective Role              │
├──────────────────────────────────────────────────────┤
│ alice@company.com     │ Viewer (from org)           │
│ security@company.com  │ Security Reviewer (from org)│
│ devops@company.com    │ Editor (from folder)        │
│ bob@company.com       │ Compute Admin (from folder) │
│ charlie@company.com   │ Owner (from project)        │
│ dave@company.com      │ Instance Admin (from VM)    │
└──────────────────────────────────────────────────────┘

Key Points:
  ✓ All parent permissions inherited
  ✓ Permissions are cumulative (union)
  ✓ More permissive wins
  ✓ Cannot remove inherited permissions
  ✗ Child cannot override parent (use Deny policies)

Permission Evaluation

Allow Policy Evaluation

┌────────────────────────────────────────────────────────┐
│  Permission Check Flow                                 │
└────────────────────────────────────────────────────────┘

Request: alice@company.com wants to compute.instances.start
Resource: projects/web-prod/zones/us-central1-a/instances/web-1

Step 1: Collect all policies
├─ Organization policy
├─ Folder policy
├─ Project policy
└─ Resource policy

Step 2: Merge all bindings
├─ Combine all role assignments
└─ Create union of permissions

Step 3: Check conditions (if any)
├─ Evaluate IAM conditions
├─ Check time constraints
├─ Check resource attributes
└─ Check request context

Step 4: Evaluate deny policies (if any)
├─ Check organization deny policies
├─ Deny takes precedence over allow
└─ If denied, request is rejected

Step 5: Check if permission exists
├─ Does any role include compute.instances.start?
├─ Are all conditions met?
└─ Is it not explicitly denied?

Result:
  ✓ ALLOW: Permission found and conditions met
  ✗ DENY: Permission not found or denied

IAM Best Practices

1. Use Groups

┌────────────────────────────────────────────────────────┐
│  Group-Based Access Management                         │
└────────────────────────────────────────────────────────┘

❌ Bad Practice:
gcloud projects add-iam-policy-binding web-prod \
  --member='user:alice@company.com' \
  --role='roles/editor'

gcloud projects add-iam-policy-binding web-prod \
  --member='user:bob@company.com' \
  --role='roles/editor'

gcloud projects add-iam-policy-binding web-prod \
  --member='user:charlie@company.com' \
  --role='roles/editor'

Problems:
  • Hard to manage individual users
  • Difficult to audit
  • Error-prone
  • Doesn't scale

✅ Good Practice:
# Create group: developers@company.com
# Add alice, bob, charlie to group

gcloud projects add-iam-policy-binding web-prod \
  --member='group:developers@company.com' \
  --role='roles/editor'

Benefits:
  ✓ Single policy binding
  ✓ Easy to add/remove users
  ✓ Clear team structure
  ✓ Scales well
  ✓ Easier auditing

2. Least Privilege

┌────────────────────────────────────────────────────────┐
│  Principle of Least Privilege                          │
└────────────────────────────────────────────────────────┘

❌ Bad: Overly Permissive
gcloud projects add-iam-policy-binding web-prod \
  --member='serviceAccount:app@web-prod.iam.gserviceaccount.com' \
  --role='roles/editor'

Problems:
  • Can modify ANY resource
  • Can create/delete VMs, databases, etc.
  • Security risk
  • Compliance issues

✅ Good: Minimal Permissions
gcloud projects add-iam-policy-binding web-prod \
  --member='serviceAccount:app@web-prod.iam.gserviceaccount.com' \
  --role='roles/storage.objectViewer'

gcloud projects add-iam-policy-binding web-prod \
  --member='serviceAccount:app@web-prod.iam.gserviceaccount.com' \
  --role='roles/cloudsql.client'

Benefits:
  ✓ Only necessary permissions
  ✓ Reduced security risk
  ✓ Easier to audit
  ✓ Compliance friendly

3. Use Predefined Roles

┌────────────────────────────────────────────────────────┐
│  Role Selection Priority                               │
└────────────────────────────────────────────────────────┘

Priority Order:
1. Predefined Roles (Recommended)
   ├─ Curated by Google
   ├─ Regularly updated
   ├─ Well-documented
   └─ Example: roles/compute.instanceAdmin.v1

2. Custom Roles (When needed)
   ├─ Specific permission combinations
   ├─ Not available in predefined
   └─ Requires maintenance

3. Basic Roles (Avoid)
   ├─ Too permissive
   ├─ Legacy
   └─ Use only for testing

Example:
  ❌ roles/editor (basic role - too broad)
  ✅ roles/compute.instanceAdmin.v1 (predefined - specific)
  ✅ custom.myAppRole (custom - tailored)

Managing IAM Policies

View Policies

# Get project IAM policy
gcloud projects get-iam-policy PROJECT_ID

# Get policy in JSON format
gcloud projects get-iam-policy PROJECT_ID \
  --format=json

# Get policy for specific member
gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --filter="bindings.members:user:alice@company.com"

# Get policy for specific role
gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --filter="bindings.role:roles/editor"

Add Policy Binding

# Grant role to user
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='user:alice@company.com' \
  --role='roles/viewer'

# Grant role to group
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='group:developers@company.com' \
  --role='roles/editor'

# Grant role to service account
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='serviceAccount:app@PROJECT_ID.iam.gserviceaccount.com' \
  --role='roles/storage.objectViewer'

# Grant with condition
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='user:contractor@external.com' \
  --role='roles/viewer' \
  --condition='expression=request.time < timestamp("2026-12-31T23:59:59Z"),title=Expires 2026,description=Temporary contractor access'

Remove Policy Binding

# Remove role from user
gcloud projects remove-iam-policy-binding PROJECT_ID \
  --member='user:alice@company.com' \
  --role='roles/viewer'

# Remove all bindings for a member
gcloud projects get-iam-policy PROJECT_ID \
  --format=json > policy.json

# Edit policy.json to remove member
# Then set the policy
gcloud projects set-iam-policy PROJECT_ID policy.json

IAM Conditions

Condition Examples

# Time-based access (expires)
--condition='expression=request.time < timestamp("2026-12-31T23:59:59Z"),
title=Expires end of 2026'

# Time-based access (valid period)
--condition='expression=request.time > timestamp("2026-01-01T00:00:00Z") && 
request.time < timestamp("2026-12-31T23:59:59Z"),
title=Valid only in 2026'

# Resource-based (specific bucket)
--condition='expression=resource.name.startsWith("projects/_/buckets/prod-"),
title=Only prod buckets'

# Attribute-based (resource type)
--condition='expression=resource.type == "storage.googleapis.com/Bucket",
title=Only storage buckets'

# IP-based access
--condition='expression=origin.ip == "203.0.113.0/24",
title=Only from office IP'

# Combined conditions
--condition='expression=request.time < timestamp("2026-12-31T23:59:59Z") && 
resource.name.startsWith("projects/_/buckets/dev-"),
title=Temporary access to dev buckets'

Testing Permissions

Test IAM Permissions

# Test if you have specific permissions
gcloud projects test-iam-permissions PROJECT_ID \
  --permissions=compute.instances.list,compute.instances.get,compute.instances.create

# Output shows which permissions you have
# permissions:
# - compute.instances.list
# - compute.instances.get

# Test for service account
gcloud projects test-iam-permissions PROJECT_ID \
  --permissions=storage.buckets.list \
  --impersonate-service-account=app@PROJECT_ID.iam.gserviceaccount.com

Policy Troubleshooter

# Use Policy Troubleshooter (via Console)
# IAM & Admin → Policy Troubleshooter

# Input:
# - Member: user:alice@company.com
# - Resource: projects/web-prod/zones/us-central1-a/instances/web-1
# - Permission: compute.instances.start

# Output shows:
# - Whether access is granted
# - Which policy grants access
# - Inheritance path
# - Conditions evaluated

Common IAM Patterns

Pattern 1: Development Team

# Create group
# developers@company.com (via Google Groups)

# Grant editor access to dev project
gcloud projects add-iam-policy-binding dev-project \
  --member='group:developers@company.com' \
  --role='roles/editor'

# Grant viewer access to prod project
gcloud projects add-iam-policy-binding prod-project \
  --member='group:developers@company.com' \
  --role='roles/viewer'

Pattern 2: Service Account for App

# Create service account
gcloud iam service-accounts create web-app \
  --display-name="Web Application"

# Grant minimal permissions
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='serviceAccount:web-app@PROJECT_ID.iam.gserviceaccount.com' \
  --role='roles/storage.objectViewer'

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='serviceAccount:web-app@PROJECT_ID.iam.gserviceaccount.com' \
  --role='roles/cloudsql.client'

Pattern 3: Temporary Contractor

# Grant time-limited access
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='user:contractor@external.com' \
  --role='roles/viewer' \
  --condition='expression=request.time < timestamp("2026-06-30T23:59:59Z"),
title=Contract ends June 2026'

Troubleshooting

Issue: Permission denied
Solution:
  • Check IAM policy with get-iam-policy
  • Use test-iam-permissions
  • Use Policy Troubleshooter
  • Check for deny policies
  • Verify conditions are met

Issue: Cannot grant role
Solution:
  • Verify you have IAM Admin role
  • Check organization policies
  • Ensure role exists
  • Check member format

Issue: Inherited permission not working
Solution:
  • Check parent policies
  • Verify policy propagation (can take minutes)
  • Check for deny policies
  • Use Policy Troubleshooter

Next Steps