Exercises: Infrastructure as Code
Several of these need a cloud account and cost real money. The ones that do are marked, and the
plan-reading exercises — which are the most valuable in the chapter — need only a terraform show
-json output you already have.
code/plan_review.py parses plan JSON and needs no Terraform, no cloud account, and no network.
Difficulty: ⭐ warm-up · ⭐⭐ standard · ⭐⭐⭐ deeper.
Solutions: daggered (†) and odd-numbered problems are in
appendices/answers-to-selected.md.
Part A — Warm-ups ⭐
28.1 † Reproducibility buys three things. Rank them by value and say which is most often cited.
28.2 What is Terraform state, and why is it not derived from reality? Name the three things that go wrong.
28.3 † State the boundary between Terraform and your pipeline, and give both arguments for it.
28.4 What does -/+ mean in a plan? Why is a rename the dangerous case?
28.5 † Why pin a container image by digest rather than by tag?
28.6 Give the three genuine reasons to use Kubernetes. Which is the most common good one, and what is not on the list?
28.7 † How do you adopt infrastructure as code on a platform that already exists? What is the most valuable artifact of the exercise?
28.8 What is a state file's real unit, and which split should you make on day one?
28.9 † Trace a warehouse credential from a CI job to a dbt process, with no long-lived secret.
28.10 Why is drift not a discipline failure? What are the three design goals instead?
Part B — Standard ⭐⭐
28.11 Take a real terraform plan from your own systems, export it with terraform show -json,
and run plan_review.py against it. Report the findings and whether each is real.
28.12 † Find every stateful resource in your configuration and check whether it has
prevent_destroy. Report the count without it. Case Study 1's audit found twelve, including both
lake buckets.
28.13 Write a change that would replace a stateful resource — a rename is easiest — and confirm
that both prevent_destroy and plan_review.py stop it. Do this in a scratch environment.
28.14 † Pin one image by digest and measure. Report the image size before and after a multi-stage rebuild, and estimate the per-task startup cost at your own task volume.
28.15 Run terraform plan -refresh-only against a real environment. Report the drift. Write
down your prediction before running it, as Case Study 2's last question asks.
28.16 † For each drift finding in 28.15, classify it: should it be adopted into code, reverted, or left with a note? Do this before deciding what to do, because the classification is the exercise.
28.17 Import one existing resource with an import block and get to a clean plan. Report every
difference between what you believed and what was there.
28.18 † Write the post-apply assertion from §28.12 for one resource — verify the thing behaves as expected rather than that the command succeeded. Then break the resource by hand and confirm the assertion fails.
Part C — Deeper ⭐⭐⭐
28.19 §28.1 argues review is worth more than recreation. Test the recreation claim: estimate how long it would take to rebuild your platform from your configuration alone. Be honest about what is not in it.
28.20 † §28.5 says most data teams do not need Kubernetes. Price it for your team: the operational load, the isolation you would lose without it, and the alternatives. Which of §28.5's three reasons applies to you?
28.21 Case Study 2's pattern is "one actor changes reality, another restores the declared state." Find three instances in your systems — not necessarily Terraform — and say for each whether the convergence notifies anyone.
28.22 † Design the plan-output improvement §"The Analysis" asks for: distinguishing changes the author requested from changes that come along. State what information it needs and whether Terraform's JSON contains it.
Part D — The Kestrel Platform ⭐⭐⭐
28.23 — Increment 28: the platform, in files.
(a) Terraform state remote, versioned, locked, and backed up separately from whatever backs up everything else.
(b) The boundary respected: no table resources anywhere. prevent_destroy on every stateful
resource.
(c) Write a plan that would replace a stateful resource, and confirm that both prevent_destroy and
plan_review.py stop it. Two independent controls, each tested — because Chapter 27 Case Study 2's
lesson is that a control you have not seen fail is a hypothesis. This is the exercise that carries
the chapter.
(d) A digest-pinned multi-stage image. Report the size and the per-task startup change.
(e) Three environments from one module, with the differences as a readable list.
(f) OIDC to a role, short-lived warehouse tokens, secrets in a manager. Then answer §28.9's 🔐 question: what can read production, and how long has each of those credentials existed?
(g) A nightly drift check posting to a channel at 07:00 — after the on-call window — with wording that reads as information.
(h) default_tags including managed_by, and a budget in the same repository as the thing it
constrains.
28.24 † Split the state into stateful and stateless. Report what you had to move, and how many cross-state references it created.
Do this before you need to. Case Study 2's team said the split they would make on day one is this one, and retrofitting required moving resources between states — the one Terraform operation with no good story.
Reflection
A. Case Study 1 was a destructive change that looked cosmetic; Case Study 2 was two correct actions composing into a wrong outcome. Neither had a careless person in it. How many of this book's twenty-odd incidents did? What does that ratio imply about where to spend your next improvement?
B. §28.10 asks you to treat drift as information. That is a claim about culture, not tooling. What would have to be true about how your team responds to a drift report for the nightly check to produce more documented changes rather than fewer?