Library · Summary & review

Building Secure and Reliable Systems

By Heather Adkins and five Google colleagues, 1st edition. Design, test and ship so that human errors and attacks do not bring production down.

FR EN
Building Secure and Reliable Systems book cover, Adkins et al.

Building Secure and Reliable Systems

Building Secure and Reliable Systems: Best Practices for Designing, Implementing, and Maintaining Systems

6.4 /10

« Written for Google, dated 2020, silent on coding agents, yet one of the clearest deployment lessons you can read for free. »

  • AuthorHeather Adkins, Betsy Beyer, Paul Blankinship, Piotr Lewandowski, Ana Oprea, Adam Stubblefield
  • OriginalO'Reilly (Google), 2020 · 1st edition
  • LanguageEnglish only
  • Read for free sre.google Published by O'Reilly, free to read on Google's site.
  • This page~27 min read
Book rating across 5 dimensionsIdeas8/10Practical5/10Readability6/10Aged well6/10Examples7/10

Design, test and ship so that human errors and attacks do not bring production down.

Why this book

A web developer ships code, then asks two uncomfortable questions. Who can touch production, and with which rights? And how do you know that what runs is what was written? This book starts from one thesis: security and reliability are not bolted on afterward, they must be designed from the start.

The authors are six Google engineers, on the security side and on the SRE side (Site Reliability Engineering: the teams who run production and keep it standing). The book treats honest failures and attacks as one subject. A human error and an attacker bring production down in the same way, and the same design prevents both.

Three families: design (ideas 1 to 4), build and ship (5 to 8), hold and recover (9 and 10). Idea 7, on deployment and provenance, is the core.

Three warnings. The scale is Google's: thousands of engineers, in-house tools. The code is mostly C++ and Java. Finally, the book dates from 2020 and says nothing about coding agents (AI tools that write and modify code, sometimes alone). Any link to them is therefore mine, in the "My reading" boxes (my opinion, outside the book). The "(ch. N)" references point to chapter N of the book.

I opened it to fill, in the site's Great Book, the chapters on quality and web security. I leave aside attacker profiles and multi-team crisis management.

The ideas that stick

1A security failure is a failure: neither gets bolted on afterward

People often file security and reliability under things to add later. The book answers that both "are emergent properties of a system’s design" (ch. 1). An emergent property belongs to no single part. It arises from the assembly, so you do not fix it by changing one part.

The book opens with proof. On September 27, 2012, Google's internal password manager went down. An email gave thousands of employees the new password of the bus WiFi, stored in that manager. Everyone came to read it: traffic exploded, beyond what a tool built for a few administrators could bear. The service had no load shedding (dropping part of the requests to save the rest). This outage is a reliability problem. But the recovery got bogged down because of security. Restarting required an HSM (a hardware box that keeps keys). That card was in a safe, and the safe's combination was in the failed manager. It took a drill for the safe, then one more hour: the drive's green light lied, and the card was upside down (ch. 1).

Why treat both together, when they differ? Reliability aims at failures without intent. Security faces an active adversary, who looks for the flaw. And their remedies sometimes contradict each other. Redundancy helps reliability but widens the attack surface. During a security incident, you shrink the circle of responders so as not to alert the attacker. During a reliability incident, you widen it to get more viewpoints. Logs help recovery but become a target (ch. 1).

A harmless-looking change is enough to break everything. An open source developer removed two lines from OpenSSL (in the Debian version) to silence a debugging tool. Result: the seed of the random generator, its starting point, shrank to a process ID between 1 and 32,768. Brute force then recovered the keys. Closer to home, YouTube was unavailable for more than an hour in October 2018. The cause: a small change in a logging library, which had passed review and tests. Under load, the servers ran out of memory, and cascading failures stopped everything (ch. 1).

Both qualities are invisible while all goes well, so we believe they can wait. The book totals the bill from press reports. Yahoo's breach would have cut Verizon's purchase price by $350 million. Delta's power outage cancelled nearly 700 flights (ch. 1). The trap, it says, is to sacrifice them "in the name of velocity" (ch. 1).

My reading

