Yes, but not by writing Terraform code once and deploying it anywhere.

Because Terraform resource definitions (like azurerm_linux_virtual_machine) map directly to Azure-specific APIs, Terraform itself doesn’t abstract away the cloud provider. However, you can use Terraform architecturally to minimize your dependency on Azure.

The core strategy is to use Terraform to provision cloud-agnostic runtime layers and open-source managed services, pushing your business logic away from proprietary Azure products.


Key Strategies to Reduce Azure Lock-In

1. Avoid Proprietary Azure PaaS Services

The fastest way to get locked into Azure is using proprietary services that have unique APIs, SDKs, and data structures. Use open-source or standardized alternatives managed via Terraform instead:

Azure-Native Service (High Lock-In)Cloud-Agnostic EquivalentPortable Deployment Method
Azure App ServiceDocker Containers / KubernetesTerraform provisions AKS/EKS; Helm handles the app.
Azure FunctionsOpenFaaS / Knative / DockerDeploy serverless runtimes inside containers.
Azure SQL / Cosmos DBPostgreSQL / MongoDBUse managed Postgres/Mongo on each cloud, or run via operator.
Azure Service BusApache Kafka / RabbitMQStandardized messaging APIs across providers.
Azure Key VaultHashiCorp VaultSame Vault API and Terraform provider everywhere.

2. Adopt a “Kubernetes-First” Infrastructure Strategy

Instead of defining individual Azure VMs, load balancers, and scaling groups in Terraform, treat Azure merely as a “dumb hypervisor” to host Kubernetes:

  1. Terraform layer: Provisions basic networking and Azure Kubernetes Service (AKS) — or generic VMs running K3s/Talos Linux.
  2. Kubernetes layer: Deploys your actual workloads, databases, network routing (Ingress), and security using Helm or the Terraform kubernetes / helm providers.

The Benefit: If you move to AWS (EKS), GCP (GKE), or On-Premises, your Terraform layer for provisioning the cluster changes, but 100% of your application manifests and Helm releases remain unchanged.

3. Standardize OS Provisioning with Cloud-Init & Ansible

Keep virtual machine configurations out of Terraform entirely:

4. Abstract Your Terraform Code into Multi-Cloud Modules

Organize your repository so that your core application configuration is decoupled from the underlying cloud provider:

infrastructure/
├── modules/
│   └── web_application/       # Universal Helm values, config files, app logic
├── environments/
│   ├── azure/                 # Installs app on AKS / Azure VMs
│   ├── aws/                   # Installs app on EKS / AWS EC2
│   └── proxmox/               # Installs app on Proxmox VMs

By keeping environment variables, domain rules, and application setups inside shared module inputs, switching clouds becomes a matter of applying a different environment directory.


The Trade-off to Consider

Reducing dependency on Azure requires accepting a trade-off: you lose access to Azure’s deepest native integrations and convenience features.