# ADR-0006: IaC split — Ansible hosts, Terraform ground, Flux ground-only, fleet manifest for drones ## Status Accepted (2026-07-08) ## Context Three very different things need provisioning: (1) drone hosts, which are air-gapped and never reachable by a controller in flight; (2) the ground segment (warehouse, observability, offload), a normal k3s cluster; (3) the simulation environment that mirrors the ground segment locally. Using one tool for all three would force a GitOps controller or a Terraform apply loop onto the drone — impossible for an autonomous, disconnected node ([ADR-0001](ADR-0001-no-swarm-orchestrator.md)). ## Decision Split infrastructure ownership by lifecycle: | Layer | Tool | Scope | | --- | --- | --- | | Host preparation | **Ansible** | Drone bench prep (keys, forced commands, WireGuard, Compose bundle) and the local k3d sim cluster | | Ground workloads | **Terraform** | k3s/k3d resources: virtual fleet + observability (`sim-env`), warehouse + T1→T3 offload (`ground`) | | Ground continuous delivery | **Flux (GitOps)** | Ground segment **only** — policy labels, dashboard bundles | | Drone delivery | **Fleet release manifest** | A versioned, digest-pinned artifact list; no controller pulls to the drone | Drones are delivered by the **fleet release manifest** (one version for the whole fleet, atomic rollback), never by a controller reaching into the air. ## Consequences - No GitOps agent or `terraform apply` ever targets a drone; the air side stays controller-free. - Terraform state is environment-local and kept out of Git ([ADR-0008](ADR-0008-runtime-data-paths.md)). - The sim cluster is a faithful miniature: the same Terraform describes it and the ground segment. - Boundaries are documented in [`../06-environments.md`](../06-environments.md#iac-boundaries); delivery in [`../11-cicd-delivery.md`](../11-cicd-delivery.md).