The First Apply Is Local (and That's Fine)

The First Apply Is Local (and That's Fine)

TL;DR. The deployment chain that applies your IaC is itself infrastructure — and something has to create it first. Instead of hand-building the pipeline chain before the code could run, we applied the foundation locally, with a human identity, onto the exact remote state path the pipeline would later use — then wired the pipeline and let it adopt the state. Success had a measurable definition: the pipeline’s first plan returns No changes on every unit. It did. And the decision is an ADR, because the least-written-down phase of every platform is the one that created it.

Every IaC platform has a creation myth nobody documents. The pipeline applies the code — but the pipeline’s identity, its service connection, its approval gates are also infrastructure, and something applied the first version of them. Usually a laptop. Usually in a hurry. Usually never spoken of again.

We hit the moment explicitly on a recent landing zone: foundation code written and validated, and no deployment chain at all — no service connection, no pipeline identity, no gated environment in the project. Two ways forward.

The two orders

Chain first. Stand up the service connection, bootstrap the pipeline identity, grant its roles, create the environment and its checks — then let the pipeline do the first apply. Purist, and slow in the worst way: it front-loads several days of manual, cross-portal round-trips during which the finished code sits unverified. You’re doing ClickOps to avoid ClickOps.

Code first, locally. Apply the foundation with a human identity that already holds every required permission, then build the chain and hand over. The objection writes itself: “you applied production from a laptop.” The answer is in the constraints.

What made local-first safe here

This isn’t a universal license; it rested on three specific conditions, and the ADR lists them:

  1. The human identity already had everything. Full rights on the target subscription, on the peered hub side, and data-plane access to the state storage. No permission was invented for the occasion.
  2. Nothing in the foundation required a pipeline-only context. No resource whose data plane is reachable only from a private network the pipeline runs in. (A private Key Vault whose content must be written from inside the network would have flipped the decision.)
  3. The state went to its final home immediately. The local applies wrote to the exact remote state path the pipeline would later use — same storage, same key convention. No local state, no migration later, no second source of truth. This is the condition that makes the whole move reversible-free.

The measurable handover

The wager of local-first is that the pipeline can pick up the work without recreating anything. That gives the handover a pass/fail definition most bootstraps never get:

Wire the chain, run the pipeline’s first plan under its own identity, and require No changes across every unit.

Anything else — a tag diff, a case-sensitive name, a default the human’s provider filled differently — is a bootstrap bug, caught before the pipeline’s first apply rather than during it. Ours came back clean, which retroactively made the laptop applies what they were always meant to be: a temporary identity swap, not a parallel process.

The epilogue matters as much as the sequence: the ADR was updated with a settled note the day the chain went live, and local applies were re-scoped to bootstrap and documented break-glass only. The laptop path still exists — pretending otherwise is how it gets used in secret — but now it’s written down, bounded, and exceptional.

The shape of it

Bootstrapping order is a real architecture decision — it deserves an ADR, conditions, and a success test, like anything else that touches production. If you choose local-first: same state path as the future pipeline, an identity that already has the rights, and a handover defined as No changes. If you can’t meet those three, you’ve also learned something — your foundation has a hidden dependency on the chain, and it’s better to meet it on paper than at apply time.

This was one decision among the many that stamping a second landing zone forced into writing — that bigger story is here.

References

Related Posts

The AVM ALZ accelerator is solid. Here's what we add on top (and what we'd do differently)

The AVM ALZ accelerator is solid. Here's what we add on top (and what we'd do differently)

TL;DR. The official Azure/avm-ptn-alz/azurerm module covers the essentials of an Azure Landing Zone correctly. Three things aren't in the box and cost us time: explicit pinning of the alz/`a

read more
Building 60+ Terraform Modules for an Azure Landing Zone

Building 60+ Terraform Modules for an Azure Landing Zone

Why Build From Scratch? When I started building the Azure Landing Zone for a regulated European telecom operator, the obvious question was: _why not just use the Azure Verified Modules (AVM) direc

read more
The Second Landing Zone Is the Real Test of the First

The Second Landing Zone Is the Real Test of the First

TL;DR. We stamped out a second application landing zone from the first one. The diff between the two repos is six values: subscription, name acronym, address space, project, service connecti

read more
Running a 79-Module Terraform Library Like a Product

Running a 79-Module Terraform Library Like a Product

TL;DR. A shared Terraform module library has two possible futures: product or landfill. Ours holds 79 modules consumed live from main by four landing zones — no pinning. The only reason th

read more
When terraform plan says 'no changes' and the feature is broken anyway

When terraform plan says 'no changes' and the feature is broken anyway

Everything was green. Workspace deployed, host pool up, users assigned, RBAC clean. Then a user opens Windows App and hits: "No devices or apps found." The feed never loads. Nothing in the Azure

read more
Why I Don't Use AVM Modules As-Is (And What I Do Instead)

Why I Don't Use AVM Modules As-Is (And What I Do Instead)

AVM Is Great — But Not For Everything Azure Verified Modules are the gold standard for Terraform on Azure. Microsoft maintains them, they follow

read more
GitOps Without PATs: Argo CD to Azure DevOps via Workload Identity

GitOps Without PATs: Argo CD to Azure DevOps via Workload Identity

TL;DR. Argo CD can authenticate to Azure DevOps repos with Entra Workload Identity instead of a PAT: a user-assigned managed identity, a federated credential bound to the `argocd-repo-server

read more
Argo CD, Managed by Argo CD

Argo CD, Managed by Argo CD

TL;DR. Argo CD deploys everything from Git — except, too often, its own configuration, which someone once kubectl apply'd and everyone now fears touching. We closed the loop: a platform AppP

read more
Azure Virtual Desktop: from POC to prod, the hardening checklist

Azure Virtual Desktop: from POC to prod, the hardening checklist

TL;DR. A fully private AVD POC that works is not a prod. Between the two: harden the FSLogix storage (NTFS ACLs, backup), automate secret rotation, wire up observability (AVD Insights + dedicate

read more
Deploying Azure Virtual Desktop End-to-End in a Landing Zone

Deploying Azure Virtual Desktop End-to-End in a Landing Zone

TL;DR. This is the deployment walkthrough for a fully private, Entra-only Azure Virtual Desktop environment inside a regulated Azure Landing Zone. Pooled Windows 11 multi-session on a **cust

read more
Azure Virtual Desktop in a regulated Landing Zone: the traps no doc tells you about

Azure Virtual Desktop in a regulated Landing Zone: the traps no doc tells you about

TL;DR. Deploying Azure Virtual Desktop fully private in a Landing Zone (Private Endpoints everywhere, Palo Alto NVA for egress, centralised DNS) works very well — once you know about a dozen

read more
Azure Landing Zone with Palo Alto NVA: Lessons Learned

Azure Landing Zone with Palo Alto NVA: Lessons Learned

Deploying Palo Alto VM-Series as a Network Virtual Appliance in an Azure Landing Zone sounds straightforward — until you actually do it. This article covers the hard-won lessons from building the fire

read more
SubnetWithNsg: How Azure Policy Deny Forced Me to Use azapi

SubnetWithNsg: How Azure Policy Deny Forced Me to Use azapi

The Problem Every production Azure Landing Zone deploys a Deny policy: "Subnets must have a Network Security Group." It is a security best practice — no subnet should exist without an NSG cont

read more