
Why post-deployment alerts are failing your security posture, and how to stop missconfigurations before the API call even finishes.
Every platform team goes through the exact same four-stage security cycle:
- Freedom: Developers create resources fast. Things get shipped.
- The Audit: A scanner (Prisma, Wiz, or Security Command Center) is plugged in. It turns up 1,400 critical alerts: public Cloud Storage buckets, compute instances with exposed external IPs, and long-lived service account keys sitting in plaintext .env files.
- The Slog: Security teams flood Slack and Jira with remediation requests. DevOps spends months building reactive Cloud Functions to terminate rogue resources after they launch.
- Fatigue: Alerts become background noise. Someone creates a test VM with a public IP on a Friday afternoon, and an automated port scanner finds it before your scanner’s 15-minute polling interval even triggers.
- The fundamental flaw isn’t that developers don’t care about security; it’s that organizations treat cloud security as a detective problem rather than a preventative one.
IAM tells you who has permission to invoke an API. It does not dictate what configuration parameters that API call should accept. To build structural guardrails that developers cannot bypass — even with Owner or Editor permissions — you need the GCP Organization Policy Service.
1. The Core Paradigm: IAM vs. Org Policy
A frequent misconception among GCP practitioners is assuming robust IAM roles protect against architectural misconfigurations.
- IAM (Identity & Access Management): Regulates identities and operations. If a developer has roles/compute.instanceAdmin.v1, they can run gcloud compute instances create.
- Organization Policy: Regulates resource state and configurations globally. If the org policy says “No compute instance may have a public IP,” then even a project Owner executing gcloud compute instances create — address=”” will receive an instant 403 Precondition Failed error from the Google Cloud API gateway.
- The API call is evaluated and dropped at Google’s management layer. The VM is never scheduled, no disk is provisioned, and no reactive remediation runbook is required.
2. The Hierarchy and Inheritance Mechanics
Organization policies operate on the standard Google Cloud Resource Manager hierarchy:
Organization
└── Core-Services Folder
└── Environments Folder
├── Production Folder
│ └── Project: api-prod
└── Development Folder
└── Project: sandbox-lab
How Inheritance Evaluates
Policies set at a parent node cascade down to all child folders and projects. However, how they combine depends on the constraint type:
- Boolean Constraints: Binary toggles (e.g., enforce/do not enforce). A child can explicitly inherit or override the parent state.
- List Constraints: Can allow or deny specific string values (e.g., allowed resource locations). By default, child nodes inherit parent values. However, you can configure child policies to:
- Merge (inheritFromParent: true): Combine the child’s allowlist/denylist with the parent’s.
- Replace (inheritFromParent: false): Completely discard the parent’s rules for that specific node.
- Reset (reset: true): Revert the policy back to the default GCP behavior.
Production Tip: Never use “Replace” recklessly on production projects without auditing upstream inheritance. If an organization node denies 50 unauthorized geographic regions and a child project overrides without inheritance, that project silently permits global deployments.
3. The Foundational 5: Baseline Constraints for Every Org
Google manages 196 predefined Organization Policies aligned with GCP security best practices, available at no additional cost. Each constraint should be evaluated based on your organization’s specific security posture and business requirements.
In addition to these Google-managed constraints, customers can create Custom Organization Policies tailored to meet unique organizational needs.
If you manage a Google Cloud organization, considering these five constraints from day one can be a helpful way to strengthen your security across environments.
These are common policies that are widely recommended for every environment.
1. Kill Long-Lived Service Account Keys
- Constraint: constraints/iam.disableServiceAccountKeyCreation
- Type: Boolean
- Why: Service account user-managed JSON keys are the leading cause of GCP credential leaks in public GitHub repos. Enforcing this requires developers to use Workload Identity Federation (for external CI/CD like GitHub Actions or GitLab) and attached service accounts for compute workloads.
2. Block Public IP Addresses on VMs
- Constraint: constraints/compute.vmExternalIpAccess
- Type: List
- Rule: Deny all
- Why: Virtual machines should never be directly routable from the public internet. External entry should terminate at Cloud Load Balancing or Cloud Armor, with outbound traffic managed via Cloud NAT.
3. Enforce Uniform Bucket-Level Access
- Constraint: constraints/storage.uniformBucketLevelAccess
- Type: Boolean
- Why: Disables legacy Object ACLs across all Cloud Storage buckets. Permission management is centralized strictly via IAM, preventing scenarios where an individual file is marked allUsers:READER inside an otherwise private bucket.
4. Restrict Resource Locations (Data Residency)
- Constraint: constraints/gcp.resourceLocations
- Type: List
- Rule: Allow specific regions (e.g., in:eu-locations or in:us-locations)
- Why: Ensures compliance with GDPR, HIPAA, or sovereign data mandates by physically preventing services and storage from spinning up in unapproved geographies.
5. Disable Default Service Account Automatic Role Grants
- Constraint: constraints/resourcemanager.disableDefaultServiceAccountRoleGrant
- Type: Boolean
- Why: By default, creating a new project grants the legacy Compute Engine default service account the dangerous roles/editor role. This constraint stops that automatic assignment dead in its tracks.
4. The Rollout Strategy: How Not to Break Production
The number-one reason teams hesitate to deploy Org Policies is fear: “What if an automated CI/CD pipeline or third-party partner integration is deploying a resource that violates this rule right now?”
To solve this, Google introduced Dry-Run Mode.
Instead of switching a policy directly to enforced, you apply the policy spec under dryRunSpec. The policy engine evaluates all incoming API calls, but rather than blocking non-compliant requests, it logs the violation directly to Cloud Logging.
Incoming API Request
│
▼
[Org Policy Engine]
│
Violates Rule?
├── YES (Dry-Run) ──► Write Deny Log to Cloud Audit ──► Allow API to Proceed
└── YES (Enforced) ──► Write Deny Log to Cloud Audit ──► Terminate API (HTTP 403)
The 3-Step Zero-Downtime Rollout
Step A: Apply in Dry-Run
Configure the policy with dryRunSpec.
Step B: Query Violations in Cloud Logging
Use Log Analytics or this simple Cloud Logging query to catch any violations during a 14-day bake period:
protoPayload.metadata.@type="type.googleapis.com/google.cloud.orgpolicy.v2.AuditLogMetadata"
protoPayload.metadata.dryRunResult="DENIED"
Inspect the caller identities, service accounts, and projects generating violations, then work with those teams to refactor their infrastructure code (e.g., migrating off SA keys or removing external IP configurations).
Step C: Promote to Enforced
Once logs drop to zero, promote the dryRunSpec configuration to spec (active enforcement).
5. Beyond Out-of-the-Box: Custom Constraints with CEL
Predefined constraints are great, but enterprise infrastructure frequently has niche requirements. What if you want to ensure that Cloud Run services only accept traffic through an Internal Load Balancer, or that GKE clusters never launch without Workload Identity enabled?
GCP allows you to build Custom Constraints using Common Expression Language (CEL) on supported resource types.
Here is a practical example blocking any Cloud Run service from exposing direct, unauthenticated internet ingress:
# constraint-cloudrun-ingress.yaml
name: organizations/123456789012/customConstraints/custom.requireInternalCloudRun
resourceTypes:
- run.googleapis.com/Service
methodTypes:
- CREATE
- UPDATE
condition: "resource.traffic[0].percent == 100 && resource.template.metadata.annotations['run.googleapis.com/ingress'] != 'internal-and-cloud-load-balancing'"
action: DENY
displayName: "Force Internal-Only Ingress on Cloud Run"
description: "Prevents direct all-internet routing on Cloud Run; traffic must enter via Load Balancer."
Create the constraint using gcloud:
gcloud org-policies set-custom-constraint constraint-cloudrun-ingress.yaml
Once registered , the custom constraint behaves identically to native constraints: it can be applied to folders, projects, or org nodes, and supports dry-run testing.
6. Automating with Terraform (GitOps Guardrails)
Hardcoding security policies in the Google Cloud Console creates config drift. To maintain continuous governance, manage policies as code using the google_org_policy_policy resource (v2 API).
Here is a production snippet demonstrating how to enforce uniform bucket-level access org-wide, while testing external IP restrictions in dry-run mode:
# 1. Active Enforcement: Uniform Bucket-Level Access
resource "google_org_policy_policy" "enforce_ubla" {
name = "organizations/123456789012/policies/storage.uniformBucketLevelAccess"
parent = "organizations/123456789012"
spec {
rules {
enforce = "TRUE"
}
}
}
# 2. Safe Rollout: Disable VM External IPs via Dry-Run
resource "google_org_policy_policy" "dry_run_vm_external_ip" {
name = "organizations/123456789012/policies/compute.vmExternalIpAccess"
parent = "organizations/123456789012"
dry_run_spec {
rules {
deny_all = "TRUE"
}
}
}
7. Dynamic Policy Scoping with Resource Manager Tags
One of the historical headaches with Org Policy was the “sandbox exception.” Developers needed a project to test edge configurations, forcing platform engineers to create messy folder structures just to bypass a single rule.
With Conditional Policies based on Resource Manager Tags, you can define exceptions cleanly:
Condition: tagValue != "environments/sandbox"
Action: Enforce vmExternalIpAccess Deny
If a project has the tag environment: sandbox attached to it, the policy engine automatically evaluates the condition to false and skips enforcement. No special folders, no orphan projects, and no policy drift.
Summary Checklist for Platform Engineers
- Audit your current estate: Identify which of the “Foundational 5” constraints are missing across your root org node.
- Never enforce blind: Always start with dryRunSpec and monitor Cloud Audit Logs for at least 7 to 14 days.
- Use Tags for exceptions: Avoid creating detached, unmanaged folders just to grant exemptions. Use scoped Resource Manager tags with explicit expiration dates.
- Leverage Custom Constraints: Replace home-grown post-deployment validation scripts with native CEL constraints at the API level
- Stop chasing misconfigurations across your environment. Build the fence where the API lives, and make secure defaults the only path forward.
The Cloud Guardrails : Mastering GCP Organization Policy was originally published in Google Cloud – Community on Medium, where people are continuing the conversation by highlighting and responding to this story.
Source Credit: https://medium.com/google-cloud/the-cloud-guardrails-mastering-gcp-organization-policy-5df8b027fdd4?source=rss—-e52cf94d98af—4
