---
cuppy_hub: gcp
cuppy_path: reference/identity/iam-model.md
cuppy_section: docs
cuppy_doc: BAQP-PGEN
cuppy_doc_uuid: 8d6e305c-d7d0-4248-a715-68b8ab1ae1a2
cuppy_permalink: https://cuppy.io/gcp/d/BAQP-PGEN
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/gcp/docs/reference/identity/iam-model
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: f35a5bab6fd8b1b7cd10fef684a18c395b20f4c9a4734ff97abb4875f3626ffc
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Google Cloud IAM — the model

## 1. The five nouns

| Noun | What it is |
|---|---|
| **principal** | the identity a permission is granted to |
| **permission** | one named ability, formatted `service.resource.verb` — the overview's own example is `resourcemanager.projects.list` |
| **role** | a collection of permissions. A permission is never granted directly to a principal; a role is |
| **resource** | the Google Cloud asset access is controlled on |
| **allow policy** | the object that grants roles to principals on a resource. It is made of **role bindings**, which "associate IAM roles with the principals who are granted those roles" |

Two further policy objects exist and are not the same thing as an allow policy:

- a **deny policy** prevents a principal from using certain permissions, and the overview states it holds "even
  if they're granted a role with the permission". **Deny overrides allow.** If a caller is refused while
  holding what looks like the right role, a deny policy is the first thing to look for, not the last.
- a **Principal Access Boundary (PAB) policy** defines which resources a principal is *eligible* to access at
  all. It is a third, outer bound, independent of both of the above.

## 2. Inheritance runs one way, and only down

The resource hierarchy is **organization → folders (optional) → projects → service resources**. An allow
policy set at one level is inherited by everything below it: the resource-hierarchy page's wording for the top
level is that policies applied there are "inherited by every resource in the organization".

The reading an agent must take from this: **a grant cannot be removed by a policy on a child.** Taking a
binding off a project does not take away a binding the principal holds at the folder or organization above it.
Only a deny policy or a PAB policy narrows an inherited grant.

See `reference/overview/projects-and-resource-hierarchy.md` for the hierarchy itself and what else inherits
through it (organization policies, labels, billing).

## 3. The three role types, and the one that is a mistake in production

| Type | Shape | Use |
|---|---|---|
| **predefined** | `roles/<service>.<roleName>`, Google-managed | the default choice |
| **custom** | yours, from a list of permissions | when no predefined role is close enough |
| **basic** | `Owner`, `Editor`, `Viewer` | the IAM overview calls them "highly permissive, unsuitable for production" |

Named roles and the permission-to-role lookup: `reference/identity/predefined-roles-and-permissions.md`.

## 4. The eventual-consistency trap

The IAM overview states the IAM API is **eventually consistent**: a change "might take time to affect access
checks". So the failure mode is a test that runs immediately after a `gcloud ... add-iam-policy-binding` and
fails with a permission error that is already fixed. **Retry a permission failure once after a grant before
you debug it**; do not change the policy again on the first failure, because a second concurrent change to the
same policy is how a binding gets lost (read-modify-write on a policy with a stale `etag`).

## 5. The limits that are limits, not quotas

IAM's quotas page separates the two and says of the first group, verbatim, **"Limits cannot be changed."** The
ones an agent actually hits:

| Fixed limit | Value, as the page states it |
|---|---|
| total principals in one allow policy | 1,500 |
| deny policies per resource | 500 |
| custom roles per project | 300 |
| custom roles per organization | 300 |
| service account keys per service account | 10 |
| access boundary rules | 10 |
| maximum access token lifetime | 3,600 seconds, extendable to 12 hours by an organization policy |

Rate quotas (IAM API reads and writes per project per minute, Service Account Credentials API requests) are
adjustable; the page's own instruction is to "use the Google Cloud console to request a quota adjustment for
your project". **This hub never types an adjustable value** — read it live, see
`reference/overview/quotas-and-limits-model.md`.

The 1,500-principal ceiling is the one that changes a design: a policy that names individual principals runs
out, a policy that names groups does not.

## 6. When a call is refused

Go to `reference/identity/errors.md` for the verbatim strings and `guides/identity/fix-permission-denied.md`
for the order to check things in.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 91 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/gcp/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
