Post

Crie VMs Linux no Azure em Minutos com Terraform

Fala galera!👋

Bem-vindo ao blog Cloud Insights! ☁️

Neste post, vamos explorar como automatizar a implantação de uma máquina virtual no Azure utilizando Terraform. A abordagem Infrastructure as Code (IaC) permite criar e gerenciar infraestrutura de forma repetível, eficiente e sem a necessidade de configurações manuais.

Embora esse processo funcione para diferentes distribuições Linux, neste guia utilizaremos o Ubuntu Server 24.04 como exemplo. A automação desse processo oferece vários benefícios:

  • Consistência: Elimina erros manuais ao criar recursos no Azure.
  • Eficiência: Reduz o tempo de configuração e implantação.
  • Versionamento: Permite rastrear e controlar alterações no ambiente de infraestrutura.

Ao longo deste artigo, vamos configurar o Terraform, definir os recursos no Azure e provisionar a VM automaticamente. Pronto para tornar suas implementações mais rápidas e seguras? Vamos lá!

Pré-Requisitos

Antes de começarmos nosso laboratório, verifique se você possui:

  • Uma conta do Azure com uma assinatura ativa.

Caso você não tenha uma subscription, você pode criar uma Trial. Mais informações consulte aqui.

  • Um Service Principal (um tipo de identidade no Azure usada para autenticação) com permissionamento adequado.

Obs.: Aqui estou utilizando um Service Principal com permissão de “Global Administrator” no Entra ID e com a permissao de Contributor na minha assinatura. Para saber como adicionar permissões elevadas em uma conta, consulte aqui.

  • Ter o VSCode Instalado em seu Sistema Operacional Windows com as extensões Azure Terraform, Hashicorp Terraform e PowerShell.

Caso não tenha o VSCode Instalado, faça o Download do instalador aqui.

  • Ter o Terraform instalado no seu computador.

Caso não tenha o Terraform instalado, siga este procedimento.

1. Criar estrutura de Arquivos

  • Crie uma nova pasta e abra o VSCode “Visual Studio Code” nela para começar a configurar os recursos necessários.
    • Vamos estruturar os arquivos do projeto para iniciar a criação dos recursos com Terraform. Crie a estrutura de arquivos a abaixo:

Folder-Structure

2. Vamos iniciar codificando nossos arquivos

  • Aqui vamos adicionar as informações do nosso ambiente no Azure.
    • Precisaremos setar algumas variáveis de ambiente.
  • Adicione esse conteúdo no arquivo powershell-credencials-azure.ps1.
1
2
3
4
$env:ARM_CLIENT_ID = "Client ID do seu SPN" # Aqui estou adicionando as informações do meu Service Principal que contém a permissão de Global Administrator no Entra ID
$env:ARM_TENANT_ID = "O ID do seu Tenant no EntraID"
$env:ARM_SUBSCRIPTION_ID = "ID da sua subscription"
$env:ARM_CLIENT_SECRET = "Secret do seu SPN" # Aqui estou adicionando as informações do meu Service Principal que contém a permissão de Global Administrator no Entra ID
  • Vamos criar a chave SSH para acessar a VM por meio de conexão segura.

    • O comando ssh-keygen -t rsa -b 4096 -f key-pub-lnx é usado para gerar um par de chaves SSH. O que esses parâmetros segnificam?

      • ssh-keygen: É a ferramenta de linha de comando usada para gerar, gerenciar e converter chaves de autenticação para o SSH (Secure Shell).

      • -t rsa: Especifica o tipo de chave a ser gerada. Neste caso, é uma chave RSA (Rivest–Shamir–Adleman), um dos algoritmos mais comuns para criptografia de chave pública.

      • -b 4096: Define o número de bits na chave gerada. Neste exemplo, a chave terá 4096 bits, o que proporciona um nível elevado de segurança.

      • -f key-pub-lnx: Especifica o nome do arquivo que será gerado. A chave privada será salva no arquivo key-pub-lnx, e a chave pública será salva no arquivo key-pub-lnx.pub.

