CloudExpert UP

Criar VM Windows com Terraform

Azure Virtual Machine Avançado 30 min Gratuito

📋 Visão Geral

Neste workshop você aprenderá a provisionar uma máquina virtual Windows Server completa usando Terraform — a ferramenta de Infrastructure as Code (IaC) mais popular do mercado.

Você irá criar toda a infraestrutura declarativamente:

  • Resource Group
  • Virtual Network (VNet) com Subnet
  • Network Security Group (NSG) com regras para RDP e HTTP
  • Public IP Address
  • Network Interface (NIC)
  • Storage Account para Boot Diagnostics
  • Windows VM com extensão IIS
💡 Dica: Terraform permite versionar, revisar e reproduzir infraestrutura. É uma skill essencial para certificações como AZ-104 e AZ-400.

✅ Pré-requisitos

Antes de começar, certifique-se de ter:

  • Uma subscrição Azure ativa
  • Terraform instalado (download) — versão 1.0+
  • Azure CLI instalado e autenticado
  • Um editor de código (VS Code recomendado com extensão Terraform)
⚠️ Importante: Este workshop pode gerar custos na sua subscrição Azure. Lembre-se de executar terraform destroy ao final.

🚀 Configuração do Ambiente

Prepare o ambiente e crie a estrutura do projeto Terraform:

1. Autenticar no Azure

az login

2. Criar diretório do projeto

mkdir terraform-vm-lab
cd terraform-vm-lab

3. Criar arquivo providers.tf

Este arquivo define os providers necessários (azurerm e random):

terraform {
  required_version = ">=1.0"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~>3.0"
    }
  }
}

provider "azurerm" {
  features {}
}

⚙️ Implementação

Crie os arquivos Terraform para toda a infraestrutura:

Passo 1: Criar variables.tf

variable "resource_group_location" {
  type        = string
  default     = "eastus"
  description = "Location of the resource group."
}

variable "resource_group_name_prefix" {
  type        = string
  default     = "rg"
  description = "Prefix for the resource group name."
}

variable "admin_username" {
  type        = string
  default     = "azureuser"
  description = "The admin username for the VM."
}

variable "admin_password" {
  type        = string
  sensitive   = true
  description = "The admin password for the VM."
}

Passo 2: Criar main.tf — Infraestrutura Completa

Este é o arquivo principal com todos os recursos:

# Resource Group
resource "random_pet" "rg_name" {
  prefix = var.resource_group_name_prefix
}

resource "azurerm_resource_group" "rg" {
  location = var.resource_group_location
  name     = random_pet.rg_name.id
}

# Virtual Network
resource "azurerm_virtual_network" "my_vnet" {
  name                = "myVnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

# Subnet
resource "azurerm_subnet" "my_subnet" {
  name                 = "mySubnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.my_vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}

# Public IP
resource "azurerm_public_ip" "my_public_ip" {
  name                = "myPublicIP"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method   = "Dynamic"
}

# Network Security Group
resource "azurerm_network_security_group" "my_nsg" {
  name                = "myNSG"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  security_rule {
    name                       = "RDP"
    priority                   = 1000
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "3389"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  security_rule {
    name                       = "web"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "80"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

# Network Interface
resource "azurerm_network_interface" "my_nic" {
  name                = "myNIC"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "my_nic_configuration"
    subnet_id                     = azurerm_subnet.my_subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.my_public_ip.id
  }
}

# Connect NSG to NIC
resource "azurerm_network_interface_security_group_association" "example" {
  network_interface_id      = azurerm_network_interface.my_nic.id
  network_security_group_id = azurerm_network_security_group.my_nsg.id
}

# Storage Account for Boot Diagnostics
resource "random_id" "random_id" {
  keepers = {
    resource_group = azurerm_resource_group.rg.name
  }
  byte_length = 8
}

resource "azurerm_storage_account" "my_storage" {
  name                     = "diag${random_id.random_id.hex}"
  location                 = azurerm_resource_group.rg.location
  resource_group_name      = azurerm_resource_group.rg.name
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

# Windows Virtual Machine
resource "azurerm_windows_virtual_machine" "main" {
  name                  = "myVM"
  admin_username        = var.admin_username
  admin_password        = var.admin_password
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.my_nic.id]
  size                  = "Standard_DS1_v2"

  os_disk {
    name                 = "myOsDisk"
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2022-datacenter-azure-edition"
    version   = "latest"
  }

  boot_diagnostics {
    storage_account_uri = azurerm_storage_account.my_storage.primary_blob_endpoint
  }
}

# Install IIS via VM Extension
resource "azurerm_virtual_machine_extension" "web_server_install" {
  name                       = "wsi"
  virtual_machine_id         = azurerm_windows_virtual_machine.main.id
  publisher                  = "Microsoft.Compute"
  type                       = "CustomScriptExtension"
  type_handler_version       = "1.8"
  auto_upgrade_minor_version = true

  settings = <<SETTINGS
    {
      "commandToExecute": "powershell -ExecutionPolicy Unrestricted Install-WindowsFeature -name Web-Server -IncludeManagementTools;"
    }
  SETTINGS
}
📝 Nota: O arquivo main.tf cria 10 recursos Azure interconectados: Resource Group, VNet, Subnet, Public IP, NSG (com regras RDP + HTTP), NIC, associação NSG-NIC, Storage Account, VM e extensão IIS.

Passo 3: Criar outputs.tf

output "resource_group_name" {
  value = azurerm_resource_group.rg.name
}

output "public_ip_address" {
  value = azurerm_windows_virtual_machine.main.public_ip_address
}

Passo 4: Inicializar e Executar Terraform

# Inicializar o Terraform (baixar providers)
terraform init -upgrade

# Criar o plano de execução
terraform plan -out main.tfplan

# Aplicar o plano (criar os recursos)
terraform apply main.tfplan
📝 Nota: Você será solicitado a fornecer a admin_password durante o plan/apply. O deployment completo leva de 5 a 10 minutos.

✅ Validação

Verifique se toda a infraestrutura foi provisionada corretamente:

1. Verificar outputs do Terraform

# Ver o nome do resource group criado
terraform output resource_group_name

# Ver o IP público da VM
terraform output public_ip_address

2. Verificar recursos no Azure

# Listar recursos no resource group
az resource list \
  --resource-group $(terraform output -raw resource_group_name) \
  --output table

3. Testar o IIS no navegador

Acesse o IP público retornado pelo output:

http://<PUBLIC_IP_ADDRESS>
🎉 Parabéns! Se a página do IIS aparecer, você provisionou toda uma infraestrutura Azure como código usando Terraform — VNet, Subnet, NSG, NIC, Storage, VM e IIS!

🧹 Limpeza

Use o Terraform para destruir todos os recursos de forma limpa:

# Criar plano de destruição
terraform plan -destroy -out main.destroy.tfplan

# Executar a destruição
terraform apply main.destroy.tfplan
⚠️ Atenção: O terraform destroy removerá todos os 10 recursos criados (Resource Group, VNet, Subnet, IP, NSG, NIC, Storage, VM, extensão). A operação é irreversível.