Outside the book, coding agents. A coding agent is velocity squared. A routine change passes review and tests (YouTube), so the guardrails must be structural (rights, checks, deployment), not a promise of good will.

2Least privilege is designed in: you limit access because people make mistakes

Handing the production key to a trusted colleague seems reasonable. The book rejects this shortcut: "Engineers may make mistakes, their accounts may be compromised, or they may be malicious." (ch. 5). A privilege is a right to act (read, write, restart). Least privilege grants only those the task needs. A command pasted in the wrong place is as dangerous as an attacker.

First, classify access by risk. The book proposes three data levels: public, sensitive, very sensitive. For the last one, no permanent access. It crosses them with three actions: read, write, touch the infrastructure. An API that deletes data is not treated like one that reads it.

Next, prefer small functional APIs, where one entry point does one thing. An interactive shell, by contrast, exposes the whole system: you can run anything in it. Auditing a session is not enough. An audit records after the fact, prevents nothing, and can be bypassed. The book's verdict: "they only keep the honest people honest" (ch. 5). Its example: from the vim editor, :!/bin/evilcmd runs a command without going through the shell history, so it leaves no trace.

Take a concrete case: pushing a web configuration. The wide route is OpenSSH, that is, a full shell on the server. The narrow route is OpenSSH's ForceCommand option, which limits the connection to one act: drop the file, whose fingerprint gets logged. An HTTP or gRPC receiver does the same thing.

When you must bypass the rule, the book provides for breakglass (break the glass, as on a fire alarm). It is an authorization bypass reserved for the service's SRE team, monitored and tested regularly (ch. 5). In a zero trust network, where location is distrusted, it can only be used from specific places. Breakglass used often signals a missing normal API, hence a weekly peer audit. But, in the book's words, "Without cultural reinforcement, audits can become rubber stamps, and breakglass use can become an everyday occurrence" (ch. 5).

Around breakglass, three tools. A structured justification: a ticket number that the system checks, not free text. Temporary access, which expires. An MPA (multi-party authorization: a second person must approve). The condition: make sure "the technology and social dynamics allow someone to say no" (ch. 5).

One last point, often forgotten: test the refusals. You describe what each role can do, write scenarios with the expected result, and replay them before any change in rights. Otherwise, "they’ll test in production, circumventing the controls you put in place" (ch. 5). To a client without rights, you answer with a blind 403 (forbidden, with no detail), because a detailed refusal helps guess the policy.

My reading

Outside the book, reduced version. At the scale of one developer or a small team, the essentials fit in a justification ticket. Add an access that expires and a logged breakglass. For a coding agent, apply the same rule. It never receives the developer's credentials, only its own, with the rights of its task and nothing in production.

3The safe proxy: a single passage for operator access, which logs and filters

How do you impose these rules on an existing system without rewriting it? The book answers with a case study: the safe proxy. A proxy is an intermediary. The client talks to it, never to the target.

The mechanism holds in four steps. The proxy receives a request (an RPC: a function call across the network). It logs it. It compares it to an access policy, made of ACLs (access control lists: which role may launch which action). Only then does it execute (ch. 3).

Google calls it the Tool Proxy. It is a binary that exposes a generic RPC. It runs the requested command line, and each run is checked against the policy and logged, with an MPA if needed. Example from the book: a member of group:admin may run the borg tool after approval from group:admin-leads. The policy carries its own unit tests, with an expected result of ALLOW (ch. 3). The target server refuses any direct connection, except by breakglass.

The book lists five benefits. A centralized MPA. An audit of administrative acts. Rate limiting: one restart at a time instead of all at once, so an error touches fewer machines. Compatibility with closed third-party systems. Security improvements added in a single place (ch. 3). The proxy reuses the same APIs as the target, so the engineers' experience does not change.

It serves a Google goal, Zero Touch Prod: every production change is automated, validated in advance, or triggered by an audited breakglass. The book estimates that "13% of all Google-evaluated outages could have been prevented or mitigated" by such discipline (ch. 3). It is the book's estimate, not a measurement.

