The third day-0 decision is about reachability, and it inverts the instinct most of us learned first. The instinct is to build the thing, confirm it works by hitting it directly, and then think about locking it down. Deny by default flips the order. Nothing is reachable until you have said, explicitly and narrowly, exactly what may reach it and from where. Everything else is refused, and the refusal is the ground state, not a filter you remember to add later.
The reason this belongs on day 0 and not day N is that reachability is sticky. Once something is exposed and a client depends on that exposure, closing it is a migration with a blast radius. Start closed and open one door at a time, and every open door is a decision someone made on purpose. Start open and close later, and you spend the rest of the project guessing which of the open doors anyone still needs.
Implied deny is not enough
GCP already helps here. A fresh VPC denies inbound traffic by an implied rule; nothing gets in unless a firewall rule allows it. That is a good default. It is also invisible, and invisible defaults have a way of being quietly undone.
So the network in this project does two things on top of the implied deny. First, it stands up a dedicated VPC for the workload rather than reusing anything shared, because a purpose-built network is one you can reason about completely. Second, and this is the part that looks redundant until it isn't, it adds an explicit deny-all inbound rule at the lowest priority. The implied deny already refuses everything. Writing it out anyway makes the closed posture audit-visible, something a reviewer can see in a plan rather than infer from an absence, and it survives the future: if someone later adds a careless allow rule above it, the explicit deny is still sitting underneath as the stated intent. Belt and suspenders is not paranoia when the cost is three lines and the payoff is that "this network refuses traffic" is written down instead of assumed.
One door, and it is not the internet
Against that closed background, exactly one inbound allow exists. It permits the load balancer's own data-plane and health-check ranges to reach the workload on its one port. Nothing else. Not the office IP, not a jump box, not the world. The only sources that can legitimately reach the machine are the managed edge in front of it.
This is enforced structurally, not just by the rule. The workload has no public address at all. There is no external IP on the VM, so even if a firewall rule were wrong, there is no route from the internet directly to it. Reachability is load-balancer-only by construction: the single allow names the edge's ranges, and the absence of a public IP means nothing else has a path to try. You are not trusting one rule to hold. You are removing the road.
The machine still needs to reach out, and this is where a real gotcha lives. A workload with no public IP cannot reach the internet by default. For Google's own APIs that is fine: Private Google Access routes those over Google's internal path without any public address, which is how the machine pulls its image and reads its secret. But this particular workload also has to call a non-Google endpoint to verify a challenge token, and Private Google Access does not route that. Without a fix, that call hangs to its timeout and fails closed, which quietly refuses every real user while the service looks healthy. The fix is a NAT gateway that gives exactly one outbound path while the machine still has no inbound public address. NAT is egress-only. It lets the workload start a conversation with the outside; it lets nothing outside start one with the workload. That asymmetry is the whole point, and it is scoped to just this subnet's ranges so the egress surface stays explicit.
The lesson generalizes past this app. Deny by default is not only about blocking inbound. It is about knowing every direction traffic can flow and having written down why each one is open. The inbound story here is "one door, the edge only, no public IP." The outbound story is "Google's internal path for Google, one NAT'd door for the single external call, nothing else." Both directions are enumerated. Neither is an accident.
The edge rejects the obvious before it lands
Deny by default handles who can connect. It does not handle what a legitimate-looking request carries. The one door that is open, public traffic through the load balancer, still needs something reading the requests that come through it, because "allowed to connect" is not "allowed to do anything."
That something is a managed web application firewall at the edge. Before a request reaches the backend, it runs against the standard preconfigured attack rule sets: SQL injection, cross-site scripting, remote code execution, file inclusion, protocol attacks, and scanner fingerprints. These are the high-volume, low-effort probes that hit every public endpoint constantly. Catching them at the edge means the obvious attacks are answered with a refusal before they ever touch application code, and the tools that automate them are turned away by their own signatures.
Two deliberate choices keep this honest rather than theatrical. The policy runs at the highest-confidence sensitivity, the setting that fires only on strong signatures, because a web application firewall that cries wolf gets switched off by the first engineer it inconveniences, and a disabled control protects nothing. Tuning stays surgical: when a real false positive shows up in the logs, the fix is to opt out of the one specific rule that misfired, not to lower the sensitivity of the whole set. On top of the attack rules sit per-IP rate limits, a general one and a tighter one for the connection-establishing path, so that a single source cannot exhaust the service by flooding it. The rate limit is not about clever attacks. It is about the boring one where someone just sends too much.
The shape of the decision
Put together, the posture reads in one sentence: the network refuses everything, one narrow inbound path is opened to the edge and only the edge, the workload has no public address so there is no other road, egress is a single enumerated door, and the edge inspects what comes through the one door that is open. Every one of those is a stated decision, visible in the configuration, made before the first user arrived.
None of it is exotic. That is the reassuring part. Deny by default is not an advanced technique; it is a default you choose to keep instead of a default you let erode. The work is not cleverness. It is the discipline to open doors one at a time, on purpose, and to write down why each one is open next to the door itself.
Previously in this series: Identity Before Infrastructure. Next: Encrypt by Default, and What Not to Log.
The same decision on AWS: The Network Says No First.