GCP IAM Conditions vs Organization Policy: Which Layer Should Enforce the Rule?
Key Takeaways
- The choice comes down to who the rule needs to bind to. Neither construct is stronger than the other. IAM Conditions attach a rule to one principal's role binding. Organization Policy attaches a rule to a resource hierarchy node, and it holds no matter who's asking, including the organization's own admins.
- A conditional IAM binding doesn't override an unconditional one for the same role. Google states this directly: conditional role bindings don't override role bindings with no conditions. A carefully scoped condition can end up doing nothing if a broader, unconditional grant exists elsewhere.
- The two inherit in opposite directions. IAM's allow policies are additive only: a lower level can never revoke what a parent granted. Organization Policy's boolean constraints do the opposite: the nearest node in the hierarchy wins, so a child can override its parent outright. Assuming they behave the same way is a common design mistake.
- They're built to stack, and each one covers what the other can't. A rule that has to hold for every principal, permanently, belongs in Organization Policy. A temporary or principal-specific exception belongs in an IAM Condition sitting on top of whatever Organization Policy already enforces.
The Verdict
If the rule depends on who's making the request, especially if the need is temporary, scope it as an IAM Condition on the role binding. If the rule needs to hold no matter who's asking, including your own org admins, and it's meant to be permanent, put it in Organization Policy. The two constructs answer different questions, evaluated at different points in the request, and most rules that look like an either/or choice are asking for both, layered. This page assumes some familiarity with both constructs; for the full mechanics of each, see GCP IAM Conditions Explained and GCP Organization Policy Explained.
GCP IAM Conditions vs Organization Policy: Side by Side
| Characteristic | IAM Conditions | Organization Policy |
|---|---|---|
| What it governs | Whether a specific role binding is active for a specific principal | Whether a configuration is allowed to exist on a resource, independent of identity |
| Scope of a single rule | One role binding, for one principal or group, on one resource | One constraint, applied at an organization, folder, or project node |
| Holds against org admins? | No. An admin can create a new unconditional binding for the same role and bypass the condition entirely | Yes. It holds even against a project owner's or org admin's own IAM permissions |
| Inheritance model | Additive only. The effective policy is the union of every binding up the hierarchy, and a lower level can't revoke what a parent granted | Depends on constraint type. Boolean constraints let the nearest node override its parent; list constraints merge with or replace the parent based on inheritFromParent |
| Expression language | CEL, evaluated against attributes like resource.name, resource.type, resource.service, and request.time | CEL, but only inside a custom constraint's condition, evaluated against resource fields the target service has exposed to Organization Policy |
| Built-in expiration | Yes. A condition like request.time < timestamp(...) expires a grant natively | No. Enforcement is binary and permanent until someone edits the policy |
| Coverage limitation | Not every Google Cloud service or resource type supports conditional role bindings | Not every configuration has a managed constraint, and a custom constraint only covers fields a service has instrumented for Organization Policy |
| Works with basic roles or public principals? | No. Conditions can't be attached when granting legacy basic roles (Owner, Editor, Viewer) or when granting to allUsers or allAuthenticatedUsers | Not applicable. Organization Policy doesn't grant roles to principals at all, so this restriction doesn't carry over |
| Who can edit the rule | Whoever can edit the IAM policy on that resource, typically roles/resourcemanager.projectIamAdmin or Owner at the project level | Requires roles/orgpolicy.policyAdmin, a role that exists only at the organization level, never at the project level |
| Practical scale limit | Google recommends no more than 100 conditional role bindings in a single allow policy, since conditions count against the policy's overall size limit | No comparable per-resource cap; the limits sit at the access-policy level (perimeters, constraints per org) rather than per binding |
| Infrastructure as code | Terraform's google_project_iam_member (or equivalent) resource, using its condition block | Terraform's google_org_policy_policy resource |
| Typical use case | Time-boxed elevated access, access scoped to a specific resource or tag | Blocking a class of configuration org-wide: public IPs, service account key creation, resource location |
Which Layer Should Enforce the Rule?
- Does the rule depend on who's making the request? If the rule should apply no matter which principal is involved, that's not an identity question at all. It belongs in Organization Policy. If it does depend on who's asking, move to the next question.
- Does the rule need to hold even against the organization's own admins? If yes, use Organization Policy. IAM Conditions only govern the specific bindings they're attached to, and nothing stops a separate unconditional binding from granting the same access outside the condition's reach. If the rule only needs to constrain a particular grant, an IAM Condition on that binding is enough.
- Is the need temporary? An on-call window, a time-boxed migration, or a contractor's engagement each has a natural expiration, and IAM Conditions support that natively with a time-based expression. Organization Policy has no native expiration; someone has to remember to revert it manually.
- Is there a managed or custom Organization Policy constraint that covers this configuration? If the configuration you're trying to control isn't covered by a managed constraint and can't be expressed as a custom one because the service hasn't exposed the relevant field, an IAM Condition scoped to that resource or tag may be the only enforceable option, even though it's less structurally permanent than a policy would be.
- Is the grant itself a basic role, or is it going to a public principal? IAM Conditions can't attach to
Owner, Editor, Viewer, allUsers,orallAuthenticatedUsers.If that's what the grant needs to be, move the condition onto a predefined or custom role instead of the basic one, or reframe the rule as a configuration restriction and enforce it through Organization Policy.
Using Both Together: A Worked Example
An organization wants two things at once: production Cloud SQL instances should never be reachable by a public IP, for every principal, permanently; and a specific on-call engineer needs temporary Cloud SQL admin access on one project during a scheduled maintenance window.
The two requirements sit at different layers of the same policy.
Organization Policy handles the permanent, identity-independent rule:
name: organizations/123456789012/policies/sql.restrictPublicIp
spec:
rules:
- enforce: trueThis holds regardless of who's provisioning the instance, including the on-call engineer once their access is granted.
IAM Conditions handle the temporary, principal-specific grant:
gcloud projects add-iam-policy-binding maintenance-project-id \
--member='user:oncall-engineer@example.com' \
--role='roles/cloudsql.admin' \
--condition='expression=request.time < timestamp("2026-09-01T06:00:00Z"),title=maintenance-window,description=Expires after the scheduled maintenance window'The engineer gets roles/cloudsql.admin on the project until the timestamp passes. After that, the grant stops evaluating as true and the role no longer applies. At no point during that window can the engineer configure a public IP on a production instance, because the Organization Policy constraint sits underneath the IAM grant and evaluates independently of it. Neither layer has to be aware of the other for both rules to hold.
Native maps whether IAM Conditions or Organization Policy is carrying each compliance requirement across a Google Cloud environment, and enforces the requirement through Organization Policy when the framework it's meant to satisfy calls for something structural rather than a conditional binding. See how Native handles compliance enforcement across Google Cloud.
FAQ
Can IAM Conditions replace Organization Policy?
No. IAM Conditions only affect the specific role binding they're attached to. A rule that needs to hold against every principal, including admins who could create a new unconditional binding, belongs in Organization Policy instead.
Can Organization Policy replace IAM Conditions?
No. Organization Policy has no concept of identity or time-based expiration. It can block a class of configuration outright, but it can't grant a specific engineer temporary elevated access the way an IAM Condition can.
Why didn't my IAM Condition restrict access?
The most common cause is an unconditional binding for the same role that still applies elsewhere in the hierarchy. Conditional role bindings don't override unconditional ones, so if a principal already holds the role without a condition, adding a conditional binding changes nothing. Check the effective policy at the resource with gcloud projects get-iam-policy rather than assuming the condition you added is the only grant in play.
Do IAM Conditions and Organization Policy inherit the same way?
No, and assuming they do is a common design mistake, especially for anyone used to how the other one behaves. Grant a broad IAM role at the organization level and no project underneath can revoke it, only add to it. Set a boolean Organization Policy constraint at the organization level and a project underneath can flip it back off, unless something else locks down who's allowed to edit policies. Design each hierarchy with that difference in mind rather than assuming one inheritance model governs both.
Which one should I use to restrict where resources can be created?
Organization Policy, using a constraint like gcp.resourceLocations, if the restriction should apply to every principal permanently. Use an IAM Condition referencing resource.name or a resource tag only if the restriction is meant to apply to a specific principal's grant rather than the configuration itself.
Can I add an IAM Condition to a basic role like Owner or Editor?
No. Conditions can't be attached when granting a legacy basic role (Owner, Editor, or Viewer), nor when granting to allUsers or allAuthenticatedUsers. If the grant has to use one of those, a condition isn't an option, and the rule needs to move to a predefined or custom role, or to Organization Policy if it's a configuration question rather than an identity one.
Who has the authority to edit each one, and why does that matter?
Editing an IAM binding usually just takes project-level IAM admin rights, which is often the same access the requester already has. Editing an Organization Policy requires roles/orgpolicy.policyAdmin, a role that exists only at the organization level. That gap is a large part of why Organization Policy holds against admins in practice: changing it takes a permission most project-level admins don't have, even ones with broad IAM access on the resources the policy governs.