The drawbacks are admitted. The proxy costs something to maintain. It becomes a single point of failure (if it goes down, nobody acts), hence several instances. Its policy is a source of errors, hence safe default policy templates. And a central machine attracts attackers, hence a clear rule: the proxy holds no elevated privileges. It passes on the requester's identity and acts in their name, because "no request is executed under a proxy role" (ch. 3). Whoever compromises the proxy therefore inherits no powerful role of its own. The book presents it as the economical option for an existing system, and stronger when combined with the principles of idea 2.

My reading

Outside the book, coding agents. The pattern transfers as is. A coding agent that runs commands on a server should talk to a small receiver (HTTP or gRPC). That receiver logs, and accepts only a list of actions. The agent has no shell.

4Say what is always true: invariants, and a small trusted base

We think we understand our system because we wrote it. The book asks for more demanding proof. It defines an invariant as "a property that is always true, no matter how the system’s environment behaves or misbehaves" (ch. 6). For example, every external value is validated or encoded before it reaches an API sensitive to injection. On the reliability side: an overloaded component returns an overload error rather than crashing. Retries (automatic re-attempts) without a pause still overload the component until it crashes: they break the second example (idea 9).

Why invariants, not tests? A property that must hold for every behavior cannot be tested: tests cover a small share of the cases. The book puts it plainly: "Absence of evidence is not evidence of absence." (ch. 6). At the other extreme, the formal proof of a microkernel cost about 20 person-years, unrealistic for an application. The chapter aims for the middle: informal but disciplined arguments.

A mental model (the simplified picture we hold of the system) helps, but it breaks under attack or overload. The book's concrete remedy: production servers without swap (backup memory on disk). A service short of memory then returns a predictable error quickly, instead of crawling indefinitely (ch. 6).

The named enemy is complexity: "The primary enemy of understandability is unmanaged complexity." (ch. 6). Two remedies. Smaller components. And a framework (a shared code base) that centralizes authentication, authorization, logging and timeouts, so a reviewer reads the framework and the configuration, not every method.

Then there is the TCB (trusted computing base: the set of components whose failure breaks the security policy). The smaller it is, the easier to audit. The book's example is a widget sales site. As a monolith with a single database, everything is in the TCB: a SQL injection (idea 5) in the catalog search exposes customers' addresses. Split into microservices (small separate services, each with its own database), the TCB shrinks to the purchase service. An end-user context token is a short ticket, issued by a central authentication service: it proves the request comes from that user. The purchase service requires it, so a compromised frontend reads only the data of the user whose ticket it holds (ch. 6).

And a separate web origin for payment (a distinct subdomain, since the browser isolates pages by origin) contains an XSS flaw from the catalog (ch. 6).

My reading

Outside the book. Write three invariants per project, as tests that fail when they are violated. For an agent, they serve as a verifiable specification: it may change anything, except what breaks an invariant.

5Make the bug unwritable: types and frameworks rather than reviews

Humans do not maintain a global invariant across thousands of files. The book accepts it: "even the best-trained engineers make mistakes" (ch. 12). Manual review is not enough either. Reviewers gravitate toward the interesting attacks, and they neglect the hundreds of HTML templates to check one by one against XSS (script injection into a page, seen by the visitor).

The answer is to write libraries and frameworks that make the class of bug impossible to write. A fix made in one place benefits every application. First example: a remote call server framework with interceptors. These are functions run before and after each request, to log, authenticate, authorize and rate-limit. If the request is refused, the business logic does not run, but the refusal is logged (ch. 12).

Second example, more striking: safe types. A SQL injection happens when a query is built by pasting text from the user. The book defines a TrustedSqlString type: it can only be built from literals (text written as-is in the source code). In Go, it is obtained through a stringLiteral type alias private to the package. Calling code cannot create one, but literals convert to it automatically. Query functions accept only this type. Text coming from outside is not a literal, and neither is its concatenation with a query. It does not have the right type, so the compiler rejects the program (ch. 12). The same principle applies to XSS, with SafeHtml and SafeUrl types and context-aware escaping templates.

An escape hatch exists: an unsafequery package, reviewed by a part-time security engineer on a rotating basis, for hundreds to thousands of developers (ch. 12). The review concentrates on the rare places that leave the rails.