Quando você executar esse comando, será solicitado que você insira uma senha (opcional) para proteger a chave privada. Aqui está um exemplo de como a execução se parecerá:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): key-pub-lnx
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in key-pub-lnx.
Your public key has been saved in key-pub-lnx.pub.
The key fingerprint is:
SHA256:...
The key's randomart image is:
+---[RSA 4096]----+
| .o.             |
| .o+ .           |
| ooE+ .          |
|.oB=..           |
|=+o+.. o o       |
|.+ .+.= B        |
|o o. .++ +       |
| +.o   +         |
|  oo             |
+----[SHA256]-----+

Adicione o conteudo abaixo no terminal PowerShell.

1
ssh-keygen -t rsa -b 4096 -f key-pub-lnx

RSA-Key

A chave privada (key-pub-lnx) deve ser mantida segura e nunca compartilhada. A chave pública (key-pub-lnx.pub) pode ser distribuída para qualquer sistema com o qual você deseja se conectar via SSH.

Nunca compartilhe sua chave privada (id_rsa), pois ela dá acesso irrestrito à VM. Para maior segurança, utilize um cofre de senhas ou uma solução como o Azure Key Vault para armazená-la.

  • Aqui vamos adicionar as informações de Provider do AzureRM. Adicione o conteúdo abaixo no arquivo provider.tf.
1
2
3
4
provider "azurerm" {
  # Configure the Azure Resource Manager provider
  features {} # Configuration options for the provider
}
  • Aqui vamos adicionar as informações da versão mais recente do Provider AzureRM e HTTP. Adicione o conteúdo abaixo no arquivo version.tf.
1
2
3
4
5
6
7
8
9
10
11
12
13
# Configure Terraform para usar os provedores necessários
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.17.0"
    }
    http = {
      source  = "hashicorp/http"
      version = "3.4.5"
    }
  }
}

Se quiser consultar uma versão mais recente, pode buscar nos links a seguir AzureRM Provider e HTTP-Provider.

  • Agora vamos iniciar a codificação dos recursos que precisamos fazer o deploy. Vamos iniciar com as tags. Ela é importante para identificar os recursos no Portal da Azure. Adicione o conteúdo abaixo no arquivo locals.tf.
1
2
3
4
5
6
7
8
9
10
11
# Tags padrões para os recursos criados pelo Terraform
locals {
  tags = {
    # Ambiente em que o recurso esta sendo criado
    Environment = "Dev"
    # Nome do projeto que o recurso esta sendo criado
    Project = "VM-Ubuntu2404"
    # Ferramenta que esta gerenciando o recurso
    Managedby = "Terraform"
  }
}
  • Agora vamos adicionar o código para criar um Resource-Group. Adicione o código abaixo no arquivo rg.tf.
1
2
3
4
5
6
7
# Crie um recurso do tipo resource_group
# mais informacoes: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group
resource "azurerm_resource_group" "rg-vm-lnx" {
  name     = "rg-vm-lnx"
  location = "East US 2"
  tags     = local.tags
}
  • Agora vamos adicionar o código para criar uma Virtual Network. Adicione o conteúdo abaixo no arquivo vnet.tf.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Crie um recurso do tipo azurerm_virtual_network
# mais informacoes: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network
resource "azurerm_virtual_network" "vnet" {
  name                = "vnet"
  resource_group_name = azurerm_resource_group.rg-vm-lnx.name
  location            = azurerm_resource_group.rg-vm-lnx.location
  address_space       = ["10.101.0.0/16"] # Espaco de enderecamento da VNet
  tags                = local.tags
}

