Skip to main content
Back
DateRead6 min

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

CharacteristicIAM ConditionsOrganization Policy
What it governsWhether a specific role binding is active for a specific principalWhether a configuration is allowed to exist on a resource, independent of identity
Scope of a single ruleOne role binding, for one principal or group, on one resourceOne 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 entirelyYes. It holds even against a project owner's or org admin's own IAM permissions
Inheritance modelAdditive only. The effective policy is the union of every binding up the hierarchy, and a lower level can't revoke what a parent grantedDepends on constraint type. Boolean constraints let the nearest node override its parent; list constraints merge with or replace the parent based on inheritFromParent
Expression languageCEL, evaluated against attributes like resource.name, resource.type, resource.service, and request.timeCEL, but only inside a custom constraint's condition, evaluated against resource fields the target service has exposed to Organization Policy
Built-in expirationYes. A condition like request.time < timestamp(...) expires a grant nativelyNo. Enforcement is binary and permanent until someone edits the policy
Coverage limitationNot every Google Cloud service or resource type supports conditional role bindingsNot 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 allAuthenticatedUsersNot applicable. Organization Policy doesn't grant roles to principals at all, so this restriction doesn't carry over
Who can edit the ruleWhoever can edit the IAM policy on that resource, typically roles/resourcemanager.projectIamAdmin or Owner at the project levelRequires roles/orgpolicy.policyAdmin, a role that exists only at the organization level, never at the project level
Practical scale limitGoogle recommends no more than 100 conditional role bindings in a single allow policy, since conditions count against the policy's overall size limitNo comparable per-resource cap; the limits sit at the access-policy level (perimeters, constraints per org) rather than per binding
Infrastructure as codeTerraform's google_project_iam_member (or equivalent) resource, using its condition blockTerraform's google_org_policy_policy resource
Typical use caseTime-boxed elevated access, access scoped to a specific resource or tagBlocking a class of configuration org-wide: public IPs, service account key creation, resource location

Which Layer Should Enforce the Rule?

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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, or allAuthenticatedUsers. 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:

YAML
name: organizations/123456789012/policies/sql.restrictPublicIp
spec:
 rules:
 - enforce: true

This 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:

bash
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.

Ready to enforce secure-by-design?