GCDLChapter 43 of 101Objective 2.5

IAM Concepts: Principals, Roles, and Bindings

This chapter covers the foundational IAM concepts of principals, roles, and bindings in Google Cloud. These concepts are the bedrock of all access control decisions in GCP and are tested heavily on the GCDL exam, appearing in approximately 15-20% of questions across multiple domains. Understanding how these three elements interact is critical for designing secure, least-privilege architectures. We will dissect each component, explain the underlying mechanisms, and highlight exactly what the exam expects you to know.

25 min read
Intermediate
Updated May 31, 2026

IAM as a Secure Building Access System

Imagine a large corporate building with multiple floors and departments. The building has a single main entrance with a security checkpoint. Each employee (principal) receives a badge that identifies them uniquely. However, the badge alone does not grant access to all areas. Instead, the security guard (IAM system) checks a central directory that maps each employee to specific roles (e.g., 'Finance Team', 'IT Admin'). Each role has a set of permissions (bindings) that allow entry to certain doors: Finance role allows access to the 3rd floor finance office and the server room only during business hours; IT Admin role allows 24/7 access to the server room and the network closet. When an employee swipes their badge at a door, the guard looks up the employee's role, checks the bindings for that role, and decides whether to unlock the door. The guard does not care which specific employee is at the door—only whether that employee's role permits entry. If an employee is reassigned, the guard simply updates the role mapping in the directory; the employee's badge remains the same. This decoupling of identity (badge) from permissions (role bindings) is the essence of IAM: principals are authenticated, roles define what they can do, and bindings attach those roles to principals for specific resources (doors).

How It Actually Works

What Are IAM Principals?

In Google Cloud IAM, a principal is an identity that can be granted access to resources. Principals can be: - Google Account: A specific user's email address (e.g., user@gmail.com). - Service Account: An identity for an application or a virtual machine (e.g., my-sa@project.iam.gserviceaccount.com). - Google Group: A collection of users and service accounts (e.g., admins@example.com). - Google Workspace Domain: All identities within a Google Workspace domain (e.g., example.com). - Cloud Identity Domain: Similar to Workspace but for Cloud Identity customers. - All Authenticated Users: A special identifier that includes any principal authenticated with a Google account or service account. - All Users: A special identifier that includes anyone on the internet, including unauthenticated users. This is rarely used due to security risks.

Each principal has a unique identifier. For users, this is their email address; for service accounts, it is the service account email. The IAM system uses these identifiers to evaluate policies.

How IAM Works Internally — The Policy Evaluation Engine

When a principal makes an API call to a Google Cloud service, the following steps occur:

1.

Authentication: The request includes credentials (OAuth 2.0 token, service account key, etc.). Google's authentication layer verifies the identity and extracts the principal's email.

2.

Policy Retrieval: The IAM system retrieves all IAM policies that apply to the target resource. IAM policies are attached at the project, folder, and organization levels (hierarchical), and also directly on individual resources (like a Cloud Storage bucket). The effective policy for a resource is the union of all policies inherited from ancestors plus any resource-specific policy. Deny policies (introduced later) are also evaluated.

3.

Binding Evaluation: Each IAM policy consists of a list of bindings. A binding binds a single role to a set of principals. For example:

bindings:
- members:
  - user:alice@example.com
  - serviceAccount:my-sa@project.iam.gserviceaccount.com
  role: roles/storage.objectViewer

This binding grants the roles/storage.objectViewer role to both Alice and the service account.

4.

Role Permission Mapping: Each role contains a list of permissions. For example, roles/storage.objectViewer includes permissions like storage.objects.get and storage.objects.list. The IAM system checks if the role in any binding that includes the requesting principal contains the permission required for the API call.

5.

Decision: If any binding grants the required permission, access is allowed. If no binding grants it, access is denied. If a deny policy explicitly denies the permission, access is denied regardless of allow bindings (deny takes precedence).