# Crie um recurso do tipo azurerm_subnet
# mais informacoes: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet
resource "azurerm_subnet" "subnet" {
  name                              = "subnet"
  resource_group_name               = azurerm_resource_group.rg-vm-lnx.name
  virtual_network_name              = azurerm_virtual_network.vnet.name
  address_prefixes                  = ["10.101.10.0/24"] # Sub-rede criada na VNet
  # Habilita a aplicacao de politicas de seguranca na sub-rede a nivel de NSG
  private_endpoint_network_policies = "NetworkSecurityGroupEnabled"
}
  • Agora vamos adicionar o código para criar uma NSG (Network Security Group) e uma rule. Adicione o conteúdo abaixo no arquivo nsg.tf.
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
# Esse código faz uma solicitação HTTP para obter o endereço IP público da máquina que está executando o Terraform. É como perguntar "Qual é o meu IP?" e obter a resposta diretamente na sua configuração do Terraform.
data "http" "myip" {
  url = "http://ipv4.icanhazip.com"
}

# Cria um recurso do tipo network_security_group
# mais informacoes: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group
resource "azurerm_network_security_group" "nsg" {
  name                = "nsg"
  resource_group_name = azurerm_resource_group.rg-vm-lnx.name
  location            = azurerm_resource_group.rg-vm-lnx.location
  tags                = local.tags

  # Permite que as requisições sejam recebidas somente a partir do meu IP público, garantindo que apenas eu consiga acessar a VM.
  security_rule {
    name                       = "SSHInbound"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = chomp(data.http.myip.response_body)
    destination_address_prefix = azurerm_windows_virtual_machine.vm-lnx.private_ip_address # Aqui no destino você garante que a origem vai conseguir comunicação na porta 3389 somente no IP Privado da VM que vamos criar.
  }
}

# Associa o NSG à Subnet
# mais informacoes: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_network_security_group_association
resource "azurerm_subnet_network_security_group_association" "association" {
  subnet_id                 = azurerm_subnet.subnet.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

  • Aqui vamos adicionar o código das nossas variáveis que iremos utilizar. Adicione o conteúdo abaixo no arquivo variables.tf.

Em vez de adicionar os valores das variáveis no arquivo variables.tf, vamos adicioná-las como variáveis de ambiente ao executar o Terraform. Isso ajuda a manter dados sensíveis, como senhas, fora dos arquivos de configuração do Terraform.

1
2
3
4
5
6
# Variável para chave pública SSH
variable "key_pub_lnx" {
  description = "Chave pública para acesso remoto via SSH."
  type        = string
  sensitive   = true
}
  • Agora vamos adicionar o código para a estrutura da VM. Adicione o conteúdo abaixo no arquivo vm-lnx.tf.
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
resource "azurerm_public_ip" "pip-vm-lnx" {
  name                = "pip-vm-lnx"
  resource_group_name = azurerm_resource_group.rg-vm-lnx.name
  location            = azurerm_resource_group.rg-vm-lnx.location
  allocation_method   = "Static"
  tags                = local.tags
}

resource "azurerm_network_interface" "nic-vm-lnx" {
  name                = "nic-vm-lnx"
  location            = azurerm_resource_group.rg-vm-lnx.location
  resource_group_name = azurerm_resource_group.rg-vm-lnx.name
  tags                = local.tags
  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.pip-vm-lnx.id
  }
}

resource "azurerm_linux_virtual_machine" "vm-lnx" {
  name                = "vm-lnx"
  resource_group_name = azurerm_resource_group.rg-vm-lnx.name
  location            = azurerm_resource_group.rg-vm-lnx.location
  size                = "Standard_B1s"
  admin_username      = "terraform"
  tags                = local.tags
  network_interface_ids = [
    azurerm_network_interface.nic-vm-lnx.id,
  ]

  # Utiliza a chave SSH gerada para autenticação segura
  admin_ssh_key {
    username   = "terraform"
    public_key = var.key_pub_lnx
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    disk_size_gb         = 128
    name                 = "vm-lnx-os-disk"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "ubuntu-24_04-lts"
    sku       = "server"
    version   = "latest"
  }

  # Habilita o agente de provisionamento da VM
  provision_vm_agent = true

  # Habilita o TPM
  vtpm_enabled = true

  # Habilita o Secure Boot
  secure_boot_enabled = true
}

  • Por fim, vamos adicionar alguns outputs para facilitar a visualização dos resultados do deploy. Adicione o conteúdo abaixo no arquivo output.tf.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Saída do endereço IP público da máquina virtual
