Skip to content
DevOps AI ToolKit
Newsletter
All guides
GCP with AI By James Joyner IV · · 9 min read

GCP Error Guide: 'Operation denied by org policy: constraints/compute.vmExternalIpAccess violates constraint'

Fix the GCP org policy violation blocking external IPs on Compute Engine VMs. Diagnose the vmExternalIpAccess constraint and resolve it the right way.

  • #gcp
  • #troubleshooting
  • #errors
  • #orgpolicy

Exact Error Message

Trying to create or modify a Compute Engine VM that requests an external IP, when an organization policy forbids it, returns a constraint violation:

ERROR: (gcloud.compute.instances.create) Could not fetch resource:
 - Constraint constraints/compute.vmExternalIpAccess violated for project acme-prod-417.
   Add instance projects/acme-prod-417/zones/us-central1-a/instances/web-ingress-3
   to the constraint to use external IP with it.

The same condition appears from the API and Terraform as a structured org-policy denial:

googleapi: Error 412: Operation denied by org policy:
["constraints/compute.vmExternalIpAccess": Externally accessible IP addresses are not allowed.
The instance "web-ingress-3" violates constraint "constraints/compute.vmExternalIpAccess"], conditionNotMet

What the Error Means

GCP Organization Policy lets administrators set guardrails — constraints — at the organization, folder, or project level. The compute.vmExternalIpAccess constraint is a list constraint that controls which VM instances are permitted to have an external (public) IP address. When the effective policy denies external IPs (an empty allowed list, or a denyAll), any VM creation or update that attaches an external IP is rejected before the resource is ever provisioned.

This is not an IAM error and not a quota error. Your account may have full compute.instances.create permission and you would still be blocked, because org policy evaluates independently of and ahead of the action’s IAM check. The constraint is inherited down the resource hierarchy: a policy set on the organization or a parent folder applies to your project unless an explicit override exists. The phrase “Add instance … to the constraint” hints at the resolution — the policy can list specific allowed instances, but for most teams the correct fix is to not request an external IP at all.

Common Causes

  • A security baseline (common with CIS benchmarks and “secure by default” landing zones) denies external IPs org-wide to force traffic through controlled egress.
  • The VM request includes an --address or default EXTERNAL access config when the policy expects internal-only instances.
  • The constraint is set on a parent folder or organization, so a project-level admin is surprised by a policy they did not author.
  • Terraform applies a config that worked in a sandbox project but hits a stricter inherited policy in production.
  • A previously permissive policy was tightened (to denyAll) and existing automation now fails.
  • The instance template or MIG references an external IP the policy no longer allows.

How to Reproduce the Error

  1. As an org admin, set constraints/compute.vmExternalIpAccess to denyAll on a folder.
  2. In a project under that folder, attempt to create a VM with an external IP: gcloud compute instances create web-ingress-3 --zone us-central1-a (the default network interface requests an ephemeral external IP).
  3. The create call fails with the vmExternalIpAccess violated error because the inherited policy forbids the external IP, even though you hold full Compute permissions.

Diagnostic Commands

Every command below only reads policy and resource state.

# Describe the effective org policy for this constraint on the project.
gcloud resource-manager org-policies describe \
  compute.vmExternalIpAccess --project acme-prod-417

# Walk up the hierarchy: check the parent folder and org too.
gcloud resource-manager org-policies describe \
  compute.vmExternalIpAccess --folder 456789012345

gcloud resource-manager org-policies describe \
  compute.vmExternalIpAccess --organization 112233445566

# Find the project's parent so you know where the policy is inherited from.
gcloud projects describe acme-prod-417 \
  --format="value(parent.type, parent.id)"

# Inspect the constraint definition itself (list vs boolean, etc.).
gcloud resource-manager org-policies describe \
  compute.vmExternalIpAccess --project acme-prod-417 --effective

# Confirm what the VM request is actually asking for.
gcloud compute instances describe web-ingress-3 \
  --zone us-central1-a --project acme-prod-417 \
  --format="yaml(networkInterfaces)"

Step-by-Step Resolution

There are two legitimate paths. Pick based on whether the VM should be public.

Path A — the VM does not need a public IP (preferred). Recreate it internal-only and reach it through a NAT, IAP, or load balancer:

gcloud compute instances create web-ingress-3 \
  --zone us-central1-a --no-address --project acme-prod-417

For outbound internet from internal-only VMs, configure Cloud NAT; for SSH, use Identity-Aware Proxy.

Path B — this specific VM genuinely must be public. Have an org policy administrator scope the constraint to allow the instance rather than disabling the guardrail wholesale:

gcloud resource-manager org-policies allow \
  compute.vmExternalIpAccess \
  "projects/acme-prod-417/zones/us-central1-a/instances/web-ingress-3" \
  --project acme-prod-417

This requires roles/orgpolicy.policyAdmin. Prefer narrowing the policy at the lowest level (project) rather than relaxing it at the org.

Path C — override an inherited policy only when justified, by setting a project-level policy that the security team has signed off on. Never blanket-allow all instances to make an error go away.

Prevention and Best Practices

  • Default to internal-only VMs and front public ingress with a load balancer; treat external IPs on instances as the exception.
  • Document where each org policy is set (org / folder / project) so engineers are not blindsided by inherited constraints.
  • Encode the --no-address choice and Cloud NAT into your Terraform modules so new instances comply by default.
  • When an exception is needed, scope vmExternalIpAccess to named instances at the project level — not allowAll on the org.
  • Run a policy dry-run or gcloud resource-manager org-policies describe --effective in CI before applying infra to catch violations pre-merge.
  • Route org-policy denials into your alerting so a blocked deploy is triaged quickly rather than silently retried — see our incident response tooling.
  • constraints/compute.requireShieldedVm violated — a boolean org-policy constraint requiring Shielded VM, same denial mechanism.
  • constraints/iam.disableServiceAccountKeyCreation violated — org policy blocking SA key creation; identical “violates constraint” shape.
  • Operation denied by org policy: constraints/gcp.resourceLocations — region-restriction policy blocking resource creation outside allowed locations.
  • Required 'compute.instances.create' permission — a true IAM denial, distinct from an org-policy block despite both stopping creation.

Frequently Asked Questions

Is this an IAM permission problem I can fix by granting a role? No. Org policy is evaluated separately from and ahead of IAM. Even an Owner is blocked by a deny constraint. The fix is changing the policy scope or not requesting the external IP.

Where is the policy actually set? It may be inherited from a parent folder or the organization. Use gcloud resource-manager org-policies describe at the project, folder, and org levels to locate the source, then read the project’s parent to trace inheritance.

Can I just disable the constraint to unblock myself? You can if you hold orgpolicy.policyAdmin, but you usually should not. Prefer making the VM internal-only, or scope an allow exception to the specific instance at the lowest level.

How do I run a public service if external IPs are banned? Put the workload behind an external HTTP(S) load balancer (which holds the public IP) or use Cloud NAT for egress and IAP for admin access. The VMs stay internal-only and policy-compliant.

Why did this start failing when nothing in my code changed? A parent-level org policy was likely tightened to denyAll. The inherited change applies to your project immediately even though your Terraform is unchanged.

The error says “Add instance … to the constraint” — should I? Only for genuine, reviewed exceptions, and only as a scoped allow at the project level. Adding instances ad hoc erodes the guardrail. More patterns are in our GCP guides.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.