Key Components in Detail

Roles are collections of permissions. There are three types: - Basic Roles: Owner, Editor, Viewer. These are legacy roles that apply to all resources in a project. They are broad and not recommended for production use. - Predefined Roles: Fine-grained roles created by Google Cloud for specific services. Examples: roles/storage.objectViewer, roles/compute.instanceAdmin.v1. These are the recommended roles for least privilege. - Custom Roles: User-defined roles that aggregate specific permissions. You create them at the project or organization level. Example: a custom role with only compute.instances.start and compute.instances.stop permissions.

Bindings are the glue that connects principals to roles. A binding in a policy looks like:

- members:
  - user:alice@example.com
  role: roles/compute.instanceAdmin.v1

Note: A single binding can list multiple members, but each member-role pair is effectively a grant.

Permissions are the atomic units of access. They are strings like compute.instances.create. Permissions are not directly assigned to principals; they are always grouped into roles.

Hierarchical Policy Inheritance

IAM policies are hierarchical. You can set policies at the organization, folder, project, and resource levels. The effective policy for a resource is the union of all policies from the resource's ancestors (organization, folder, project) plus any policy directly on the resource. This means that if you grant a role at the organization level, it applies to all projects and resources under that organization. However, inheritance is additive: you cannot restrict permissions at a lower level if a higher level grants them. For example, if a user has roles/editor at the project level, you cannot remove their ability to delete a specific bucket by setting a more restrictive policy on that bucket. To restrict, you must use deny policies or change the higher-level policy.

Deny Policies (Introduced in 2021)

Deny policies allow you to explicitly deny access to principals for specific permissions, even if an allow policy grants them. Deny policies are evaluated after allow policies and take precedence. They are defined at the organization, folder, or project level using the Deny rule set. Example YAML:

denied:
  - denial_condition:
      expression: "resource.name.startsWith('projects/_/buckets/secret-bucket')"
    denied_principals:
    - principalSet://goog/public:allUsers
    denied_permissions:
    - storage.objects.get

This denies all users (including authenticated) the ability to read objects in any bucket whose name starts with 'secret-bucket'.

Service Accounts: Special Principals

Service accounts are a special type of principal used by applications and VMs. They have their own email and can be granted roles like any user. However, unlike users, they authenticate using keys (RSA key pairs) or by attaching to Compute Engine instances. When a VM runs with a service account, the instance's metadata includes the service account email. The instance can then request OAuth tokens via the metadata server. Service accounts are essential for secure application-to-API communication without storing user credentials.

Default Values and Quotas

IAM policies have a maximum size of 64 KB per resource.

A single binding can include up to 1,500 members (but this is a soft limit).

Custom roles can contain up to 3,000 permissions (combined from a list of available permissions).

You can create up to 300 custom roles per project or organization.

Deny policies are limited to 10 per organization, 10 per folder, and 10 per project.

Configuration Commands

To view IAM policies:

gcloud projects get-iam-policy PROJECT_ID

To add a binding:

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member user:alice@example.com \
    --role roles/storage.objectViewer

To remove a binding:

gcloud projects remove-iam-policy-binding PROJECT_ID \
    --member user:alice@example.com \
    --role roles/storage.objectViewer

To create a custom role:

gcloud iam roles create customRole --project PROJECT_ID \
    --title "Custom Role" --permissions compute.instances.start,compute.instances.stop

Interaction with Resource Manager

IAM is tightly integrated with Google Cloud Resource Manager. The resource hierarchy (Organization > Folder > Project > Resources) directly influences policy inheritance. When you grant a role at the organization level, it trickles down to all folders and projects. This allows for centralized access control. However, it also means that a mistake at a high level can grant unintended access across the entire organization.

Common Exam Scenarios

Least privilege: Always use predefined or custom roles instead of basic roles.

Service accounts: Understand that service accounts are identities, not resources. They can be granted roles, and they can also be impersonated by users.

