Tutorial Anterior: Estação de Trabalho como Código (Parte 12): Infraestrutura na AWS com Terraform
Introdução
O Microsoft Azure é o segundo maior provedor de nuvem do mercado, com forte presença em ambientes corporativos, especialmente entre empresas que usam tecnologias Microsoft. O Azure oferece integração profunda com ferramentas como Active Directory, Office 365 e SQL Server, além de serviços de IA e análise de dados de classe mundial.
Neste tutorial, vamos aprender a provisionar infraestrutura no Azure usando Terraform, cobrindo conceitos como Resource Groups, Virtual Networks, Virtual Machines, módulos reutilizáveis e como organizar seu código para múltiplos ambientes.
Observação: Esta parte foca em Terraform (recomendado). Se preferir usar Azure CLI manualmente, consulte a documentação oficial. No entanto, recomendamos Terraform para automação profissional.
Objetivos desta Parte
- Instalar e configurar o Azure CLI
- Criar um Service Principal para acesso via Terraform
- Configurar o provider Azure no Terraform
- Criar Resource Groups e redes virtuais
- Provisionar máquinas virtuais no Azure
- Configurar grupos de segurança de rede (NSGs)
- Organizar código em módulos reutilizáveis
- Usar variáveis para flexibilidade
Pré-requisitos
- Conclusão da Parte 12 desta série
- Conta Azure criada (pode usar free tier ou créditos)
- Terraform instalado (Parte 7)
- Azure CLI instalado (Parte 11)
A quem se destina
Este tutorial é ideal para:
- DevOps Engineers: Que precisam provisionar infraestrutura no Azure
- Arquitetos de Nuvem: Que querem usar IaC para Azure
- SysAdmins: Que querem expandir para a nuvem
- Profissionais de TI: Que querem implementar IaC em Azure
Pré-conhecimento: Conhecimento de Terraform, Azure e networking (coberto nas partes anteriores) é recomendado.
Tempo Estimado
⏱ 150-180 minutos
Isso inclui:
- Leitura e compreensão: ~25 min
- Configuração Azure CLI: ~15 min
- Criação de Service Principal: ~10 min
- Criação de estrutura Terraform: ~20 min
- Desenvolvimento de módulos: ~50 min
- Execução e testes: ~30 min
- Troubleshooting: ~15 min
Dica Útil: Use o free tier do Azure para experimentar sem custos. Você tem créditos de teste.
Entendendo Azure
Antes de começar, é importante entender os conceitos fundamentais.
O que é Azure?
Azure (Microsoft Azure) é uma plataforma de computação em nuvem que oferece mais de 200 serviços diferentes. Os principais são:
- Computação: Virtual Machines, App Service, Functions
- Armazenamento: Blob Storage, File Shares, Disk Storage
- Banco de Dados: SQL Database, Cosmos DB, PostgreSQL
- Rede: Virtual Networks, Load Balancer, Application Gateway
- Segurança: Azure AD, Key Vault, Security Center
Conceitos Principais
| Conceito | Descrição |
|---|
| Subscription | Contrato de faturamento com a Microsoft |
| Resource Group | Contêiner para recursos relacionados |
| Region | Localização geográfica com múltiplos datacenters |
| Availability Zone | Datacenter isolado dentro de uma região |
| VNet | Rede virtual isolada onde você executa recursos |
| Subnet | Segmento de rede dentro de uma VNet |
| VM | Máquina virtual no Azure |
| NSG | Firewall virtual para controlar tráfego |
| Service Principal | Identidade para automação e Terraform |
Verificando Pré-Requisitos
Antes de começar, certifique-se de que seu ambiente está pronto.
1
2
3
4
5
| # Verifique se Terraform está instalado
$ terraform --version
# Você deve ver:
# Terraform v1.14.5
|
Passo 2: Verificar Azure CLI
1
2
3
4
5
6
| # Verifique se Azure CLI está instalado
$ az --version
# Você deve ver:
# azure-cli 2.83.0
# core 2.83.0
|
Passo 3: Verificar Login no Azure
1
2
3
4
| # Verifique se está logado no Azure
$ az account show
# Você deve ver informações de sua conta
|
Configurando Azure CLI
Passo 1: Instalar Azure CLI
1
2
3
4
5
| # Instale Azure CLI
$ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Verifique
$ az --version
|
Passo 2: Fazer Login
1
2
3
4
5
| # Faça login no Azure
$ az login --use-device-code
# Você será solicitado a abrir um link e digitar um código
# Siga as instruções na tela
|
Passo 3: Verificar Conta
1
2
3
4
5
6
7
8
9
10
| # Verifique sua conta
$ az account show
# Você deve ver:
# {
# "id": "0273e9e7-269c-4199-a62c-4f84da6e12e4",
# "name": "Azure subscription 1",
# "tenantId": "813ccd62-e6a9-4405-9a4d-dd7fad0d386a",
# ...
# }
|
Criando Service Principal
Passo 1: Obter Subscription ID
1
2
3
4
5
| # Obtenha o Subscription ID
$ az account show --query id -o tsv
# Você verá:
# 0273e9e7-269c-4199-a62c-4f84da6e12e4
|
Passo 2: Criar Service Principal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Crie um Service Principal
$ az ad sp create-for-rbac \
--role="Contributor" \
--scopes="/subscriptions/$(az account show --query id -o tsv)"
# Você verá:
# {
# "appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
# "displayName": "azure-cli-2026-02-19-12-34-56",
# "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
# "tenant": "813ccd62-e6a9-4405-9a4d-dd7fad0d386a"
# }
# Salve essas informações em um local seguro
|
Passo 3: Configurar Variáveis de Ambiente
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Configure variáveis de ambiente para Terraform
$ export ARM_CLIENT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$ export ARM_CLIENT_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$ export ARM_SUBSCRIPTION_ID="0273e9e7-269c-4199-a62c-4f84da6e12e4"
$ export ARM_TENANT_ID="813ccd62-e6a9-4405-9a4d-dd7fad0d386a"
# Ou adicione ao ~/.bashrc para persistência
$ cat >> ~/.bashrc << 'EOF'
export ARM_CLIENT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export ARM_CLIENT_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export ARM_SUBSCRIPTION_ID="0273e9e7-269c-4199-a62c-4f84da6e12e4"
export ARM_TENANT_ID="813ccd62-e6a9-4405-9a4d-dd7fad0d386a"
EOF
# Recarregue
$ source ~/.bashrc
|
Passo 1: Criar Diretórios
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # Crie a estrutura de diretórios
$ mkdir -p ~/workspace-as-code/terraform/providers/azure/{modules,environments}
$ cd ~/workspace-as-code/terraform/providers/azure
# Estrutura esperada:
# azure/
# ├── modules/
# │ ├── resource_group/
# │ │ ├── main.tf
# │ │ ├── variables.tf
# │ │ └── outputs.tf
# │ ├── network/
# │ │ ├── main.tf
# │ │ ├── variables.tf
# │ │ └── outputs.tf
# │ └── vm/
# │ ├── main.tf
# │ ├── variables.tf
# │ └── outputs.tf
# ├── environments/
# │ ├── dev/
# │ │ ├── main.tf
# │ │ ├── terraform.tfvars
# │ │ └── backend.tf
# │ ├── staging/
# │ └── prod/
# ├── main.tf
# ├── variables.tf
# ├── outputs.tf
# └── provider.tf
|
Passo 2: Criar Arquivo de Provider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| # Crie arquivo provider.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/provider.tf << 'EOF'
terraform {
required_version = "~> 1.14.5"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {
virtual_machine {
delete_os_disk_on_deletion = true
graceful_shutdown = false
skip_shutdown_and_force_delete = false
}
}
skip_provider_registration = false
}
EOF
# Verifique
$ cat ~/workspace-as-code/terraform/providers/azure/provider.tf
|
Passo 3: Criar Variáveis Principais
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| # Crie arquivo variables.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/variables.tf << 'EOF'
variable "azure_region" {
description = "Azure region"
type = string
default = "canadacentral"
}
variable "project_name" {
description = "Project name"
type = string
default = "workspace-as-code"
}
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
default = "dev"
}
variable "vnet_cidr" {
description = "CIDR block for Virtual Network"
type = string
default = "10.0.0.0/16"
}
variable "subnet_cidr" {
description = "CIDR block for subnet"
type = string
default = "10.0.1.0/24"
}
variable "vm_size" {
description = "Azure VM size"
type = string
default = "Standard_B1s"
}
variable "enable_public_ip" {
description = "Enable public IP for VM"
type = bool
default = true
}
EOF
# Verifique
$ cat ~/workspace-as-code/terraform/providers/azure/variables.tf
|
Módulo 1: Resource Group
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| # Crie diretório do módulo
$ mkdir -p ~/workspace-as-code/terraform/providers/azure/modules/resource_group
# Crie arquivo main.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/resource_group/main.tf << 'EOF'
resource "azurerm_resource_group" "main" {
name = "${var.project_name}-${var.environment}-rg"
location = var.azure_region
tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "Terraform"
}
}
EOF
# Crie arquivo variables.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/resource_group/variables.tf << 'EOF'
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "azure_region" {
description = "Azure region"
type = string
}
EOF
# Crie arquivo outputs.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/resource_group/outputs.tf << 'EOF'
output "resource_group_id" {
description = "Resource Group ID"
value = azurerm_resource_group.main.id
}
output "resource_group_name" {
description = "Resource Group name"
value = azurerm_resource_group.main.name
}
EOF
|
Módulo 2: Network (VNet + Subnet + NSG)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
| # Crie diretório do módulo
$ mkdir -p ~/workspace-as-code/terraform/providers/azure/modules/network
# Crie arquivo main.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/network/main.tf << 'EOF'
# Virtual Network
resource "azurerm_virtual_network" "main" {
name = "${var.project_name}-${var.environment}-vnet"
address_space = [var.vnet_cidr]
location = var.azure_region
resource_group_name = var.resource_group_name
tags = {
Name = "${var.project_name}-vnet"
}
}
# Subnet
resource "azurerm_subnet" "main" {
name = "${var.project_name}-${var.environment}-subnet"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [var.subnet_cidr]
}
# Network Security Group
resource "azurerm_network_security_group" "main" {
name = "${var.project_name}-${var.environment}-nsg"
location = var.azure_region
resource_group_name = var.resource_group_name
# SSH Ingress
security_rule {
name = "AllowSSH"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
# HTTP Ingress
security_rule {
name = "AllowHTTP"
priority = 200
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
# HTTPS Ingress
security_rule {
name = "AllowHTTPS"
priority = 300
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags = {
Name = "${var.project_name}-nsg"
}
}
# Associate NSG with Subnet
resource "azurerm_subnet_network_security_group_association" "main" {
subnet_id = azurerm_subnet.main.id
network_security_group_id = azurerm_network_security_group.main.id
}
# Public IP
resource "azurerm_public_ip" "main" {
name = "${var.project_name}-${var.environment}-pip"
location = var.azure_region
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
tags = {
Name = "${var.project_name}-pip"
}
}
# Network Interface
resource "azurerm_network_interface" "main" {
name = "${var.project_name}-${var.environment}-nic"
location = var.azure_region
resource_group_name = var.resource_group_name
ip_configuration {
name = "testconfiguration1"
subnet_id = azurerm_subnet.main.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.main.id
}
tags = {
Name = "${var.project_name}-nic"
}
}
EOF
# Crie arquivo variables.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/network/variables.tf << 'EOF'
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "azure_region" {
description = "Azure region"
type = string
}
variable "resource_group_name" {
description = "Resource Group name"
type = string
}
variable "vnet_cidr" {
description = "CIDR block for Virtual Network"
type = string
}
variable "subnet_cidr" {
description = "CIDR block for subnet"
type = string
}
EOF
# Crie arquivo outputs.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/network/outputs.tf << 'EOF'
output "vnet_id" {
description = "Virtual Network ID"
value = azurerm_virtual_network.main.id
}
output "subnet_id" {
description = "Subnet ID"
value = azurerm_subnet.main.id
}
output "nsg_id" {
description = "Network Security Group ID"
value = azurerm_network_security_group.main.id
}
output "nic_id" {
description = "Network Interface ID"
value = azurerm_network_interface.main.id
}
output "public_ip" {
description = "Public IP address"
value = azurerm_public_ip.main.ip_address
}
EOF
|
Módulo 3: Virtual Machine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| # Crie diretório do módulo
$ mkdir -p ~/workspace-as-code/terraform/providers/azure/modules/vm
# Crie arquivo main.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/vm/main.tf << 'EOF'
# Generate SSH key if not exists
resource "tls_private_key" "main" {
algorithm = "Ed25519"
}
# Virtual Machine
resource "azurerm_linux_virtual_machine" "main" {
name = "${var.project_name}-${var.environment}-vm"
location = var.azure_region
resource_group_name = var.resource_group_name
size = var.vm_size
admin_username = "azureuser"
admin_ssh_key {
username = "azureuser"
public_key = tls_private_key.main.public_key_openssh
}
network_interface_ids = [
var.network_interface_id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Debian"
offer = "debian-12"
sku = "12"
version = "latest"
}
tags = {
Name = "${var.project_name}-vm"
}
}
# Save private key locally
resource "local_file" "private_key" {
content = tls_private_key.main.private_key_openssh
filename = "${path.module}/../../${var.project_name}-${var.environment}-key.pem"
file_permission = "0600"
}
EOF
# Crie arquivo variables.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/vm/variables.tf << 'EOF'
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "azure_region" {
description = "Azure region"
type = string
}
variable "resource_group_name" {
description = "Resource Group name"
type = string
}
variable "vm_size" {
description = "Azure VM size"
type = string
default = "Standard_B1s"
}
variable "network_interface_id" {
description = "Network Interface ID"
type = string
}
EOF
# Crie arquivo outputs.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/modules/vm/outputs.tf << 'EOF'
output "vm_id" {
description = "Virtual Machine ID"
value = azurerm_linux_virtual_machine.main.id
}
output "private_key_path" {
description = "Path to private key file"
value = local_file.private_key.filename
}
EOF
|
Criando Configuração Principal
Passo 1: Arquivo Main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| # Crie arquivo main.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/main.tf << 'EOF'
# Módulo Resource Group
module "resource_group" {
source = "./modules/resource_group"
project_name = var.project_name
environment = var.environment
azure_region = var.azure_region
}
# Módulo Network
module "network" {
source = "./modules/network"
project_name = var.project_name
environment = var.environment
azure_region = var.azure_region
resource_group_name = module.resource_group.resource_group_name
vnet_cidr = var.vnet_cidr
subnet_cidr = var.subnet_cidr
}
# Módulo VM
module "vm" {
source = "./modules/vm"
project_name = var.project_name
environment = var.environment
azure_region = var.azure_region
resource_group_name = module.resource_group.resource_group_name
vm_size = var.vm_size
network_interface_id = module.network.nic_id
}
EOF
# Verifique
$ cat ~/workspace-as-code/terraform/providers/azure/main.tf
|
Passo 2: Arquivo Outputs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| # Crie arquivo outputs.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/outputs.tf << 'EOF'
output "resource_group_id" {
description = "Resource Group ID"
value = module.resource_group.resource_group_id
}
output "resource_group_name" {
description = "Resource Group name"
value = module.resource_group.resource_group_name
}
output "vnet_id" {
description = "Virtual Network ID"
value = module.network.vnet_id
}
output "subnet_id" {
description = "Subnet ID"
value = module.network.subnet_id
}
output "nsg_id" {
description = "Network Security Group ID"
value = module.network.nsg_id
}
output "vm_id" {
description = "Virtual Machine ID"
value = module.vm.vm_id
}
output "vm_public_ip" {
description = "VM Public IP"
value = module.network.public_ip
}
output "private_key_path" {
description = "Path to private key file"
value = module.vm.private_key_path
}
EOF
# Verifique
$ cat ~/workspace-as-code/terraform/providers/azure/outputs.tf
|
Criando Ambientes
Passo 1: Ambiente Dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| # Crie diretório do ambiente
$ mkdir -p ~/workspace-as-code/terraform/providers/azure/environments/dev
# Crie arquivo terraform.tfvars
$ cat > ~/workspace-as-code/terraform/providers/azure/environments/dev/terraform.tfvars << 'EOF'
azure_region = "canadacentral"
project_name = "workspace-as-code"
environment = "dev"
vnet_cidr = "10.0.0.0/16"
subnet_cidr = "10.0.1.0/24"
vm_size = "Standard_B1s"
EOF
# Crie arquivo main.tf (referencia módulos)
$ cat > ~/workspace-as-code/terraform/providers/azure/environments/dev/main.tf << 'EOF'
terraform {
required_version = "~> 1.14.5"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
module "azure_infrastructure" {
source = "../../"
azure_region = var.azure_region
project_name = var.project_name
environment = var.environment
vnet_cidr = var.vnet_cidr
subnet_cidr = var.subnet_cidr
vm_size = var.vm_size
}
EOF
# Crie arquivo variables.tf
$ cat > ~/workspace-as-code/terraform/providers/azure/environments/dev/variables.tf << 'EOF'
variable "azure_region" {
type = string
}
variable "project_name" {
type = string
}
variable "environment" {
type = string
}
variable "vnet_cidr" {
type = string
}
variable "subnet_cidr" {
type = string
}
variable "vm_size" {
type = string
}
EOF
|
1
2
3
4
5
6
7
8
| # Navegue para o diretório
$ cd ~/workspace-as-code/terraform/providers/azure
# Inicialize Terraform
$ terraform init
# Você deve ver:
# Terraform has been successfully configured!
|
Passo 2: Validar Configuração
1
2
3
4
5
| # Valide a sintaxe
$ terraform validate
# Você deve ver:
# Success! The configuration is valid.
|
1
2
3
4
| # Formate o código
$ terraform fmt -recursive
# Isso vai formatar todos os arquivos .tf
|
Passo 4: Planejar Execução
1
2
3
4
| # Crie um plano
$ terraform plan -out=tfplan
# Você verá as mudanças que serão feitas
|
Passo 5: Aplicar Configuração
1
2
3
4
5
| # Aplique o plano
$ terraform apply tfplan
# Você verá:
# Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
|
Passo 6: Verificar Saída
1
2
3
4
5
6
7
| # Veja os outputs
$ terraform output
# Você verá:
# vm_public_ip = "20.48.230.96"
# private_key_path = "..."
# ...
|
Acessando a Instância Azure
Passo 1: Obter IP Público
1
2
3
4
5
| # Obtenha o IP público
$ terraform output vm_public_ip
# Você verá:
# "20.48.230.96"
|
Passo 2: Obter Caminho da Chave Privada
1
2
3
4
5
| # Obtenha o caminho da chave privada
$ terraform output private_key_path
# Você verá:
# "~/workspace-as-code/terraform/providers/azure/workspace-as-code-dev-key.pem"
|
Passo 3: Conectar via SSH
1
2
3
4
5
6
7
8
9
10
| # Conecte à instância
$ ssh -i $(terraform output -raw private_key_path) azureuser@$(terraform output -raw vm_public_ip)
# Você deve ver:
# The authenticity of host '20.48.230.96 (20.48.230.96)' can't be established.
# Are you sure you want to continue connecting (yes/no)?
# Digite: yes
# Você deve estar conectado à instância
|
Passo 4: Verificar Instância
1
2
3
4
| # Verifique informações da instância
$ uname -a
$ cat /etc/os-release
$ df -h
|
| Módulo | Descrição | Recursos |
|---|
| resource_group | Cria Resource Group | Resource Group |
| network | Cria rede e segurança | VNet, Subnet, NSG, NIC, Public IP |
| vm | Cria máquina virtual | Linux VM, SSH Key |
Troubleshooting
Erro: “The client does not have authorization”
Problema: Service Principal sem permissões ou credenciais inválidas.
Solução:
1
2
3
4
5
6
| # Verifique variáveis de ambiente
$ echo $ARM_CLIENT_ID
$ echo $ARM_SUBSCRIPTION_ID
# Ou recrie Service Principal
$ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/$(az account show --query id -o tsv)"
|
Erro: “ResourceGroupNotFound”
Problema: Resource Group não existe.
Solução:
1
2
3
4
5
| # Verifique Resource Groups
$ az group list --query "[].name" -o table
# Ou recrie com terraform apply
$ terraform apply
|
Erro: “VirtualNetworkNotFound”
Problema: Virtual Network não existe.
Solução:
1
2
3
4
5
| # Verifique VNets
$ az network vnet list --query "[].name" -o table
# Ou recrie com terraform apply
$ terraform apply
|
Erro: “InvalidImageReference”
Problema: Imagem Debian não encontrada.
Solução:
1
2
3
4
5
| # Verifique imagens disponíveis
$ az vm image list --publisher Debian --offer debian-12 -o table
# Ou use outra imagem
# Edite modules/vm/main.tf com nova imagem
|
Instância não responde a SSH
Problema: NSG bloqueia SSH.
Solução:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Verifique regras NSG
$ az network nsg rule list --resource-group <rg> --nsg-name <nsg>
# Ou adicione regra manualmente
$ az network nsg rule create \
--resource-group <rg> \
--nsg-name <nsg> \
--name AllowSSH \
--priority 100 \
--source-address-prefixes '*' \
--source-port-ranges '*' \
--destination-address-prefixes '*' \
--destination-port-ranges 22 \
--access Allow \
--protocol Tcp
|
Dicas e Boas Práticas
Dica 1: Use Variáveis para Flexibilidade
1
2
3
4
5
6
7
8
9
| # Bom
variable "vm_size" {
default = "Standard_B1s"
}
# Ruim
resource "azurerm_linux_virtual_machine" "main" {
size = "Standard_B1s"
}
|
Dica 2: Organize em Módulos
1
2
3
4
| modules/
├── resource_group/
├── network/
└── vm/
|
Dica 3: Use Outputs para Referências
1
2
3
| output "vm_public_ip" {
value = module.network.public_ip
}
|
Dica 4: Versione Tudo
1
2
3
| $ git add .
$ git commit -m "feat: add Azure infrastructure"
$ git push origin main
|
Dica 5: Use Workspaces para Ambientes
1
2
3
| $ terraform workspace new dev
$ terraform workspace new staging
$ terraform workspace new prod
|
Passo 1: Organizar Estrutura
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Verifique a estrutura
$ tree ~/workspace-as-code/terraform/providers/azure/
# Você deve ver:
# azure/
# ├── modules/
# │ ├── resource_group/
# │ ├── network/
# │ └── vm/
# ├── environments/
# │ └── dev/
# ├── main.tf
# ├── variables.tf
# ├── outputs.tf
# └── provider.tf
|
Passo 2: Versionar no Git
1
2
3
4
5
6
7
8
| # Adicione ao Git
$ cd ~/workspace-as-code
$ git add terraform/providers/azure/
$ git commit -m "feat: add Azure infrastructure with Terraform"
$ git push origin main
# Verifique
$ git log --oneline | head -5
|
Script de Validação
Para verificar se tudo foi configurado corretamente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| #!/bin/bash
# Script de validação de Azure Terraform
echo "Validando Azure Terraform..."
# Verificar Azure CLI
if command -v az &> /dev/null; then
echo "✓ Azure CLI instalado"
else
echo "✗ Azure CLI não instalado"
exit 1
fi
# Verificar login
if az account show &> /dev/null; then
echo "✓ Login Azure OK"
else
echo "✗ Não está logado no Azure"
exit 1
fi
# Verificar Terraform
if command -v terraform &> /dev/null; then
echo "✓ Terraform instalado"
else
echo "✗ Terraform não instalado"
exit 1
fi
# Verificar estrutura
if [ -d "terraform/providers/azure/modules" ]; then
echo "✓ Módulos existem"
else
echo "✗ Módulos não existem"
exit 1
fi
# Validar Terraform
cd terraform/providers/azure
if terraform validate &> /dev/null; then
echo "✓ Terraform válido"
else
echo "✗ Terraform inválido"
exit 1
fi
echo ""
echo "Validação concluída com sucesso!"
|
Conclusão
Você aprendeu a provisionar infraestrutura no Azure usando Terraform. Com Terraform, você pode definir infraestrutura como código, versioná-la no Git e reutilizá-la em múltiplos ambientes.
O Que Você Alcançou
✓ Instalação e configuração do Azure CLI ✓ Criação de Service Principal ✓ Configuração do provider Azure no Terraform ✓ Criação de Resource Groups ✓ Criação de redes virtuais ✓ Provisão de máquinas virtuais ✓ Configuração de segurança (NSG) ✓ Organização em módulos reutilizáveis ✓ Uso de variáveis para flexibilidade
- Configure Azure CLI:
1
| $ az login --use-device-code
|
- Crie Service Principal:
1
| $ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/$(az account show --query id -o tsv)"
|
- Configure variáveis de ambiente:
1
2
3
4
| $ export ARM_CLIENT_ID="..."
$ export ARM_CLIENT_SECRET="..."
$ export ARM_SUBSCRIPTION_ID="..."
$ export ARM_TENANT_ID="..."
|
- Crie estrutura Terraform:
1
| $ mkdir -p ~/workspace-as-code/terraform/providers/azure/{modules,environments}
|
- Crie módulos:
1
| $ mkdir -p ~/workspace-as-code/terraform/providers/azure/modules/{resource_group,network,vm}
|
Copie arquivos dos exemplos acima
- Inicialize Terraform:
1
2
| $ cd ~/workspace-as-code/terraform/providers/azure
$ terraform init
|
- Valide e aplique:
1
2
3
| $ terraform validate
$ terraform plan
$ terraform apply
|
- Versione no Git:
1
2
3
| $ git add terraform/
$ git commit -m "feat: add Azure infrastructure"
$ git push origin main
|
Próximo Tutorial
Com infraestrutura no Azure configurada, o próximo passo é aprender a usar GCP com Terraform.
Recursos Adicionais
Fim da Parte 13
Próxima: Infraestrutura no GCP com Terraform