Martin Rylko
  • Services
  • Blog
  • About
  • Contact
  • Get in Touch
Martin Rylko

Senior Cloud Architect & DevOps Engineer. Specializing in Microsoft Azure, IaC, Cloud Security and AI.

Navigation

  • Services
  • Blog
  • About
  • Contact

Collaboration

Looking for an experienced architect for your Azure project? Get in touch.

rylko@cloudmasters.cz

© 2026 Martin Rylko. All rights reserved.

Built in the cloud. Deployed via Azure Static Web Apps.

Home/Blog/5 Terraform Best Practices for Production Azure Projects
All articlesČíst česky

5 Terraform Best Practices for Production Azure Projects

2/10/2026 2 min
#Terraform#Azure#IaC#DevOps

5 Terraform Best Practices for Production Azure Projects

After three years of intensive work with Terraform in enterprise environments (from H&M Group to smaller FinTech companies), I've identified five key principles that separate amateur IaC code from production-hardened infrastructure.

1. Remote State with Locking – No Exceptions

Never, I mean never, use a local terraform.tfstate in a team setting. An Azure Storage Account with a blob container and state locking is the foundation:

terraform {
  backend "azurerm" {
    resource_group_name  = "rg-terraform-state"
    storage_account_name = "stterraformstprod"
    container_name       = "tfstate"
    key                  = "landing-zone/prod.tfstate"
    use_oidc             = true
  }
}

Why use_oidc = true? Because Managed Identity + OIDC federation eliminates the need to store service principal secrets in pipeline variables. More secure, simpler.

2. Modularization from Day One

The biggest mistake I see at client sites: a massive monolithic main.tf with 2,000+ lines. The solution? Terraform modules:

infrastructure/
├── modules/
│   ├── networking/          # VNet, NSG, Route Tables
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   ├── compute/             # VM, VMSS, AKS
│   ├── security/            # Key Vault, Defender
│   └── monitoring/          # Log Analytics, Alerts
├── environments/
│   ├── dev/
│   │   └── main.tf          # Calls modules with dev parameters
│   ├── staging/
│   └── prod/
└── shared/
    └── backend.tf

Each module has a clear responsibility. A change in the networking module doesn't affect compute. You test in isolation, deploy safely.

3. Drift Detection in CI/CD Pipeline

Infrastructure changes over time – someone clicks in the portal, someone runs a script. Drift is the silent killer of IaC consistency. The solution:

# Azure DevOps pipeline - nightly drift check
schedules:
  - cron: "0 3 * * *"
    displayName: "Nightly drift detection"
 
steps:
  - task: TerraformCLI@2
    inputs:
      command: 'plan'
      workingDirectory: 'infrastructure/environments/prod'
      commandOptions: '-detailed-exitcode'
    continueOnError: true
 
  - script: |
      if [ $TERRAFORM_EXITCODE -eq 2 ]; then
        echo "##vso[task.logissue type=warning]DRIFT DETECTED!"
        # Send notification to Teams/Slack
      fi
    displayName: 'Evaluate drift'

4. Resource Naming via a Naming Convention Module

Consistent naming is the SEO of infrastructure – without it, you'll get lost:

module "naming" {
  source = "Azure/naming/azurerm"
  suffix = [var.environment, var.location_short]
}
 
resource "azurerm_resource_group" "main" {
  name     = module.naming.resource_group.name
  location = var.location
}
 
resource "azurerm_virtual_network" "hub" {
  name                = module.naming.virtual_network.name
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  address_space       = ["10.0.0.0/16"]
}

5. Infrastructure Testing – Terratest or terraform validate

Yes, infrastructure needs to be tested. At a minimum:

  • terraform validate – syntax check
  • terraform plan in a PR pipeline – review changes before merge
  • tflint – static analysis for best practices
  • Terratest (Go) – integration tests for critical modules

Conclusion

Terraform is a powerful tool, but without discipline it becomes a nightmare. Start with remote state and modularization, add drift detection and naming conventions. Your future self will thank you.

Interested in how to set up a complete Terraform CI/CD pipeline in Azure DevOps? I'm preparing a detailed guide on that topic.

Tags:#Terraform#Azure#IaC#DevOps
LinkedInX / Twitter

About the author

Martin Rylko

Martin Rylko

Senior Cloud Architect & DevOps Engineer

14+ years in IT – from on-premises datacenters and Hyper-V clustering to cloud infrastructure on Microsoft Azure. I specialize in Landing Zones, IaC automation, Kubernetes and security compliance.

Email LinkedInFull profile

You might also like

Building an Azure Landing Zone with Bicep

A practical guide on how to effectively structure your Bicep code for deploying an enterprise-ready Azure Landing Zone (ALZ).

Read

AKS for Production: A Checklist for Cloud Architects

What you need to address before deploying Azure Kubernetes Service to production – from networking through RBAC and scaling to monitoring and backup.

Read

NIS2 and Azure: A Practical Compliance Checklist for Architects

How to prepare your Azure environment for the NIS2 directive – concrete steps from Azure Policy through Defender for Cloud to logging and incident response.

Read