The chapter's strongest figure concerns applications built on an internal framework designed with these types. They had "far fewer reported XSS vulnerabilities (by two orders of magnitude)" than applications written without safe types, even though those were reviewed carefully (ch. 12). Two orders of magnitude means about a hundred times fewer.

The admission: it is harder to graft onto existing code. The book describes a gradual rollout. Add an overload that accepts the safe type. Restrict the old call with an annotation. Git hooks block new uses. Then clean up the rest. Another lesson: compile errors give immediate feedback. Developers adopt a safe API when the cycle is fast and the fix is simple.

Shorter levers: simple code, strong types, Go's data race detector. And a memory-managed language, which frees memory for you: a memory error lets you read or overwrite what is not yours. Around 70% of Microsoft's vulnerabilities and 85% of Android bugs come from this (ch. 12).

My reading

Outside the book, coding agents. A compiler and a type that is only built in one place is a reviewer who never tires. Facing generated code, it is the cheapest defense: the agent can write anything, and the compiler refuses what is not of the safe type. Go's html/template and Twig's automatic escaping go the same way.

6Test by family: sanitizers at night, continuous fuzzing, static analysis in review

A unit test checks what we thought to check. The book adds three families for what we did not think of: sanitizers, fuzzing and static analysis. They have different costs, so they sit at different steps of the CI (continuous integration: the chain that builds and tests on every change).

A sanitizer is a compiler that inserts checks into the program. AddressSanitizer surrounds each allocation with poisoned zones and marks freed memory as poisoned. An overflow or a reuse of freed memory then triggers an error. Others detect undefined behavior, race conditions or leaks. The cost: "the compiler-instrumented binaries can be orders of magnitude slower than the native binaries" (ch. 13). The book's answer: run them at night, not on every commit.

Fuzzing sends a program random or mutated inputs to make it crash. An engine generates the inputs, and a driver feeds them to the target: a format parser, a decoder, a protocol. A keyword dictionary and a corpus (valid seed examples) keep the fuzzer from getting stuck on rejected inputs. A parser discards pure noise at once, while a valid example goes further. The faulty input then becomes a regression test. The stated limit: "it’s not feasible to block every commit on the results of an extended test" (ch. 13). So a bug can already be merged when fuzzing finds it. Fuzzing complements the other tests, it does not replace them.

OSS-Fuzz, Google's continuous fuzzing service for open source projects, found more than a thousand bugs in five months (launched December 2016). Tricorder, Google's static analysis tool, examines about 50,000 changes a day with 146 analyzers. A false positive is an alert raised in error. Tricorder measures perceived false positives through a "Not useful" link that the reviewer clicks during review, and caps that rate at 10% (ch. 13). A low cap matters: without it, people stop reading the alerts.

Static analysis reads code without running it. It is limited by principle: "statically verifying any program is an undecidable problem" (ch. 13). Undecidable means no tool settles every case. Hence a trade-off between false alarms and missed flaws, which shifts depending on the step.

Two discipline traps. Flaky tests pass or fail for no reason. "Try to fix flaky tests as they arise; otherwise, developers may get in the habit of ignoring test results when checking in changes." (ch. 13). And the hollow test: in new code, temporarily replace a condition with if (false). If no test fails, no test was protecting that condition. Last detail: do not copy a real database into tests (excessive rights, idea 2).

My reading

Outside the book, Go, PHP and agents. The book is centered on C and C++. Go serves only as an example (interceptors, data race detector), and its only fuzzer cited is the third-party tool go-fuzz (ch. 13). Since Go 1.18, go test -fuzz does native fuzzing, and go test -race detects, at run time, concurrent accesses to the same variable. In PHP, PHPStan finds bugs without writing tests. Psalm is a static analysis tool and tracks user data (taint analysis). For code written by an agent, run the if (false) test first: an agent can produce tests that pass without protecting anything.

7Deploy without trusting the developer's machine: mandatory review, locked build, provenance

The chapter's question is this: "Is the code running in your production environment the code you assume it is?" (ch. 14). The book treats three adversaries on equal footing: the insider who makes a mistake, the malicious insider, and the attacker who took over an account. The chain runs from repository to build, tests and deployment. The book lists eleven threats along it, including a build run from a modified local copy.

