Cloud/ Google Cloud / Networking / GCP Firewall Rules: VPC Firewall vs Firewall Policies, Explained Properly

GCP Google Cloud Platform Guide 6 of 10 54 guides ยท updated 2026

Guides to BigQuery, Vertex AI, GKE, Dataflow, and the rest of Google's data- and AI-first cloud โ€” written for engineers shipping real workloads.

GCP Firewall Rules: VPC Firewall vs Firewall Policies, Explained Properly

โ€œJust add a firewall ruleโ€ sounds simple until youโ€™re staring at a project with forty rules across three different rule systems โ€” legacy VPC firewall rules, network firewall policies, and hierarchical firewall policies inherited from a folder or organization level โ€” trying to figure out why a specific packet is or isnโ€™t getting through. GCPโ€™s firewall model has genuinely grown more sophisticated over time, and understanding which system does what, and how they interact when more than one applies to the same traffic, is what separates confident troubleshooting from guessing.

This isnโ€™t a single feature to learn โ€” itโ€™s three related but distinct systems that compose together, and the composition rules are exactly the part that trips people up.


The Three Firewall Systems

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ System โ”‚ Scope and purpose โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ VPC Firewall Rules โ”‚ The original, per-VPC rule system โ€” โ”‚
โ”‚ (legacy) โ”‚ still widely used, simple to reason about โ”‚
โ”‚ Network Firewall Policy โ”‚ Newer, reusable rule sets attachable to โ”‚
โ”‚ โ”‚ one or more VPCs โ€” supports rule reuse โ”‚
โ”‚ โ”‚ across networks โ”‚
โ”‚ Hierarchical Firewall Policyโ”‚ Attached at organization or folder level โ€”โ”‚
โ”‚ โ”‚ enforces rules across every project โ”‚
โ”‚ โ”‚ beneath it, regardless of individual VPC โ”‚
โ”‚ โ”‚ configuration โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

VPC Firewall Rules are the original system โ€” still perfectly valid, widely used, and the right starting point for most single-team environments. Network Firewall Policies solve a real limitation of legacy rules: reusability across multiple VPCs without duplicating rule definitions. Hierarchical Firewall Policies solve an organizational problem entirely โ€” enforcing baseline security rules (block a known-bad range, require specific protocols) across every project in an organization or folder, regardless of what individual project owners configure at the VPC level, similar in spirit to IAM Deny policies but for network traffic instead of API permissions.


Evaluation Order When Multiple Systems Apply

This is the part that actually matters for correct troubleshooting โ€” when hierarchical policies, network firewall policies, and VPC firewall rules could all theoretically apply to the same traffic, GCP evaluates them in a defined order:

Yes

No match

Yes

No match

Yes

No match

Yes

No match

Packet arrives

1. Organization-level hierarchical firewall policy

Rule matches with

explicit allow/deny?

Decision made โ€” stop here

2. Folder-level hierarchical firewall policy

Rule matches?

3. VPC-level Network Firewall Policy

Rule matches?

4. VPC Firewall Rules - legacy

Rule matches?

Implied default:

deny ingress, allow egress

Hierarchical policies evaluate first, top-down from organization to folder, before VPC-level rules get a chance โ€” this is deliberate, since the whole point of a hierarchical policy is to enforce a guardrail that individual project or VPC configuration canโ€™t accidentally override. A hierarchical policy rule with goToNext: false (the default) stops evaluation entirely at that level; setting goToNext: true explicitly allows evaluation to continue down to lower levels for anything that rule doesnโ€™t match โ€” worth knowing because itโ€™s the mechanism for โ€œenforce this specific guardrail, but otherwise defer to whatever the project has configured.โ€


Creating a Hierarchical Firewall Policy

