Imported from matt-FFFFFF/fleet (
terraform/stages/1-cluster/AGENTS.md). Install upstream withnpx skills add matt-FFFFFF/fleet --skill 1-cluster. Copyright stays with the author.
stages/1-cluster/
Per-cluster infra. One state per cluster. Runs in CI per matrix leg.
What it creates
AKS (Entra-only, private, Cilium), per-cluster KV, private DNS zone + VNet links (env + mgmt), DCR/DCRA + Prometheus rule groups, per-cluster UAMIs + FICs, RBAC (ESO on mgmt cluster KV, external-dns, ACR pull, kubelet identity assignments). Mgmt cluster also creates uami-kargo-mgmt.
The var.doc contract
var.doc is intentionally untyped (any) — the loader output (terraform/config-loader/load.sh) is the contract. Stage validates via lifecycle.precondition blocks and trusts loader-side checks (networking.subnet_slot integer, CIDR math, subscription_id presence).
Stage TF reads:
var.doc.cluster.{name,env,region,subscription_id,role}var.doc.derived.{dns_zone_fqdn,keyvault_name,acr_login_server,networking.*}var.doc.fleet.{name,tenant_id,...}
Stage TF never calls terraform_remote_state and makes zero Azure data-source calls at plan time for Stage 2 prep — Stage 2 receives Stage 1 outputs via in-job terraform output -json → stage2.auto.tfvars.json.
CI-injected TF_VARs (not authorable here)
From bootstrap/environment GH env vars (decoded by tf-apply.yaml):
env_region_vnet_resource_id,mgmt_region_vnet_resource_idnode_asg_resource_id,route_table_resource_idacr_resource_id(repo var from env=mgmt)env_monitor_workspace_id,env_dce_id,env_action_group_idmgmt_cluster_kv_id(nullable, gates ESO role assignment on mgmt cluster KV)mgmt_aks_oidc_issuer_url,kargo_mgmt_uami_principal_id,fleet_env_uami_principal_id
Files
main.tf module wiring; var.doc consumption
main.network.tf azapi subnet children (snet-aks-api /28, snet-aks-nodes /25)
main.aks.tf ../../modules/aks-cluster (depends_on subnets)
main.kv.tf ../../modules/cluster-kv
main.monitoring.tf ../../modules/cluster-monitoring (count gated by managed_prometheus_enabled)
main.identities.tf per-cluster UAMIs + FICs
main.identities.kargo.tf mgmt-only: uami-kargo-mgmt
main.rbac.tf ESO, external-dns, ACR pull, kubelet RAs
outputs.tf MGMT_CLUSTER_KV_ID publish (mgmt only), Stage 2 handoff
Mgmt collapse semantics
When env=mgmt, the env VNet and the mgmt VNet are the same. The stage detects collapse by comparing resource ids, not env strings:
cluster-dns.linked_vnet_idsdeduplicates equal env+mgmt ids (the map key collapses).ra_eso_mgmt_cluster_kvcount gated on cluster being mgmt (collapse target).
Anti-patterns
- Adding HCL types to
var.doc. Breaks loader evolution. - Authoring routes in env shells — UDR lives here (gated on
egress_next_hop_ip). - Calling
terraform_remote_statefor cross-stage data. - Duplicating
linked_vnet_idsentries when env==mgmt — handle collapse by id equality. - Authoring
azurerm_*resources.azapionly.