Deny policies: Know that deny policies can override allow policies, but they are not a substitute for proper allow policy design.

Inheritance: A policy set at the project level applies to all resources in that project unless overridden by a deny policy.

AllUsers vs AllAuthenticatedUsers: allUsers includes unauthenticated users; allAuthenticatedUsers requires authentication. The exam expects you to choose the more restrictive option for security.

Edge Cases

Conditional bindings: IAM supports conditions that grant access only when specific attributes are met (e.g., resource tags, request time). Conditions are evaluated at access time.

Service account impersonation: A user with iam.serviceAccounts.actAs permission can impersonate a service account, inheriting its roles. This is commonly used for deployment pipelines.

Primitive roles: The basic roles (Owner, Editor, Viewer) are not recommended, but they still exist. The exam may ask why they are insecure: they grant permissions across all services, violating least privilege.

Verification and Debugging

To test what permissions a principal has on a resource, use the TestIamPermissions API or the gcloud command:

gcloud projects get-iam-policy PROJECT_ID \
    --filter="bindings.members:user:alice@example.com"

For a more comprehensive check, use the Policy Analyzer in the Cloud Console, which simulates access and identifies over-permissioned principals.

Summary of Best Practices

Use groups to manage principals instead of individual users.

Prefer predefined roles over custom roles when possible.

Implement deny policies for sensitive resources as a safety net.

Regularly audit IAM policies using Cloud Asset Inventory and Policy Analyzer.

Use conditional bindings to scope access based on attributes.

Walk-Through

1

Principal Authentication

The principal presents credentials (e.g., OAuth2 token, service account key) to the Google Cloud API endpoint. The authentication layer validates the token using Google's public keys. If valid, the system extracts the principal's email (e.g., user@example.com or my-sa@project.iam.gserviceaccount.com). This email becomes the identity used in policy evaluation. If authentication fails, the request is rejected with a 401 Unauthorized error before any policy evaluation occurs.

2

Resource Policy Retrieval

The IAM system identifies the target resource (e.g., a Cloud Storage bucket) and retrieves all IAM policies that apply to it. This includes the policy directly attached to the resource, plus policies from its ancestors in the resource hierarchy (project, folder, organization). The effective policy is computed by merging all these policies. Deny policies at any level are also collected. The system caches policies for a few seconds to improve performance, but changes propagate within 60-120 seconds typically.

3

Binding Matching

For each binding in the effective policy, the system checks if the principal's email appears in the `members` list. Members can be specified with prefixes like `user:`, `serviceAccount:`, `group:`, `domain:`, or `principalSet://`. The system expands groups recursively (up to a depth of 10). If the principal is a member of a group listed in a binding, that binding is considered matching. This step is computationally efficient because the system has precomputed group membership.

4

Role Permission Check

For each matching binding, the system looks up the role's permission list. Roles are defined in a global registry. The system checks if the required permission (e.g., `storage.objects.get`) is included in the role. If the role is a custom role, its permissions are stored in the project or organization. If a binding matches but the role does not contain the required permission, that binding does not grant access. The system continues checking other bindings.

5

Deny Policy Evaluation

If any allow binding grants the required permission, the system then evaluates deny policies. Deny policies are checked in the same hierarchical order. If a deny policy explicitly denies the permission for the principal (or a group they belong to), access is denied regardless of allow bindings. Deny policies can include conditions (e.g., only deny if the request is from outside a specific IP range). If the condition evaluates to true, the deny takes effect.

6

Access Decision

If no deny policy matches and at least one allow binding grants the permission, access is allowed. Otherwise, access is denied. The decision is returned to the service, which either processes the request or returns a 403 Forbidden error. The entire evaluation typically takes less than 100ms. Audit logs are generated for all access decisions, including the reason for denial (e.g., 'permission denied because no binding grants the required permission').

What This Looks Like on the Job

