Skip to content
Indra on Cloud
Go back

I Could See Every Resource. I Still Could Not Rebuild It.

Left, a complete inventory of resources in a project. Right, the same project with the state backend, CI credentials, registrar and keys drawn outside its boundary, greyed out and unreachable.

The platform I work on applies generated Terraform into the customer’s own Google Cloud project. That means the starting state is almost never an empty project. A tenant arrives with things already running, built by someone else, and the platform has to work out what it can adopt rather than create.

Doing that repeatedly taught me something that applies just as much to a handover between two companies as it does to a generator: listing what exists is the easy half, and it is not the half that decides anything.

The question an inventory does not answer

Point any tool at a project and you can enumerate it. Services, buckets, topics, databases, IAM bindings. On the largest tenant I work with that is 613 resources described by a 10,000-line generated config, and enumeration is not the part that is hard.

The question that actually matters when you are taking something over is different:

If the people who built this disappeared tomorrow, could I stand it up again?

Nothing in a resource listing answers that. A list tells you what is running. It does not tell you what is reproducible, and the distance between those two is where handovers fail.

The inventory does not describe itself honestly

Before you can even trust the list, you have to know how it lies. I wrote up three of these in detail when the platform learned to adopt existing infrastructure instead of creating it: service accounts that are addressed by a numeric id rather than the name you see, Firestore addressed by project number, and two resource types that a bulk inventory call simply never returns at all.

That last one is the dangerous shape. For those types, absence from the inventory is indistinguishable from absence from the cloud. You cannot tell “this does not exist” from “I cannot see this”, and the two lead to opposite decisions. Every candidate needs a second signal before you act on it: Delete the State File. Redeploy. Nothing Should Happen.

Get this wrong in a handover and the failure is quiet. You conclude a resource needs rebuilding, you rebuild it, and now there are two.

The things that are not in the project at all

A checklist split into two columns, in-project resources on the left all ticked, out-of-project dependencies on the right unticked and marked ask the provider.

This is the part a read-only audit of the cloud project structurally cannot reach, because the things that block an independent deploy usually live somewhere else:

The state backend. Where is the Terraform state, and who can write to it? If it sits in a bucket in the builder’s own project, you do not have the thing that maps config to reality. You have config, and a cloud, and no link between them.

Whatever runs the deploys. A pipeline in the builder’s CI account, holding a service account key you have never seen, is doing the one job you most need to be able to do yourself.

Identities that live above the project. Service accounts, workload identity bindings and org-level policy can be granted from outside the project boundary. The bindings are the topology, which is the argument I made for per-service identity rather than one shared account, and it applies here too: read the bindings and you learn what talks to what, including from outside.

Domains, DNS and third-party keys. Registrar logins, payment and email provider credentials, push certificates. None appear in a cloud inventory. All of them stop a launch.

Anything created by hand. A resource created in the console at 2am to unblock something is in the cloud and not in the state. It will not be recreated, and nobody will remember it until it is missing.

Existing is not the same as working

There is a last trap worth naming, because it survives every check above. A resource can exist, be in state, be fully described, and still not run.

The case that taught me this was a service that referenced its container image by digest. The Terraform was valid, the plan was clean, the apply created the service, and the service could not start, because the image did not exist yet. Nothing in the configuration was wrong. The ordering was.

So the acceptance question is not “is it declared” and not even “does it exist”. It is “does it run”, and that is a different check that most handover checklists skip because the first two passed.

What I would tell someone taking over infrastructure

Separate the two questions early. What exists is discoverable and cheap. What is reproducible is the deliverable. Do not let a long resource list stand in for the second one.

Write the gap list, not the inventory. The useful output of an assessment is the shortest possible list of things you cannot determine on your own, phrased so the other side can answer each one. That list is what unblocks the handover.

Assume absence means “I cannot see it”. For anything you plan to rebuild rather than adopt, get a second signal first. A rebuild against something that already exists is the expensive mistake, and it is silent.

Look outside the project boundary on purpose. State backend, CI credentials, registrar, third-party keys, org-level identity. None of it shows up where you are looking, and all of it is load-bearing.

Keep the assessment read-only, and say so. On a live system with real users, the audit that changes nothing is the only one worth trusting, and it is also the only one you can run before anybody agrees on a plan.


Share this post:

Previous Post
The Device Went Quiet. Quiet Is Not a Reading.
Next Post
The App Balanced the Ledger. The Database Refused the Write.