Frontend Labs
⋯

Chapter 3 — Assume breach: lateral movement, persistence, and containment by design

In one sentence

Design as if the attacker already has a foothold, and judge every control by how much it slows their movement, how quickly it forces them to make noise, and how small it keeps the blast radius.

Where we are

Prevention fails eventually — a phish lands, a token leaks, a dependency is poisoned (G1 Ch 47). Assume-breach architecture accepts that and optimises for containment and detection instead of pretending the perimeter holds.

How it works

The attacker's post-foothold loop:

   ORIENT     where am I? what identity do I have? what can it reach?
              (whoami, env vars, metadata, mounted secrets, token scopes,
               network neighbours)
   ESCALATE   get a more powerful identity (IAM privesc, k8s RBAC abuse,
              sudo, a service token)
   MOVE       reach the next system (reused creds, trust relationships,
              exposed internal services, SSRF, mesh calls)
   PERSIST    survive a reboot / rotation (new IAM key, cron, k8s
              CronJob/DaemonSet, OAuth grant, SSH key, webhook)
   COLLECT    find and stage the data
   EXFIL      move it out (cloud storage in the attacker's account, DNS,
              a webhook, a pastebin)
   Each step is an opportunity to CONTAIN (make it impossible) or DETECT
   (make it loud).

Containment-by-design controls, mapped to the loop:

   ORIENT     minimise ambient discovery: no broad `list`/`describe`, no
              wildcard read, workload identity scoped to exactly what the
              service needs, secrets injected not mounted broadly, network
              default-deny so "who's my neighbour" returns nothing.
   ESCALATE   remove privesc edges (Part 2 Ch 6, Part 4 Ch 17); permission
              boundaries / SCPs cap the ceiling; no standing admin (JIT).
   MOVE       segmentation (G1 Ch 39) + identity on every hop (mTLS, Part 5)
              so a reachable service still refuses an unauthenticated or
              wrong-identity call; unique creds per service (no shared DB
              user); short-lived everything.
   PERSIST    immutable infra (no in-place changes; drift = alert);
              short-lived credentials so a stolen one dies; detections on
              "new IAM key created", "new admission webhook", "new
              CronJob", "OAuth app authorised".
   COLLECT    tenant isolation + data-access limits (Part 7) so even broad
              read can't scoop everything; canary records that alert on
              access.
   EXFIL      egress default-deny with an allowlist; DLP on known channels;
              block/alert on writes to storage outside your accounts;
              detections on large or unusual outbound.

The blast-radius question, for every component: "if this is fully compromised, exactly what is now exposed, and what stops it spreading further?" Write the answer down. If it's "everything", you have a flat trust domain and that's the finding.

Worked example

Assume-breach analysis of the web pod in SecureShop.

   FOOTHOLD: RCE in the `web` pod (say, an SSTI -- Part 6 Ch 36). Attacker
   has a shell as the `web` container's user.

   ORIENT -- what do they find?
     env: DATABASE_URL? (bad -- should be injected per-request or not here)
     mounted SA token: `system:serviceaccount:edge:web` -- what can it do?
     IMDS: reachable? IMDSv2 hop-limit-1 -> only from the node, and the pod
       is not the node -> creds not directly reachable (good).
     network: can it reach `core/orders-api`? mesh says yes, but mTLS +
       an OpenFGA check means an unauthenticated call is refused (good).
       Can it reach the DB directly? NetworkPolicy: `data` namespace only
       accepts `core` -> no (good).

   ESCALATE -- SA `edge:web` RBAC: `get`/`list` on pods/services in
     `edge` only, no secrets, no create. `kubectl auth can-i --list`
     confirms. No obvious privesc. (If it had `create pods` -> node ->
     etcd; Ch 17.)

   MOVE -- best option is to abuse `web`'s legitimate identity: call
     `orders-api` as `web`. OpenFGA only lets `web` do `create:order` for
     the authenticated end-user in the request context -> attacker can't
     read arbitrary orders without a valid user session. Blast radius so
     far: whatever `web` is legitimately allowed to do on behalf of
     whoever is currently logged in. Contained.

   PERSIST -- container FS is read-only; pod will be rescheduled on any
     node drain; no cron. Persistence requires escalating first.

   DETECT -- do we see the shell? Falco rule "shell spawned in container"
     + "outbound connection from `web` to a non-mesh destination" +
     "process not in the `web` image's known set". If those fire, IR
     starts (Ch 55).

   VERDICT: blast radius of a full `web` compromise = "act as `web` for
   the current request context; read nothing cross-tenant; no host, no
   cluster, no DB". That's a designed outcome, and each "no" above is a
   specific control you can point to. The gaps (env has DATABASE_URL;
   detection unproven) become tickets.

