The Philosophical Developer -- Chapter 20: Azure on the Local Cloud

2026-07-10 · 5 min read

Azure on the Local Cloud

Two clouds down. One to go.

The AWS local cloud established the pattern. The GCP local cloud proved it ported to a different provider paradigm. This chapter closes the trilogy with Microsoft Azure using floci-az.

Azure is the hardest test for the methodology. Its provider works differently from both AWS and GCP. The azurerm provider uses a metadata discovery model where the provider fetches an endpoint document from a metadata_host to learn where every API lives. It does not accept per-service endpoint overrides.

The Metadata Discovery Pattern

When the azurerm provider starts, it sends a request to management.azure.com (or your configured metadata_host) to discover the Azure Resource Manager endpoints. The response is a JSON document that maps every Azure API to its base URL.

Floci-az serves this exact metadata document on port 4577. Set metadata_host to point at the emulator, and the provider routes every request to localhost without knowing it is not talking to real Azure.

provider "azurerm" {
  features {}

  metadata_host                   = "localhost:4577"
  resource_provider_registrations = "none"
}

The resource_provider_registrations = "none" tells the provider not to attempt registering resource providers on startup. Floci-az does not emulate Azure’s full registration flow, and local development does not need it.

Plan Mode Testing on Azure

Plan-mode tests are the backbone of the TDD approach for AWS and GCP. The command = plan flag in OpenTofu tests validates module structure, variable contracts, and output shapes without making any API calls. It works because both the AWS and GCP providers support skip_credentials_validation or equivalent flags.

Azure does not work this way.

The AzureRM provider (v4.x) requires authentication even for plan mode. It always tries to build an authorizer, whether through Azure CLI, managed identity, or service principal credentials. There is no skip_credentials_validation equivalent. This is a fundamental architectural difference in how the provider handles the plan phase.

This does not mean we skip testing. It means we test differently.

For Azure modules, validation uses tofu validate which checks the module structure, resource schemas, and variable types without needing any authentication. Every module passes tofu validate cleanly. The modules are then verified against a live floci-az emulator using tofu plan and tofu apply with the metadata_host pointing at the local endpoint.

The floci-az project itself follows the same approach. Their compatibility tests run tofu init, tofu validate, tofu plan, and tofu apply against a running emulator. They do not rely on plan-mode unit tests. The metadata discovery pattern is the intended way to use the AzureRM provider with custom environments.

This is a genuine difference between cloud providers. The methodology adapts to the provider, not the other way around.

The Modules

Five modules, matching the Azure services that floci-az supports.

Resource Group

The fundamental Azure grouping construct. Every Azure resource lives in a resource group. This module is the simplest but the most essential – nothing exists without it.

resource "azurerm_resource_group" "this" {
  name     = var.resource_group_name
  location = var.location
}

Blob Storage

Azure’s object storage, equivalent to AWS S3 and GCP Cloud Storage. The module creates a storage account and a blob container with a random suffix for global uniqueness.

Key Vault

Azure’s secrets management service, analogous to AWS Secrets Manager and GCP Secret Manager. Stores and versiones sensitive values with access policies.

Container Registry (ACR)

Azure’s container image registry, equivalent to AWS ECR and GCP Artifact Registry. The module creates a registry with admin-enabled access for local development.

Cosmos DB

Azure’s NoSQL database, analogous to DynamoDB and Firestore. The module creates a Cosmos DB account with SQL API and a single database.

The Pipeline

The Dagger pipeline mirrors the AWS and GCP versions exactly. Three validation stages plus an integration plan:

dagger call fmt-check
dagger call validate-modules
dagger call test-modules
dagger call integration-plan

The pipeline code is structure-identical. The only changes are the provider types in the module paths. The pipeline is not tied to any cloud. It is tied to the discipline of validating infrastructure before applying it.

The Trilogy Result

Across three clouds, three repositories, and fifteen OpenTofu modules, the methodology holds:

AspectAWSGCPAzure
Modules755
Plan-mode tests121010
Docker imagefloci/flocifloci/floci-gcpfloci/floci-az
Port456645884577
Pipeline stages444
All passingYesYesYes

The pattern is not AWS-specific. It is not GCP-specific. It is not Azure-specific. It is cloud-agnostic by design.

Why This Matters

The local cloud series started with a simple question: can we treat infrastructure with the same discipline we treat application code?

Thirteen chapters later, the answer is yes, across every major cloud provider. The same TDD pattern. The same pipeline structure. The same four pillars. The same Floci emulator family running on localhost.

The cloud is the variable. The methodology is the constant.


Repos: github.com/dark5un/local-cloud-az

Also on LinkedIn.

Here I geek out with my young Padawan, OrsonRius.