Scenario 1: Multi-Project Enterprise with Centralized Security

A large enterprise has 50 projects across 4 folders (Dev, Test, Staging, Production). The security team wants to grant a group of auditors read-only access to all resources in the production folder. They create a Google Group auditors@company.com and grant it the roles/viewer role at the production folder level. This single binding gives all auditors read access to every project and resource under that folder. The auditors can view instances, buckets, and databases but cannot modify anything. This is efficient because adding a new auditor only requires adding them to the group; the IAM policy does not need to change. The security team also creates a deny policy that prevents any auditor from accessing the 'finances' bucket, even though viewer role would normally allow it. This is done with a deny policy at the project level that denies storage.objects.get for the group auditors@company.com on resources with the tag 'sensitive'. This demonstrates the power of hierarchical policies combined with deny policies.

Scenario 2: Application Using Service Accounts for Microservices

A SaaS application runs on Google Kubernetes Engine (GKE) with multiple microservices. Each microservice needs to read from a specific Cloud Storage bucket and write to a specific Pub/Sub topic. The team creates a service account for each microservice, e.g., user-service-sa@project.iam.gserviceaccount.com. Each service account is granted the minimal roles: roles/storage.objectViewer on the appropriate bucket and roles/pubsub.publisher on the appropriate topic. The service accounts are attached to the GKE pods via workload identity. This ensures that if one microservice is compromised, the attacker cannot access other resources. The team also sets up a custom role for a third microservice that needs to start and stop Compute Engine instances but not delete them. They create a custom role with only compute.instances.start and compute.instances.stop permissions. This is a textbook example of least privilege.

Scenario 3: Temporary Access for Incident Response

During a security incident, an on-call engineer needs elevated privileges to investigate a compromised VM. The team uses IAM conditions to grant roles/compute.admin to the engineer only when the request comes from a specific IP range (the corporate VPN) and only for the next 2 hours. The condition is expressed using Common Expression Language (CEL): request.time < timestamp('2025-03-15T10:00:00Z') && request.auth.claims.ip == '203.0.113.0/24'. This ensures the engineer cannot use the privileges outside the incident window or from an untrusted network. This is far more secure than permanently granting admin access.

Common Misconfigurations

Overly broad basic roles: Using Owner or Editor instead of predefined roles. This grants permissions to all services, not just those needed.

Forgetting to remove old bindings: When employees leave, their IAM bindings remain. Regular audits using Cloud Asset Inventory are essential.

Incorrect member prefix: Using user: instead of serviceAccount: for a service account leads to an invalid binding that silently fails.

Deny policy conflicts: Creating deny policies that accidentally block legitimate access, e.g., denying storage.objects.get to all users when the application relies on public access.

How GCDL Actually Tests This

What the GCDL Exam Tests

The GCDL exam (Objective 2.5: IAM Concepts) focuses on understanding the difference between principals, roles, and bindings, and how they interact. Expect questions that ask you to identify the correct IAM component for a given scenario. The exam also tests hierarchical policy inheritance, the difference between basic and predefined roles, and when to use service accounts vs. user accounts.

Common Wrong Answers and Traps

1.

Confusing roles with permissions: Candidates often think that a role *is* a permission. In reality, a role is a *collection* of permissions. The exam may ask 'What is the smallest unit of access in IAM?' The answer is 'permission', not 'role'. Another trap: 'Which of the following is a role?' with options like storage.objects.get (permission) and roles/storage.objectViewer (role).

2.

Misunderstanding inheritance: A common wrong answer is that a policy set at the project level *overrides* a policy at the folder level. Actually, they are additive. If a user has a role at the folder level, they retain it in all child projects. The exam may describe a scenario where a user is denied access at the project level but granted at the folder level, and ask what happens. The correct answer is that the user has access because inheritance adds, not overrides.

3.