Real-world scenario: Google's post-Aurora shift to assume-breach

   Google has publicly documented (in its own "BeyondCorp" and
   "BeyondProd" engineering papers) that its move toward an explicitly
   assume-breach, zero-trust architecture was driven directly by a real
   intrusion: "Operation Aurora" (disclosed January 2010), a
   state-sponsored campaign that compromised Google's (and several other
   major companies') internal corporate networks via a browser
   zero-day and then moved laterally, treating the internal network as
   implicitly trusted -- exactly the flat-trust-domain failure mode this
   chapter's Chapter 3 opens with.
   Google's own account of the resulting redesign maps directly onto
   this chapter's containment-by-design table: no more implicit trust
   from network location (every internal service authenticates every
   caller, regardless of which network segment the call came from),
   workload identity on every hop (the direct ancestor of this guide's
   Part 5 SPIFFE material), and a deliberate assumption that ANY given
   machine or credential could already be compromised. It's one of the
   most influential real-world adoptions of the exact posture this
   chapter teaches, published in enough technical detail to study
   directly.

Practice (45 min)

  1. For SecureShop (or your system), pick three components: a front-end, an internal API, a CI runner. For each, write the ORIENT -> ESCALATE -> MOVE -> PERSIST -> COLLECT -> EXFIL analysis assuming full compromise.
  2. For every step, note: is it contained (impossible) or only detected (loud) or neither? Neither = a ticket.
  3. Write the one-sentence blast-radius statement for each component. Any that read "broad" or "everything" get escalated.
  4. Compare with your Chapter 0.6 instinct for question 1 ("shell in the web pod").

Common mistakes

  • Perimeter as the plan. "We have a WAF and a VPN" is not containment.
  • Flat trust domains inside the perimeter. The office network, the VPC, the cluster, the "internal" API tier — if everything inside trusts everything inside, one foothold is total.
  • Standing privileges. Long-lived admin creds, permanent break-glass, a CI role that can deploy anywhere — all are persistence gifts.
  • Detection you've never tested. "We'd see that" — did you run it (Ch 2)?
  • No blast-radius statement. If nobody has written "if X falls, Y is exposed", nobody actually knows.

Check yourself

  1. List the steps of the post-foothold loop and one containment control for each.
  2. What is a "blast-radius statement" and when is it a finding?
  3. Why are long-lived credentials specifically a persistence problem?
  4. Contain vs detect: what's the difference in outcome, and why do you want both?
  5. What makes a trust domain "flat", and why is that dangerous under assume-breach?

Further reading

  • Model: Google BeyondProd paper (assume-breach for microservices); NIST SP 800-207 (Zero Trust) re-read through an assume-breach lens.
  • Report: Mandiant M-Trends (annual) — real dwell times, lateral-movement and persistence techniques seen in incidents.
  • Talk: "Assume Breach" talks from BlackHat/BSides; the "Prevent, Detect, Respond" framing from the SANS blue-team courses.
  • Book: Building Secure and Reliable Systems (Google) — Ch. on understanding and containing compromise.

Generated from real-life-security-guide-v1.md · 8 Oct 2026 16:36