The dishonest way to end a security series is a victory lap: a list of everything I turned on, framed as if the job were done. It is never done, and a checklist that only lists wins is how teams convince themselves they are covered right up until the thing they never built fails. So this last part is a scorecard with two columns that both matter, and a third section that names the price, because "security-first" is a tradeoff and pretending it is free is its own kind of lie.
This is the end of building a GCP environment security-first. Seven parts of decisions made before the first real resource shipped. Here is where they landed.
What is genuinely day-0-solid
These are the things I would stand behind if someone audited the project tomorrow, because they were set as defaults before there was anything to protect, which is the only time they are cheap.
The root of trust is out of reach of the tool that could destroy it. The Terraform state, the thing that describes and controls everything else, is encrypted with a customer-managed key and lives entirely outside the automation, bootstrapped by a plain script rather than the IaC itself. The automation cannot delete the key or the bucket encrypting its own state. That is the one decision that, if you get it wrong, quietly undermines every decision after it, and it was made first, on purpose.
Every workload is its own minimal identity. Nothing runs as a default service account. Each component gets exactly the few grants it needs, write its own logs, read its one secret, pull its one image, and nothing project-wide. Least privilege from resource one, not retrofitted after an audit found the over-grant.
No long-lived keys anywhere. The keyless CI path is written using federated, short-lived identity tied to one exact source repository, and then deliberately left disabled, so there is not even an idle powerful service account sitting around. The most dangerous credential in the system is the one that does not exist.
The network says no first. A dedicated network, an explicit belt-and-suspenders deny-all on top of the implied deny, a single inbound allow scoped to the load balancer's ranges, egress-only with no public address, and a managed web application firewall running the standard attack rule sets at the edge. Deny by default, made audit-visible.
The one necessary broad grant is made safe and documented. Public traffic genuinely required relaxing an org restriction, so the direct path to the service was made unreachable and the reasoning was written next to the grant. A compensating control you can read is worth more than a restriction you cannot keep.
Encryption is a default and the logs are redacted on purpose. At-rest encryption everywhere without it being a feature request, and a deliberate decision about what the logs must never capture, because the more you log the more you can leak.
The audit trail is on, and now it is queryable. This is the part most teams skip until after an incident, and it is the part I built live in part five and part six. The full trail, including the Data Access logs that are off by default, is recording, routed to a durable store, and answerable: who touched access controls last week, every read of the one secret. It ships at budding, not evergreen, because it is fresh and will earn its retention and its alerts over time. But it exists, before the bad day, which was the whole point.
There is a floor of alerting. An external uptime check and an alert policy that pages a human when the service is down from multiple locations. Not analytics, the honest "wake me if it's down" tier, but the phone rings.
What is still a gap
This is the column that makes the scorecard honest, and I want it read as carefully as the first.
No org-wide guardrails. This is a single-project setup. The guardrails I have are hand-placed at the project level plus one org restriction I inherit. What I do not have is a folder hierarchy with policy applied by structure, so that every future project inherits a consistent baseline for free. Hand-placed rails are exactly the ones a hasty change can pull, and the fix is a real org-policy posture, not more per-project vigilance. Today, vigilance is doing the job a structure should do.
No threat detection. Nothing is watching for the patterns a human would miss: anomalous access, known-bad indicators, the slow reconnaissance that does not trip a single obvious rule. GCP has a managed layer for exactly this, and I have not turned it on, partly cost, partly scope. The audit trail from parts five and six means I can investigate after I have a reason to look. It does not mean anything is looking for me. That is a real difference and I will not paper over it.
No config-drift detection. If someone changes live state out from under the Terraform code, through the Console, in a hurry, during an incident, nothing tells me the world has diverged from the description of the world. I would find out at the next plan, which could be days later. Continuous drift detection is a known gap, deliberately deferred, not solved.
The audit alerting is designed, not fully shipped. I can query "who read the secret." The version that pages me when the answer changes depends on the durable store being in place, which it now is, so this is the next unit of work rather than a mystery. But designed is not done, and the scorecard says designed.
The pattern across all four gaps is the same: I have the reactive capabilities, the record, the ability to ask, the floor that pages on an outage. The proactive and structural capabilities, inherited guardrails, active threat detection, drift alarms, are the frontier. That is a defensible place to be for a single-project build, and it is not the same as being done.
What security-first actually cost
The premise of the series is that security is a day-0 property and not a day-N project, and the fair question is what that property costs, in the two currencies that matter.
Time. The honest number is that the security groundwork added something on the order of weeks, not days, to standing up an environment that could otherwise have been running in an afternoon. A lot of that was not typing, it was deciding: what is sensitive enough to audit, where a broad grant is genuinely required and how to compensate for it, which log types to enable and which to leave off. The pi-storm deploy alone cost a week of purely-GCP friction, credentials, org policy, the load balancer, before a single security decision. The cost of day-0 security is mostly the cost of thinking clearly before you are allowed to be in a hurry, and that thinking does not compress.
Money. Smaller than the time, and concentrated in a few honest line items. The audit trail is the main one: Data Access logs are billed by volume, which is exactly why the scoping discipline from part five matters, because logging secret reads and sensitive-bucket reads rather than all reads is the difference between a sane bill and a runaway one. Retention in a durable store is the second. The uptime checks and alerting sit largely in free-tier territory. And there is the standing cost the serverless-first thesis already conceded, a pinned always-on instance, which is an availability cost more than a security one but shows up on the same statement.
The thing that was not expensive is the thing people assume is: the defaults. Encryption at rest, minimal identities, deny-by-default networking, turning the audit trail on. Set before the first resource exists, these cost almost nothing, because there is nothing yet to migrate, no volume yet to pay for, no running system to carefully not break. That is the entire argument of the series in one line. The groundwork is cheap on day 0 and expensive on day N, and the only variable you control is which day you do it.
I did it on day 0. The scorecard above is what that bought, and what it did not.
Previous: know when it breaks, and guardrails that survive a mistake. This is the last part of the GCP series.
The same reckoning on the other cloud: the honest AWS scorecard.