output "public_ip" {
  value = azurerm_public_ip.pip-vm-lnx.ip_address
}

# Saída do endereço IP privado da interface de rede da máquina virtual
output "private_ip" {
  value = azurerm_network_interface.nic-vm-lnx.private_ip_address
}

# Saída do nome da máquina virtual
output "vm_name" {
  value = azurerm_linux_virtual_machine.vm-lnx.name
}

Terraform-Output

4. Inicializar o Terraform

Já com todos os arquivos codificados, vamos iniciar o Terraform. No terminal do VSCode, digite o comando abaixo. O comando terraform init inicializa um novo ou existente diretório do Terraform configurando o ambiente, baixando os plugins e preparando o estado para implantação.

1
terraform init

Terraform-Init

5. Validar se a configuração está Correta

  • Nesta etapa vamos executar o terraform validate para verificar se os arquivos de configuração criados estão corretos em termos de sintaxe e lógica. Ele não faz alterações nos recursos, apenas valida a configuração. É útil para identificar erros antes de executar o plano terraform plan. 😉
1
terraform validate

Terraform-Validate

6. Validar a formatação dos Arquivos

  • Agora vamos executar o terraform fmt. Este comando formata os arquivos de configuração para seguir um estilo de código consistente e legível. Corrige indentação, alinhamento e outros aspectos de formatação conforme as convenções do Terraform. É uma boa prática usar esse comando regularmente para manter a base de código organizada.
1
terraform fmt

Terraform-FMT

7. Criar as variáveis de ambiente para ser possivel se conectar na Azure

  • Neste passo com o powershell aberto, dentro do VSCode, execute o comando abaixo. Ele vai executar o arquivo powershell-credencials-azure.ps1.
1
.\powershell-credencials-azure.ps1
Notem na figura que eu validei se as variáveis foram adicionadas corretamente

Set-Azure-Variables

  • Aqui vamos adicionar a variavel de ambiente da chave Publico que criamos mais acima. Adicione o comando abaixo em seu terminal do PowerShell.
1
$env:TF_VAR_key_pub_lnx="Adicione aqui o conteudo da sua chave publica"

Set-VM-Variables

8. Criar plano de Execução

  • Seguido todos esses passos, agora vamos criar um plano, execute o comando terraform plan -out my_vm-lnx.out. Ele cria um plano de execução e armazena em um arquivo. O arquivo my_vm-lnx.out é criado para revisar o que será feito sem aplicar as mudanças.
1
terraform plan -out my_vm-lnx.out

Terraform-Plan

Na figura acima, estou apresentando somente a quantidade de recursos que serão criados. Isso é feito para proteger a segurança dos dados e evitar exposição desnecessária de informações sensíveis, como o ID da subscription onde os recursos serão criados. Note que ele já me traz as informações de outputs que criamos logo acima.

8. Fazer o deploy dos Recursos

  • Agora, com o plano já executado, já sabemos quais recursos serão criados. Vamos executar o terraform apply my_vm-lnx.out.
    • Esse comando aplica as mudanças especificadas no arquivo de plano gerado pelo comando terraform plan.
1
terraform apply my_vm-lnx.out

Terraform-Apply

09. Listar recursos criados pelo Terraform

  • Vamos executar o comando terraform state list. Ele é utilizado para listar todos os recursos gerenciados pelo estado do Terraform.
    • Este comando exibe uma lista de recursos que foram criados, atualizados ou destruídos pelo Terraform e que estão sendo rastreados no arquivo tfstate.
1
terraform state list

Terraform-State-List

11. Validar recursos criados no Portal Azure

  • A estrutura de recursos criada pode ser vista na figura abaixo.