The core rests on five practices. A build is the production of an artifact (a binary, an image) from code. First, mandatory review, a form of MPA: "An adversary will not be deterred if they can simply opt out of the review!" (ch. 14). Second, an automated build on a locked system (restricted access, frozen configuration). Third rule: "deployment environments should verify what is being deployed" (ch. 14), meaning artifacts, not people. Fourth, configuration is treated as code, and reviewed as such. Fifth, secrets stay out of the repository. The admitted limit: review does not cover collusion or several compromised accounts.

The advanced level rests on provenance, an artifact's identity card: the build's inputs, the command run, and the hash of the result (its fingerprint, which changes if a single byte changes). The whole is signed by the build system (ch. 14). Deployment then applies three checks. One: the signature is valid, so the provenance is authentic and nobody forged it. Two: the hash of the received artifact matches the card's, so the card applies to that artifact and not to a tampered one. Three: it complies with the rules, for example, built from a given repository. A hermetic build has its inputs fixed in advance. A reproducible build yields the same hash again.

Three architectures are compared. A trusted build service, used internally by Google. Rebuilding it yourself at deployment is not recommended: "Builds often take minutes or hours, whereas deployment decisions often need to be made in milliseconds" (ch. 14). Or rebuilders with a quorum (several machines redo the build and must agree), as at Debian. Privileges are separated: an orchestrator (the trusted process that launches the build) signs the provenance. The user's commands run without the key, otherwise they could sign anything. The control sits at a choke point, where all requests pass. Example: Kubernetes' Admission Controller (the system that runs containers), the gatekeeper that accepts or refuses each deployment.

Google sent provenance asynchronously into a database, looked up at deployment by the artifact's hash. But an artifact could be built several times, hence several records per hash. Many builds produced an empty file, and millions of records piled up under its hash. To check it, you had to scan them all. If none matched, the error shown was: "None of these 497,129 records met the policy." (ch. 14). Verification exceeded the 100 ms SLO (the time target set for this service) by several orders of magnitude. Lesson: propagate the provenance with the artifact. A first policy language, very flexible, made actionable error messages impossible, and was replaced by a much more limited one (ch. 14).

The breakglass exists here too. The book's rule: "In order to make auditing practical, breakglass events should be rare" (ch. 14). Each use raises an alarm.

The minimal version is the point to remember for a small project. The book does not address the lone developer, since review requires a second person. It admits that the advanced level may make no sense for small organizations little exposed to insiders. The floor: "At a minimum, you should script all steps" (ch. 14), through a CI. The next level: add signing, which may suffice for a small organization with a central build service (ch. 14). The book also advises requiring review approvals on GitHub, GitLab or BitBucket. Method: one link at a time, since a mistake in these controls can cause an outage. And: "Only you can decide whether these threats are worth addressing for your particular organization." (ch. 14).

My reading

Outside the book, coding agents. The chain is worth most when someone very fast produces changes. An agent may open a merge request, never validate it alone, and another person than its author must approve. It does not hold the signing key, which lives in the CI.

8Changing fast is a defense: fixes, frequent rebuilds, and the embargo that breaks

We fear deploying often because each change can break. The book argues the opposite: "you need to be able to change your infrastructure frequently and quickly, while also maintaining a highly reliable service" (ch. 7). When a critical flaw drops, the speed of the fix is a security property. Every change must be incremental, documented and tested. It is isolated behind a feature flag (a switch that enables the new code). Then it is validated and deployed in stages, starting with a canary (a small share of traffic).

The architecture that eases change has three traits. Dependencies stay up to date, so a critical fix can be applied without catching up on a backlog of updates at once. Rebuilding and redeploying often has a payoff. The book says: "Frequently rebuilding and redeploying your environment means that you’ll be ready to roll out a new version when you need to" (ch. 7). And containers are immutable: you fix the image in the registry, never the running container, and only recent images are allowed in production. A common frontend (the shared entry point) protected every service behind it: a single rule there limited SSL renegotiations during a flaw (ch. 7).

The speed depends on four factors: severity, dependencies (another team or a vendor must act first), the sensitivity of the period, and the deadline. No non-urgent change during a critical period. Rushing everything backfires: "Accelerated timelines are disruptive and more likely to break systems." (ch. 7).

