IAM, conditions & deny policies
Additive allows, conditions, and enforceable denies.
GCP IAM is deceptively simple — bindings of principals to roles on resources — but the details that matter for security are the role granularity, how policies compose across the hierarchy, and the newer deny policies that let you write true guardrails.
Roles, conditions, and least privilege
Avoid the basic roles (Owner/Editor/Viewer) — Editor alone can modify almost everything. Prefer predefined roles, which Google keeps current as APIs evolve, and reach for custom roles only when no predefined role fits (accepting that you must maintain them). IAM Conditions tighten a grant further: access only to resources with a name prefix, only from a corporate network, or only during a change window. Bind roles to Google Groups rather than individuals so membership changes in your IdP flow through without editing IAM.
# Grant object read ONLY on buckets whose name starts with "reports-",# and only to the analytics group — not project-wide storage access.gcloud projects add-iam-policy-binding payments-prod \--member="group:[email protected]" \--role="roles/storage.objectViewer" \--condition='expression=resource.name.startsWith("projects/_/buckets/reports-"),title=reports-only'
How policies compose — and deny policies
Allow policies are additive and inherited down the hierarchy: a principal’s effective access is the union of every binding from the organization down to the resource. There is no allow-override — only accumulation — which is why a stray Editor binding at a folder is dangerous. IAM deny policies close that gap: they are evaluated before allows and block matching principals from named permissions regardless of any grant, giving you an enforceable "nobody outside break-glass may delete logs" rule.