RG-Recursos

  • Os detalhes da VM criada podem ser vistos na figura abaixo.

VM-Portal

  • A regra de segurança de rede (NSG) foi criada com origem somente meu IP público e destino o IP da VM, como visto na figura abaixo.

NSG-Rule

12. Acessar VM criada

  • Nesta parte, com o usuário e chave SSH configurados como variáveis de ambiente, podemos conectar à VM utilizando o protocolo SSH com autenticação por chave pública.

Execute o comando abaixo e, na sequência, aceite a conexão

1
2
# Adicione o IP Publico da VM que foi criada. O IP da VM você obtém como output do terraform apply
ssh -i key-pub-lnx terraform@x.x.x.231

VM-Access

12. Remover recursos criados com Terraform Destroy

  • Agora que nós criamos a VM, testamos, vamos fazer a remoção dela. O comando terraform destroy é utilizado para destruir todos os recursos gerenciados pelo Terraform em sua configuração. Isso significa que ele apagará todos os recursos da infraestrutura que foram criados ou gerenciados pelo Terraform.

Esse comando é útil quando você deseja desfazer todas as mudanças aplicadas ou quando precisa limpar o ambiente.

Terraform-Destroy Terraform-Destroy2

É importante lembrar que o comando terraform destroy apaga todos os recursos gerenciados pelo Terraform, então use-o com cautela, especialmente em ambientes de produção. Sempre revise o plano de destruição antes de confirmar para garantir que você não está apagando algo por engano.

13. Segurança e Boas Práticas

Armazenamento Seguro de Credenciais: É recomendável usar o “Azure Key Vault” para armazenar informações sensíveis, como Senhas, IDs de cliente, segredos e certificados. Para integrá-lo ao Terraform, use a provider oficial do Azure. Isso garante que as credenciais sejam acessadas de forma segura e centralizada.

Exemplo:

1
2
3
4
data "azurerm_key_vault_secret" "example" {
  name         = "secret-vm-lnx"
  key_vault_id = azurerm_key_vault.example.id
}

Rotação de Secrets: Configure políticas de rotação periódica de segredos no Azure Key Vault ou automatize esse processo para minimizar riscos de segurança.

Resumo:

Neste artigo, exploramos o processo de automação da implantação de uma máquina virtual Ubuntu Server no Azure utilizando o Terraform. Discutimos os pré-requisitos necessários, incluindo a configuração de um Service Principal e a instalação das ferramentas essenciais. Além disso, detalhamos a estruturação dos arquivos do projeto e a geração de chaves SSH para acesso seguro à VM. Por fim, apresentamos o código necessário para a criação dos recursos no Azure, destacando a eficiência e consistência que a automação com Terraform proporciona.

Conclusão:

A automação da infraestrutura em nuvem com o Terraform não apenas simplifica o processo de implantação, mas também garante consistência e rastreabilidade nas configurações. Ao seguir os passos delineados neste guia, você está apto a criar e gerenciar máquinas virtuais no Azure de maneira eficiente e reproduzível. Essa abordagem reduz a probabilidade de erros manuais e facilita a manutenção e escalabilidade dos recursos na nuvem.

Próximos Passos:

Agora que sua VM já está rodando, que tal explorar mais possibilidades? Aqui estão algumas sugestões para continuar aprendendo:

  • Adicionar um disco extra à VM para armazenar mais dados 💾.
  • Automatizar a instalação de pacotes na VM com cloud-init 🛠️.
  • Utilizar o Terraform Remote State para armazenar o estado da infraestrutura na nuvem 🌍.

Essas são apenas algumas ideias para aprimorar sua infraestrutura com Terraform! Continue explorando novas configurações e torne seu ambiente ainda mais seguro e automatizado.

Até a próxima!! 😉

resource-group

#CloudInsights #Azure #Tech #Cloud #Security #Network #Terraform #InfraAsCode


Build and Deploy

Este post está licenciado sob CC BY 4.0 e pelo autor.