A zero-day (a flaw unknown to the public, with no fix) is not necessarily the main threat. The book notes that "they’re not necessarily the vulnerabilities that are most exploited by attackers" (ch. 7). Fix the big classics of past years first. Even in an emergency, deployment stays gradual, in hours or days. If no fix exists, restrict access to the component.

Two stories illustrate it. Shellshock, September 24, 2014: low-risk servers were fixed automatically, and a non-standard minority by hand. Lesson: standardize distribution so that patching is the easy path. Heartbleed: the bug entered OpenSSL in December 2011, became public in April 2014, and exposed 64 KB of private memory. The embargo (the agreed silence period before public announcement) was broken. The security firm that had found the flaw launched a website and a logo, and the media followed. Lessons: plan for a broken embargo, keep a channel open to users, and "Regularly rotate your encryption keys and other secrets." (ch. 7).

Slow change has its place: by user groups, with a mode that warns before enforcing the rule. FIDO keys were studied in 2011, deployed in 2013, and OTP was blocked in 2015. Accept partial adoption: "achieving 80% or 90% adoption can have a measurable impact on reducing security risk" (ch. 7).

My reading

Outside the book, coding agents. If an agent ships ten times a day, the frequency is already there. The question becomes: can you roll back in one command, and are the dependencies it adds up to date?

9Degrade instead of falling: fail static and retries with jitter

Facing a denial of service (DoS: saturating a service to make it unusable), the first instinct is to overprovision. The book recalls: "A well-resourced defender can absorb attacks simply by overprovisioning their entire stack, but only at great cost." (ch. 10). The attacker targets the most constrained resource (bandwidth, application processor, database). The deeper the traffic goes into the system, the more precise and costly it is to filter, hence layered defenses.

First answer: graceful degradation, which serves a reduced service rather than nothing. At Google, under overload, Blogger switches to read-only without comments. Search cuts back its features. Automatic responses (limit the noisiest IP addresses, impose a JavaScript challenge or a CAPTCHA) buy time for humans. Do not block suspicious traffic forever: you would lose visibility on the attack, and block legitimate traffic that resembles it. Alert humans only when a human action is required, that is, when demand exceeds capacity despite the automatic defenses (ch. 10).

Second answer: what does the defense system do when its own controller, the component that decides the filtering rules, fails? Three choices. Fail closed: cut everything, which is an outage. Fail open: let everything through, which hands the service to the attack. The book's third way: "Instead, we fail static, meaning the policy does not change." (ch. 10). The controller may die, and the rules already in place keep filtering. The chapter notes that a controller failing mid-attack has already happened at Google.

Third lesson, strategic. A filter on the User-Agent header "I AM BOTNET" would have blocked the attack. But "we’d be teaching our adversary to use a more plausible User-Agent, like Chrome" (ch. 10). The book therefore put CAPTCHAs in front of the addresses concerned.

The most frequent attacks are self-inflicted. In 2009, a German TV game show looked like a botnet on Google Search: viewers played at home, all on the same word beginnings. Google responded with autocomplete. Above all, there were client retries. A client that retries without a pause makes an outage worse. The remedy: exponential backoff (the wait doubles after each failure) plus a jitter, because "each client should wait for a random duration, called jitter" (ch. 10). Jitter keeps all clients from coming back at the same time. For a failing authoritative DNS server, resolver retries multiply the load about 30 times. The fix is to answer as many requests as possible: a served client stops retrying.

My reading

Outside the book, coding agents. An agent that calls an API in a loop is a client that retries. Give it a retry cap, a backoff with jitter and a global budget. Without that, the outage it tries to get around becomes its own.

10After the incident: recover in order, then write actions with an owner

After a compromise, the urge is to fix everything fast. The book, which I only skimmed on this point, says to prepare the recovery before acting, as soon as you have the attack's baseline state. The scope comes from the investigation: the list of affected systems, networks and data. A compromised configuration distribution system affects everyone who received from it. Careful: the recovery effort is not proportional to the severity of the attack.