Terminal window
# Create a policy at the organization level
gcloud compute firewall-policies create \
--organization=123456789 \
--short-name=org-baseline-security \
--description="Organization-wide security baseline"
# Add a rule blocking a known-malicious range everywhere in the org
gcloud compute firewall-policies rules create 1000 \
--firewall-policy=org-baseline-security \
--organization=123456789 \
--action=deny \
--direction=INGRESS \
--src-ip-ranges="198.51.100.0/24" \
--layer4-configs=all
# Attach the policy to the organization node
gcloud compute firewall-policies associations create \
--firewall-policy=org-baseline-security \
--organization=123456789

Once attached, this rule applies to every VM in every VPC in every project under that organization โ€” no individual project owner can override it by adding a more permissive rule at the VPC level, because hierarchical policy evaluation happens first and, for a matching rule without goToNext, stops there.


Scoping Rules Precisely with Tags and Service Accounts

Whichever system youโ€™re using, precise targeting is what keeps a growing rule set manageable rather than becoming an unreadable mess:

Terminal window
# Target by network tag
gcloud compute firewall-rules create allow-web-traffic \
--network=my-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:80,tcp:443 \
--target-tags=web-server \
--source-ranges=0.0.0.0/0
# Target by service account โ€” often the more robust choice
gcloud compute firewall-rules create allow-db-access \
--network=my-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:5432 \
--target-service-accounts=db-workload@my-project.iam.gserviceaccount.com \
--source-service-accounts=api-workload@my-project.iam.gserviceaccount.com

Service-account-based targeting is generally more robust than tag-based targeting for security-sensitive rules โ€” tags are just metadata attached to an instance and anyone with edit permission on that instance can add or remove them, while a service account is tied to the actual workload identity and IAM-controlled. For genuinely sensitive traffic paths (database access, internal admin tools), scoping by service account rather than tag closes a gap where a tag could be added to an unintended instance, deliberately or by mistake, and inherit access it shouldnโ€™t have.


Firewall Rules Logging: Seeing What Actually Happened

A rule that silently blocks traffic nobody expected it to block is one of the most frustrating debugging scenarios in networking โ€” you know traffic isnโ€™t getting through, but not which rule, across three possible systems, is responsible. Firewall Rules Logging closes that gap by recording the actual decision for matched traffic:

Terminal window
gcloud compute firewall-rules update allow-web-traffic \
--enable-logging
{
"connection": {"srcIP": "203.0.113.50", "destIP": "10.0.1.5", "destPort": 443},
"disposition": "ALLOWED",
"rule_details": {
"priority": 1000,
"reference": "network:my-vpc/firewall:allow-web-traffic"
}
}

The log entry names the exact rule, in the exact system, that made the decision โ€” which turns โ€œwhy is this being blockedโ€ from a manual process of checking every rule across hierarchical, network, and VPC-level systems by hand into a direct lookup. Enabling logging on rules protecting genuinely important traffic paths, rather than only turning it on reactively during an active incident, means the answer is already sitting in Cloud Logging the moment you need it.


Implied Rules: The Ones You Never Explicitly Created

Every VPC has two implied rules that exist without any configuration on your part, and theyโ€™re worth knowing explicitly because they explain default behavior that otherwise looks unexplained:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Implied rule โ”‚ Direction โ”‚ Behavior โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Implied allow egress โ”‚ Egress โ”‚ All outbound traffic allowedโ”‚
โ”‚ โ”‚ โ”‚ unless explicitly denied โ”‚
โ”‚ Implied deny ingress โ”‚ Ingress โ”‚ All inbound traffic denied โ”‚
โ”‚ โ”‚ โ”‚ unless explicitly allowed โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

These sit at the lowest possible priority, meaning any explicit rule you create โ€” allow or deny โ€” takes precedence over them. This is why a brand-new VM with zero custom firewall rules can reach the internet outbound (implied allow egress) but canโ€™t be reached from anywhere inbound (implied deny ingress) until you explicitly create an allow rule โ€” a default posture thatโ€™s deliberately secure-by-default rather than open-by-default.


Real-World Use Case: Organization-Wide Security Guardrails