Assuming service accounts are users: Service accounts are not users; they are application identities. They cannot log in via the console (unless impersonated). The exam may ask which principal type is best for a VM application. The wrong answer is 'a Google Account' because that would require storing user credentials on the VM, which is insecure.

4.

Overlooking deny policies: Before deny policies existed, the only way to restrict was to not grant. Now, deny policies can explicitly block access. The exam may present a scenario where a user has a role that grants access, but a deny policy exists. The correct answer is that access is denied because deny takes precedence.

Specific Numbers and Terms to Memorize

The three basic roles: Owner (roles/owner), Editor (roles/editor), Viewer (roles/viewer).

The special identifiers: allUsers and allAuthenticatedUsers.

The maximum policy size: 64 KB.

The prefix for service accounts: serviceAccount:.

The prefix for groups: group:.

The command to view IAM policy: gcloud projects get-iam-policy.

The command to add a binding: gcloud projects add-iam-policy-binding.

Edge Cases the Exam Loves

Conditional bindings: The exam may ask what happens when a condition is not met. Answer: the binding does not grant access, but other bindings may still grant it.

Service account impersonation: A user with iam.serviceAccounts.actAs can impersonate a service account. The exam may ask which permission allows impersonation.

Custom role limitations: Custom roles cannot include permissions from services that are not yet in the allowlist. The exam may ask where custom roles are defined (project or organization level).

How to Eliminate Wrong Answers

If the question mentions 'least privilege', eliminate any answer that uses basic roles (Owner, Editor, Viewer).

If the question involves a group, remember that groups can contain users and service accounts, and they are managed outside IAM (in Google Groups or Cloud Identity).

If the question asks about 'allUsers', remember that this includes unauthenticated users. For any security-conscious scenario, choose allAuthenticatedUsers instead.

If the question involves inheritance, draw the hierarchy: Organization > Folder > Project > Resource. Policies flow downward.

Key Takeaways

IAM has three core components: principals (who), roles (what), and bindings (how they connect).

Roles are collections of permissions; permissions are the atomic unit of access.

IAM policies are hierarchical: Organization > Folder > Project > Resource. Inheritance is additive, not overriding.

Deny policies take precedence over allow policies and can block access even if a role grants it.

Service accounts are application identities; they cannot log in to the console but can be impersonated.

Basic roles (Owner, Editor, Viewer) are broad and should be avoided in favor of predefined or custom roles.

Use groups to manage principals at scale; add users to groups instead of modifying IAM policies.

Conditions can restrict access based on attributes like IP address, time, or resource tags.

The maximum IAM policy size is 64 KB; a binding can have up to 1,500 members.

Audit IAM policies regularly with Cloud Asset Inventory and Policy Analyzer.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

Basic Roles (Owner, Editor, Viewer)

Apply to all resources in a project (broad scope).

Include many permissions, violating least privilege.

Cannot be customized; you get all or nothing.

Legacy roles; not recommended for production.

Example: roles/editor grants write access to all services.

Predefined Roles

Apply to specific services (e.g., roles/storage.objectViewer).

Include only the permissions needed for that service.

Created and maintained by Google Cloud.

Recommended for production use to enforce least privilege.

Example: roles/storage.objectViewer only allows read access to Storage.

Watch Out for These

Mistake

IAM roles are the same as permissions.

Correct

Roles are collections of permissions. A permission is an atomic action (e.g., `storage.objects.get`), while a role groups multiple permissions (e.g., `roles/storage.objectViewer` includes `storage.objects.get` and `storage.objects.list`). You cannot assign a permission directly to a principal; you must assign a role.

Mistake

If a user has a role at the project level, they automatically have that role on all resources in the project, and you can remove it by setting a more restrictive policy on a specific resource.

Correct

Inheritance is additive, not overriding. If a user has a role at the project level, they have it on all resources in that project. You cannot remove that access by setting a policy on an individual resource that denies the permission. To restrict, you must either use a deny policy or change the project-level policy.