The recovery traps come as questions. Are the recovery tools and infrastructure themselves compromised? The book suggests setting up a clean quarantined network, and rebuilding the configuration server before the laptops it configures. Are there variants of the attack? A buffer overflow on one server raises the question of the 20 other identical servers. Does recovery reintroduce the flaw, through golden images (reference system images) or backups already containing the attacker's changes? And above all: "there’s a human on the other side of the attack who is reacting to your incident response" (ch. 18).

The book's scenario: the attacker stole the SSL keys and slipped a backdoor into the code that takes $0.02 per transaction (ch. 18). Applying the traps above to it (my reading): check that the recovery tools are sound. Look for the same backdoor on other servers. The golden image or the backup must not contain it. Coordination channels may even be read by the attacker.

When should you evict the attacker? The common rule is to wait for full understanding. But if they are already stealing or destroying data, you can act earlier. The book speaks of a chess game. Quick mitigations create technical debt, for example a router rule added by hand, bypassing review. It must then be redone properly.

To split the work under an incident commander (the person who coordinates), the book proposes a recovery checklist. Each line holds a task, the required skill, the precise tools and commands, and the cleanup and rollback steps. Account rotation follows a priority: administrators first, then known-compromised accounts, then sensitive access. Added to that: SSL keys and API keys stored in code. And it is the chance to deploy two-factor authentication, which moves fast during a recovery.

The postmortem (the written analysis after the fact) is judged by its follow-ups. The book's rule: "Every postmortem should feature a list of action items that address the underlying problems you found during the incident." (ch. 18). Each action has an owner, and is classed as short term (low-hanging fruit: two-factor authentication, patch deadlines) or long term, which takes more time (a security team, internal network encryption). Security-specific questions: did an expected control detect the attack, and how fast? Which normal procedures were bypassed during recovery? The book does not detail the blameless approach here and refers to another Google book. Another reference point: after Operation Aurora in 2009, BeyondCorp and FIDO keys took more time (ch. 18).

My reading

Outside the book, coding agents. After an incident caused by an agent's change, the postmortem actions become guardrails. Examples: a failing test, a rule in the agent's instructions file, a right withdrawn.

My honest take

I opened it with a question from a developer in a hurry: how do you ship without trembling? A machine now writes part of the code. The book does not answer that question, it does not know it. But it answers the one before: who has the right to do what, and how do you check what goes to production. For that, idea 7 alone is worth the trip, and idea 2 will spare you sleepless nights.

Its strength: it confesses. The empty file, the breakglass turned into a habit, the drill. You come away convinced that error is normal and that the system must anticipate it.

Two reservations. The scale is Google's. The version for a lone developer fits in a few sentences. You must build it yourself, with the floor of scripting every step. Then the code is mostly C++ and Java, Go barely, PHP not at all: the principles transfer, the listings do not.

My advice: read chapter 14 (deployment) first, then chapters 5 and 3 (rights and proxy), then 7 and 10. Chapters 6, 12 and 13 can be skimmed, except the passages on invariants and safe types.

Odilon

Still valid in 2026?

The principles hold: least privilege, mandatory review, verified deployment, fail static. The vocabulary and the tools have changed, and the book does not know them.

Who is it for?

Read it if

  • you ship a PHP or Go backend to production and want to know who should have which rights.
  • you have at least a few years of experience and already have a CI, but no check of what goes to production.
  • you have an agent write part of your code and want guardrails that do not depend on its good will.
  • you like a book that confesses its field failures, with figures.

Skip it if

  • you want Go or PHP code recipes to copy: the listings are mostly in C++ and Java.
  • you are alone and expect a step-by-step for a personal project: the minimal version fits in a few sentences.
  • you want the current threats (SBOM, SLSA, sigstore, AI): the book dates from 2020.

Going further

Note based on: chapters 1, 3, 5, 6, 7, 12, 13 and 14 read in detail, 10 and 18 skimmed. Some passages of chapters 2 and 15 were found by search. That is 77,000 words of the book's 181,000. The rest is triaged but not read.

Comments (0)

On the same shelf

Networking and security

See the whole shelf (8 notes) →

Browse the whole library

More book notes coming: one book at a time, the marrow only.