A company with dozens of GCP projects, each managed with real autonomy by different application teams, wants to guarantee certain security baselines regardless of what any individual team configures โ€” no SSH exposed directly to the internet, no traffic from a specific list of known-malicious ranges, mandatory Cloud Armor-fronted traffic for anything public-facing. A hierarchical firewall policy attached at the organization level enforces these guardrails uniformly, while individual teams retain full control over their own VPC-level rules for everything the hierarchical policy doesnโ€™t explicitly govern โ€” exactly the model of โ€œcentral guardrails, local autonomyโ€ that scales to a large, multi-team organization without either bottlenecking every team through a central network admin or losing baseline security control entirely.


Best Practices


Common Mistakes

Assuming a VPC-level allow rule guarantees traffic gets through. If a hierarchical policy denies it first, the VPC-level allow rule never gets evaluated at all โ€” this is consistently the most confusing debugging scenario for teams new to hierarchical policies.

Using tags for security-sensitive access control without understanding who can modify them. Anyone with instance-edit permission can add a tag, potentially granting that instance access a rule intended for a different, more trusted set of instances.

Not setting goToNext deliberately. Leaving it at the default (stop evaluation) when the actual intent was โ€œenforce this specific case, defer everything else to lower levelsโ€ produces unexpected blocking behavior for traffic that should have fallen through to VPC-level rules.


Frequently Asked Questions

Can I see which specific rule, across all three systems, actually decided a packetโ€™s fate? VPC Flow Logs combined with Firewall Rules Logging show which rule matched and made the allow/deny decision, which is the practical way to debug across a multi-system firewall setup rather than manually tracing evaluation order by hand.

Do hierarchical firewall policies cost extra? Theyโ€™re included as part of GCPโ€™s networking capabilities without a separate licensing fee, though โ€” as with most GCP services โ€” actual traffic processed still incurs standard network usage charges.

Can a folder-level policy override an organization-level one? No โ€” evaluation is strictly top-down (organization first, then folder, then VPC-level), and a matching organization-level rule without goToNext stops evaluation before a folder-level policy is even considered.

Is it possible to have conflicting rules that never get resolved? No โ€” evaluation always produces a deterministic outcome based on priority and evaluation order across the systems; what feels like โ€œconflicting rulesโ€ is really just the evaluation order producing a result that doesnโ€™t match what someone expected, not an actual unresolved conflict.

Do the implied allow-egress and deny-ingress rules show up when I list firewall rules? No โ€” theyโ€™re not visible in the standard rule listing since theyโ€™re not user-created objects, which is exactly why theyโ€™re worth knowing about explicitly rather than discovering their existence only when troubleshooting unexpected default connectivity behavior.


A Final Note on Change Management

Firewall changes, across any of the three systems, deserve the same review discipline as application code deployments โ€” a firewall rule modified directly in the console under time pressure, without a second pair of eyes, is exactly the kind of change that occasionally opens something that shouldnโ€™t be open, or closes something that breaks a dependency nobody remembered existed. Treating firewall configuration as version-controlled infrastructure (via Terraform or Deployment Manager, both of which support GCPโ€™s firewall resource types) rather than console point-and-click changes gives you both a review step before the change takes effect and a clean audit trail afterward, which matters considerably more for network security controls than it might for a routine, low-stakes configuration change elsewhere.


Summary

GCPโ€™s firewall model rewards understanding the evaluation order across hierarchical policies, network firewall policies, and legacy VPC firewall rules before you need to debug a confusing โ€œwhy isnโ€™t this traffic getting throughโ€ situation under time pressure. Hierarchical policies are the right tool for genuine organization-wide guardrails that shouldnโ€™t be overridable by individual teams; VPC-level rules (via either legacy or network firewall policy) remain the right tool for everything else. Getting the targeting precise โ€” service accounts for sensitive paths, tags for broader groupings โ€” and understanding which system evaluates first is what keeps a growing rule set debuggable instead of becoming exactly the kind of tangled configuration that takes an afternoon to untangle during an actual incident, rather than the five-minute lookup it should have been all along.