Terraform Declarations to Physical Reality
Review Terraform as a proposal for real compute, memory, storage, and network changes—not as a deployment success signal.
The enterprise problem and today’s slice
Enterprise problem: A small Terraform diff can replace a node pool, allocate paid disks, or widen network reachability while the enterprise AI workflow platform remains unavailable; treating apply as customer proof hides both cost and outage risk.
Whole-course context: The incoming artifact is the cluster substrate map: pod requests land on nodes, nodes are VMs backed by hardware, and workload identity is independent of machine supply.
Today’s slice: We compare Terraform HCL, plan, state, provider APIs, managed node pools, and the eventual CPU, memory, storage, and network effects for the same enterprise platform.
End-of-day evidence: A signed plan, state version, provider operation IDs, node/VM IDs, pod placement, disk and network observations, customer probe, and denied unsafe plan form one run record.
Still unsolved: Module strategy, multi-account governance, disaster recovery, and application GitOps remain separate delivery decisions.
Customer use cases
Infrastructure declarations are unsafe when their hardware effects are inferred from syntax. These use cases require an approved change to reach a customer-visible result and a risky change to stop before it changes reality.
| Use case ID | Actor | Customer job | Success outcome | Denial or recovery evidence |
|---|---|---|---|---|
| D70-UC-01 | Platform engineer | Increase node capacity for the workflow API without losing traceability | Reviewed infrastructure change creates the intended nodes/disks/network bindings and schedulable pods pass the customer probe | A replacement or quota failure is visible before or during apply; prior healthy capacity remains recorded |
| D70-UC-02 | Change reviewer | Reject a plan that would exceed policy or destroy protected state | Plan policy blocks unsafe create/replace/delete actions without calling provider mutation APIs | Denial records actor, plan hash, rule, expected/observed graph, and an unaffected platform probe |
Actor-centred user stories
State is not a copy of hardware; it is Terraform’s binding between a configuration address and a remote object. These stories make that distinction operational.
| Story ID | Use case IDs | User story | Observable acceptance conditions |
|---|---|---|---|
| D70-US-01 | D70-UC-01 | As a platform engineer, I want to explain each approved Terraform action down to node capacity and pod placement, so that I can predict compute, memory, storage, and availability consequences | Plan hash, state serial, provider IDs, VM/disk/network IDs, node readiness, pod placement, and probe result are retained |
| D70-US-02 | D70-UC-02 | As a change reviewer, I want dangerous replacements and deletes rejected before apply, so that review is an effective control rather than an after-the-fact report | Denied plan has no provider mutation audit event; approved control plan still reaches expected runtime evidence |
End-to-end product flows
Terraform has a control loop distinct from Kubernetes: it compares configuration, its state bindings, and refreshed provider reality, then asks provider APIs to converge. The customer result occurs only after nodes register and pods become ready.
| Flow ID | Use case IDs | Path | Trigger | Numbered steps | Terminal evidence |
|---|---|---|---|---|---|
| D70-FLOW-01 | D70-UC-01 | Happy | Capacity review approves a node-pool increase | 1. Runner reads remote state and provider reality. 2. Plan proposes bounded actions. 3. Reviewer approves saved plan. 4. Apply calls provider APIs. 5. Provider allocates VM, disk, NIC, and control-plane configuration. 6. Kubelet registers Nodes. 7. Scheduler places pods and probe verifies the workflow API. | Plan hash, state serial, provider operation IDs, VM/disk IDs, Node UID, pod UID, HTTP result, timestamp, immutable run ID |
| D70-FLOW-02 | D70-UC-02 | Denied | Proposed plan replaces protected cluster or exposes a network | 1. Policy parses planned actions. 2. Rule detects forbidden replacement/delete/exposure. 3. Apply authority is withheld. 4. Provider audit confirms zero mutations. 5. Existing platform probe remains healthy. | Actor, plan hash, rule ID, denied action graph, zero-mutation audit result, positive-control probe, timestamp |
The configuration is intent, while the plan is Terraform’s proposed graph of provider operations. Neither box proves that a workload is ready yet.
System design derived from the flows
The dangerous gap is between a provider API accepting a request and a workload actually obtaining usable resources. This architecture keeps Terraform state, provider inventory, Kubernetes status, and customer evidence authoritative for their own facts.
| Use case ID | Entry point | Responsible services | Authoritative store | Failure evidence |
|---|---|---|---|---|
| D70-UC-01 | Reviewed infrastructure repository and Terraform runner | Terraform CLI/backend, provider plugin, cloud APIs, managed node service, kubelet, scheduler, workflow probe | Git for intent, Terraform backend for bindings, provider inventory for infrastructure, Kubernetes API for node/pod state | State lock, quota/API error, replacement, unregistered node, Pending pod, failed readiness/probe |
| D70-UC-02 | Policy evaluation of saved plan | Plan policy engine, approval service, Terraform runner, provider audit, customer probe | Policy decision and plan artifact; provider audit; immutable evidence store | Forbidden action, missing approval, unexpected drift, mutation despite denial, or failed positive control |
The original configuration, plan, and evidence remain unchanged. State binds a Terraform address to a remote object ID; provider APIs make or change the real resources; node registration is the bridge from infrastructure supply to Kubernetes placement.
Data model and ownership
Generated-application database: Not created in this slice — Terraform backend, provider inventory, Kubernetes status, and evidence records are the durable control-plane state; customer workflow data remains in its generated-application store.
| Record or entity | Store and owner | Primary key | Foreign key or opaque reference | Tenant key | Material constraint | Lifecycle and deletion | Use case IDs |
|---|---|---|---|---|---|---|---|
| TerraformStateVersion | Remote backend, owned by platform infrastructure | Workspace plus state serial | Opaque provider resource IDs | Cloud account/project and environment | Locked for one apply; sensitive values access-controlled; addresses uniquely bind remote objects | Written after apply, versioned/retained, retired only through reviewed migration/deletion | D70-UC-01, D70-UC-02 |
| InfrastructureChangeEvidence | Evidence store, owned by change governance | Immutable run ID | Plan hash, state serial, provider operation IDs, Node/Pod UIDs | Environment | Denied plans must have no mutation IDs; positive and negative paths share observation window | Created per review/run, immutable retention, expires by policy | D70-UC-01, D70-UC-02 |
The evidence now proves both control loops: Terraform changed only what the approved plan named, and Kubernetes plus the customer probe observed a usable runtime. It also supports recovery: compare refreshed reality with state, create a new reviewed plan, and never edit state JSON as a shortcut.
Code-to-reality comparison
This GKE-shaped example is representative rather than a portable hardware contract: the provider chooses physical host placement, while the declared machine type and disk configuration request virtual capacity and policy.
The Terraform resource names differ between EKS and GKE, but the underlying question is the same: which provider API changes worker-machine supply, and which Kubernetes evidence proves those machines can run the workflow API? Neither declaration grants the workload cloud authority; that remains an explicit ServiceAccount-to-cloud-identity binding.
| Same layer | EKS-shaped declaration and effect | GKE-shaped declaration and effect | What remains customer-owned |
|---|---|---|---|
| Managed control plane | aws_eks_cluster asks AWS to operate Kubernetes control-plane infrastructure | google_container_cluster asks Google Cloud to operate Kubernetes control-plane infrastructure | Cluster endpoint policy, Kubernetes access choices, workload manifests, observability, and customer outcome |
| Worker compute and memory | Managed node group or Karpenter supply requests EC2 instances with selected vCPU/RAM shapes | google_container_node_pool requests Compute Engine VM capacity with selected machine type | Pod requests/limits, scheduling policy, workload scaling, and cost guardrails |
| Node storage and network | EBS-backed node disks plus VPC subnet/security-group attachments become available to nodes | Persistent Disk-backed node disks plus VPC-native routes/firewall policy become available to nodes | Persistent-volume lifecycle, NetworkPolicies, data access, and workload exposure policy |
| Runtime proof | EC2 instance becomes Ready Kubernetes Node, then a pod schedules and customer probe passes | Compute Engine VM becomes Ready Kubernetes Node, then a pod schedules and customer probe passes | Incident response and evidence that the application—not merely infrastructure—works |
resource "google_container_node_pool" "workflow" {
name = "workflow"
cluster = google_container_cluster.platform.id
autoscaling { min_node_count = 2; max_node_count = 6 }
node_config {
machine_type = "e2-standard-4" # Provider selects a VM shape with vCPU and RAM capacity.
disk_type = "pd-balanced"
disk_size_gb = 100 # Requests persistent block-storage capacity per node.
}
}
| HCL or command | Who interprets it and state change | Compute, memory, storage, network reality | Proof after execution |
|---|---|---|---|
machine_type | Provider plugin/API updates node-pool desired configuration | New or replacement VMs obtain virtual vCPU/RAM backed by provider hosts | Provider operation plus kubectl get nodes -o wide |
disk_size_gb | Provider disk service creates/expands node boot disks | Persistent block capacity is allocated; filesystem availability depends on node image/bootstrap | Provider disk ID and node filesystem metrics |
max_node_count | Node autoscaler ceiling changes | No VM is created until unschedulable demand triggers scale-out | Autoscaler event, new VM/Node UID, then scheduled pod |
terraform apply saved.tfplan | Terraform writes state only after provider actions complete | May create, modify, or delete billable resources; it does not prove application readiness | State serial, provider audit, node/pod status, customer probe |
Run, fail, and recover
terraform plan -out=workflow.tfplan # Produce the exact reviewable operation graph.
terraform show workflow.tfplan # Inspect creates, updates, replacements, and deletes.
terraform apply workflow.tfplan # Execute only the approved saved plan.
kubectl get nodes -o wide # Verify provider capacity became Kubernetes Nodes.
kubectl -n platform get pods -o wide # Verify scheduling and runtime separately.
curl --fail --show-error "$PLATFORM_URL/healthz" # Verify customer-visible outcome.
Decision rule: approve the operation graph and its resource consequences, not the apparent size of the HCL diff. Treat state as sensitive binding data, serialize applies, and require provider, Kubernetes, and customer evidence before calling a change complete.
Primary references
Terraform state records the mapping between configuration addresses and remote objects, while plan previews proposed changes before execution: Terraform state and terraform plan.
Key takeaways
- Terraform configuration, state, provider resources, Kubernetes status, and customer evidence answer different questions.
- A VM/node declaration affects eventual compute, RAM, disk, and network supply, but pods run only after registration and scheduling.
- A denied plan with zero provider mutation is a first-class safety result.
Checklist
- [ ] Reviewed a saved plan for create/update/replace/delete operations.
- [ ] Joined a provider operation to node, pod, and customer probe evidence.
- [ ] Proved an unsafe plan is denied before provider mutation.