Mistake

Service accounts are like user accounts and can log in to the Cloud Console.

Correct

Service accounts are not user accounts. They cannot log in to the Cloud Console interactively. They are used by applications to authenticate to Google Cloud APIs. However, a user with the `iam.serviceAccounts.actAs` permission can impersonate a service account and perform actions as that service account.

Mistake

The `allUsers` identifier only includes authenticated Google users.

Correct

`allUsers` includes anyone on the internet, including unauthenticated users. If you grant a role to `allUsers`, anyone can access the resource without authentication. This is extremely dangerous and rarely used. The more restrictive `allAuthenticatedUsers` includes only users who have authenticated with a Google account or service account.

Mistake

IAM policies are evaluated only at the resource level, not at the project or organization level.

Correct

IAM policies can be set at the organization, folder, project, and resource levels. The effective policy for a resource is the union of all policies from the ancestors and the resource itself. This hierarchical evaluation is fundamental to understanding access control in Google Cloud.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

What is the difference between a role and a permission in Google Cloud IAM?

A permission is a specific action that can be performed on a Google Cloud resource, like `compute.instances.create`. A role is a collection of permissions. You cannot assign a permission directly to a user; you must assign a role. For example, the role `roles/compute.instanceAdmin.v1` includes permissions like `compute.instances.create`, `compute.instances.delete`, and others. On the exam, remember that roles are the unit of assignment, not permissions.

Can I set an IAM policy on an individual resource like a Cloud Storage bucket?

Yes, you can set IAM policies directly on many resources, including Cloud Storage buckets, Cloud SQL instances, and Pub/Sub topics. This resource-level policy is combined with policies inherited from the project, folder, and organization. The effective policy is the union of all these policies. However, you cannot use a resource-level policy to override a broader policy; you can only add more permissions. To restrict, use a deny policy.

How do I grant a service account access to a resource?

You grant a service account access the same way you grant a user: by adding the service account as a member in an IAM binding. Use the prefix `serviceAccount:` followed by the service account email. For example: `gcloud projects add-iam-policy-binding PROJECT_ID --member serviceAccount:my-sa@project.iam.gserviceaccount.com --role roles/storage.objectViewer`. The service account can then authenticate using its key or by being attached to a Compute Engine instance.

What is the purpose of a deny policy in IAM?

A deny policy explicitly denies access to principals for specific permissions, even if an allow policy grants them. Deny policies are evaluated after allow policies and take precedence. They are useful for adding an extra layer of security, such as preventing all users (including admins) from accessing a highly sensitive bucket. Deny policies are set at the organization, folder, or project level and can include conditions.

What happens if a user is a member of a group that has a role, but the user also has a deny policy that denies that role's permissions?

The deny policy takes precedence over the allow binding from the group. Even though the user inherits the role via group membership, the deny policy explicitly denies the permission, so access is denied. This is because deny policies are evaluated after allow policies and override them. The order of evaluation is: allow bindings from all levels, then deny policies.

What is the difference between allUsers and allAuthenticatedUsers?

`allUsers` includes anyone on the internet, including unauthenticated users. `allAuthenticatedUsers` includes only users who have authenticated with a Google account (or service account). Using `allUsers` is highly insecure because it grants access to anyone without requiring login. The exam expects you to choose `allAuthenticatedUsers` for scenarios that require authentication.

How do I check what permissions a user has on a project?

You can use the gcloud command `gcloud projects get-iam-policy PROJECT_ID` and filter for the user, or use the Policy Analyzer in the Cloud Console. The Policy Analyzer allows you to simulate access and see exactly which roles grant which permissions. You can also use the TestIamPermissions API programmatically.

Terms Worth Knowing

Ready to put this to the test?

You've just covered IAM Concepts: Principals, Roles, and Bindings — now see how well it sticks with free GCDL practice questions. Full explanations included, no account needed.

Done with this chapter?