GCP Firewall Rule Analyzer

Read GCP VPC firewall rules in evaluation order, with the tie-break that sends equal priorities to the deny, the rules that target every instance in the network, and the two implied rules underneath that nobody can delete.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Check the rules. Nothing leaves this tab.

Wanted a different tool?

  • GCP IAM Policy Analyzer for the other half of GCP access: the firewall says which packets arrive, IAM says what the caller may then do.
  • Azure NSG Rule Analyzer if you run both, because Azure stops at the first match and GCP resolves an equal priority in favour of the deny.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

An allow and a deny at one priority

GCP breaks the tie in favour of the deny, which is the opposite of a first-match model and the opposite of an ordering guess

[{"name":"allow-ssh","priority":1000,"direction":"INGRESS","allowed":[{"IPProtocol":"tcp","ports":["22"]}],"sourceRanges":["10.0.0.0/8"],"targetTags":["web"]},
 {"name":"deny-ssh","priority":1000,"direction":"INGRESS","denied":[{"IPProtocol":"tcp","ports":["22"]}],"sourceRanges":["10.0.0.0/8"],"targetTags":["web"]}]

A rule with no target

An empty target is every instance in the network, including ones created later by someone who never saw this rule

[{"name":"allow-internal","priority":1000,"direction":"INGRESS","allowed":[{"IPProtocol":"tcp","ports":["8080"]}],"sourceRanges":["10.0.0.0/8"]}]

A protocol with no ports

An empty ports list means every port, which reads as the opposite. From 0.0.0.0/0 that is the internet to everything.

[{"name":"allow-all","priority":900,"direction":"INGRESS","allowed":[{"IPProtocol":"tcp"}],"sourceRanges":["0.0.0.0/0"],"targetTags":["web"]}]

SSH through IAP, and SSH to the world

Both rules open port 22 and only one is a problem. 35.235.240.0/20 is Identity-Aware Proxy, not the internet, and a tool that flags it is a tool people stop reading.

[{"name":"allow-ssh-iap","priority":1000,"direction":"INGRESS","allowed":[{"IPProtocol":"tcp","ports":["22"]}],"sourceRanges":["35.235.240.0/20"],"targetTags":["bastion"],"logConfig":{"enable":true}},
 {"name":"allow-ssh-world","priority":1000,"direction":"INGRESS","allowed":[{"IPProtocol":"tcp","ports":["22"]}],"sourceRanges":["0.0.0.0/0"],"targetTags":["web"],"logConfig":{"enable":true}}]

An egress rule with a source

Egress filters on destinationRanges. A source here is either rejected or ignored, and if it is ignored the rule is far broader than it reads.

[{"name":"allow-out","priority":1000,"direction":"EGRESS","allowed":[{"IPProtocol":"tcp","ports":["443"]}],"sourceRanges":["10.0.0.0/8"],"targetTags":["web"]}]

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Assuming a lower-numbered rule always wins

    It does, until the numbers are equal. At the same priority GCP resolves in favour of the DENY, so a deny added alongside an existing allow silently takes precedence without either rule appearing to change.

    Instead:Give them different priorities so the intent lives in the configuration rather than in a tie-break the reader has to know.

  2. Leaving targetTags and targetServiceAccounts empty

    An empty target is not `no instances`, it is all of them, present and future. A port opened for one service is opened on everything in the VPC, including instances created later by someone who never saw the rule.

    Instead:Target the workload's service account. Use tags only where service accounts are impractical, and never both in one rule: GCP rejects that outright.

  3. Writing a rule with a protocol and no ports

    An empty ports list means EVERY port of that protocol, which is the opposite of how an empty list usually reads. With a source of 0.0.0.0/0 and no target it is the internet to every instance.

    Instead:Name the ports. `protocol: all` with no ports is the same mistake with more of it.

  4. Reading `no firewall rules` as an unconfigured network

    The two implied rules at 65535 allow all egress and deny all ingress, and neither can be deleted. So a VPC with nothing of its own has unrestricted outbound access, which is where data leaves.

    Instead:Add an egress deny for 0.0.0.0/0 at a high number and allow what is needed below it. Expect to allow 199.36.153.8/30 for Private Google Access.

  5. Flagging 35.235.240.0/20 as public exposure

    It is Identity-Aware Proxy TCP forwarding, and an SSH rule restricted to it is the recommended configuration: no public IP, and access decided by IAM. 130.211.0.0/22 and 35.191.0.0/16 are load balancer health checks and are equally not the internet.

    Instead:Learn the Google ranges before auditing a rule set, and prefer IAP over any public SSH rule you find.

On a tie, the deny wins

GCP's firewall looks like Azure's and behaves differently in two places, and both of them are where a rule carried over from another cloud goes quietly wrong.

Lowest priority number first, and equal priorities go to the deny

Azure forbids a priority tie. AWS has no denies at all. GCP allows the tie and resolves it in favour of the deny, so adding a deny at the same number as an existing allow silently takes precedence without either rule appearing to change. It is a reasonable default and it is not the one either neighbouring cloud teaches.

1000  allow-ssh  ALLOW  tcp:22
1000  deny-ssh   DENY   tcp:22   <- this one decides

 900  allow-ssh  ALLOW  tcp:22   <- and now this one does
1000  deny-ssh   DENY   tcp:22

A rule with no target applies to every instance in the network

An empty targetTags and targetServiceAccounts is not "no instances", it is all of them, including instances created later by someone who never saw the rule. So a port opened for one service is opened on everything in the VPC. This is the finding worth checking first on any rule set nobody has audited.

Two implied rules sit at 65535 and cannot be deleted

Allow all egress, deny all ingress. So a VPC with no firewall rules of its own is not an unconfigured network, it is one where everything can get out and nothing can get in. "We have no firewall rules" therefore means unrestricted egress, which is the path a compromised host uses to fetch a payload and to send data out.

65535  default-allow-egress   ALLOW  all -> 0.0.0.0/0
65535  default-deny-ingress   DENY   all

An empty ports list means every port

It reads as "no ports" and it is the opposite. A rule with protocol tcp and no ports is every TCP port, and combined with a source of 0.0.0.0/0 and no target it is the whole internet to every instance. Protocol all with no ports is the same thing with more of it.

Service accounts are a stronger boundary than tags

A network tag is a label anyone who can edit an instance can add, so the rule's real boundary is whoever has instance edit permission in the project. Changing an instance's service account requires stopping it, which makes it much harder to move accidentally. The two cannot be mixed in one rule at all: GCP rejects it, because an instance could match one and not the other and there is no defined answer for that.

35.235.240.0/20 is not the internet

It is Identity-Aware Proxy TCP forwarding, and an SSH rule restricted to it is the recommended shape rather than an exposure: the instance needs no public IP at all and access is an IAM decision. 130.211.0.0/22 and 35.191.0.0/16 are load balancer health checks and are equally not public. This page knows the difference, because a tool that flags the correct configuration is a tool people stop reading.

What this cannot see

It reads the rules you paste. It cannot see hierarchical firewall policies at the organisation or folder level, which are evaluated BEFORE anything here and can allow or deny regardless of what a VPC rule says. It cannot see which instances carry which tags or service accounts, so it cannot tell you what a rule actually reaches. It also does not know about VPC Service Controls, Private Service Connect, or a route sending the traffic somewhere else entirely. For what is in effect on one connection, Firewall Insights and the connectivity test in Network Intelligence Center answer that directly.