As mentioned earlier in this chapter, even though subnets that belong to the same VPC are connected, it is the firewall’s role to control communication between Compute Engine VM workloads. The same applies to networks connected via Interconnect/VPN or VPC peering. When routing information is exchanged, and connectivity is established, the next step is configuring firewall rules to allow a specific type of traffic to flow between Compute Engine instances.
By definition, a VPC is an isolated domain where almost every traffic type must be implicitly allowed. Firewall rules are applied at the VPC level. Because VPC is a global service, firewall rules are also global. With a single firewall rule, you can allow or block a specific communication that crosses regions or comes from an external network to instances in various zones.
Although firewall rules are defined at the VPC level, they are executed per VM instance. This is because firewalling in Google Cloud is distributed. As a result, there is no risk that a single firewall device could become a bottleneck when traffic increases. The following screenshot presents a section of the VPC network view while creating a new VPC network. The proposed initial firewall rules list is presented in the Firewall rules section:
Figure 9.20 – The pre-populated list of firewall rules when creating a VPC
Note that two firewall rules on this list cannot be removed. Both have the lowest priority of 65535. The implied deny-all-ingress rule blocks all incoming connections to every VM instance in this VPC. The implied allow-all-egress rule allows all VM instances in this VPC to send traffic to any destination. Firewall rules are stateful, so the matching response can also be received by the source VM when a connection is allowed.
The following screenshot depicts an example situation where only two implied firewall rules were configured for the my-vpc-network VPC. When vm-a sends a ping to vm-b, even though they belong to the same subnet, warsaw-subnet, in the same europe-central2 region, the firewall rules are evaluated for both individually. The ping message is allowed to egress a vm-a interface because of the allow-all-egress rule. And vm-a is allowed to receive a reply to the ping message because firewall rules are stateful in Google Cloud. On the other hand, vm-b is not allowed to receive any traffic because of the deny-all-ingress rule, so it will not receive the ping message. So, even though vm-a could receive a reply, it won’t be sent. But if vm-a pings a responsive resource outside the VPC, such as on the public internet (via Cloud NAT), it should be able to get a reply:
Figure 9.21 – The pre-populated list of firewall rules when creating a VPC
The following screenshot presents one of the possible solutions for the ping message to be received by vm-b. In addition to implied firewall rules, there is a new ingress rule with a higher priority of 65534 (the lower the number, the higher the priority) that takes precedence over the deny-all-ingress rule, and it allows all the instances in the VPC to receive ICMP messages when a sender IP address belongs to 10.0.1.0/24. This way, all VMs in the VPC will be able to receive ping messages from VMs in warsaw-subnet:
Figure 9.22 – A new firewall rule was added to allow vm-b to receive a ping message from vm-a
If instead of 10.0.1.0/24 (the whole warsaw-subnet IP address range), 0.0.0.0/0 was selected as a source, every source that can reach this VPC could ping all instances in my-vpc-network.
We can narrow down or broaden the possible sources that can access our workloads. However, a good practice is to follow the principle of least privilege and assign the minimum access required for an application to work. It is also recommended to keep the number of firewall rules to a minimum by combining similar flows and grouping VMs and port ranges.
Let’s look at the possible options to adjust firewall rules so that only the necessary traffic can pass through.