Skip to main content

🏗️ Creating a VM with Terraform

Terraform is an Infrastructure as Code (IaC) tool developed by HashiCorp. With it, you describe your entire infrastructure in declarative configuration files, allowing you to provision, modify, and destroy resources in an automated, versionable, and reproducible way.

When using Terraform with the Nuvion platform, you gain benefits such as:

  • 🔁 Reproducibility — recreate identical environments with a single command
  • 📋 Versioning — control infrastructure changes with Git
  • Agility — provision multiple resources in parallel automatically
  • 🔍 Auditability — the entire infrastructure state is recorded in code
📦 Prerequisite

Before starting, make sure Terraform is installed on your machine. You can download it at https://developer.hashicorp.com/terraform/downloads.

Check the installation with:

terraform -version

🔑 Step 1 — Generating OpenStack Credentials

The provider used is OpenStack, which has native compatibility with the Nuvion platform. For Terraform to authenticate and manage resources, you need to generate Application Credentials.

Access your account and navigate to My Account > OpenStack Credentials.

Tela de acesso ao menu My Account com opção OpenStack Credentials na plataforma Nuvion


Click Generate Credentials to start creating the access credentials.

Botão Generate Credentials na tela de OpenStack Credentials


Fill out the form with the required information:

FieldDescription
NameFriendly identifier for the credential
ProjectProject to which the credential will be linked
RegionRegion where the credential will operate
Expiration DateLeave blank for the credential to never expire
DescriptionOptional field to describe the credential's use

Formulário de criação de credenciais OpenStack com campos Nome, Projeto, Região, Expiração e Descrição


After generating, immediately save the following data — they will be used in the Terraform configuration:

  • 🔗 Server URL — OpenStack API authentication endpoint
  • 🪪 Credentials ID — unique identifier of the credential
  • 🔐 Credentials Secret — secret associated with the credential
⚠️ Attention when saving credentials

The Credentials Secret is shown only once. If not saved at this moment, you will need to generate a new pair of credentials.

Tela com os dados gerados: Server URL, Credentials ID e Credentials Secret


📁 Step 2 — Configuration File Structure

The basic Terraform configuration is divided into three main files. This separation is a best practice that facilitates maintenance, versioning, and reuse of configurations.

.
├── provider.tf # Configuração do provider OpenStack
├── terraform.tfvars # Valores das variáveis (credenciais e endpoints)
├── 00-variables.tf # Declaração das variáveis utilizadas
├── ssh-keypair.tf # Gerenciamento do par de chaves SSH via Terraform
└── instance.tf # Definição da VM e dos recursos associados

📄 provider.tf

Defines the minimum Terraform version and configures the OpenStack provider, providing credentials and region via variables.

terraform {
required_version = ">= 0.14.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "~> 1.53.0"
}
}
}

provider "openstack" {
application_credential_id = var.application_credential_id
application_credential_secret = var.application_credential_secret
auth_url = var.os_auth_url
region = var.os_region
}

📄 terraform.tfvars

File where the actual variable values are defined. Replace the fields between < > with the data obtained when generating the OpenStack credentials.

application_credential_id     = "<credentials-id>"
application_credential_secret = "<credentials-secret>"
os_auth_url = "https://cmp.console.saveincloud.io/openstack/2"
os_region = "RegionOne"
🔒 Security of terraform.tfvars

This file contains sensitive information. Add it to your repository's .gitignore to prevent credentials from being accidentally exposed in version control systems.

# .gitignore
terraform.tfvars
*.tfstate
*.tfstate.backup
.terraform/

📄 00-variables.tf

Declares the variables used by the provider, without assigning values — these are read from the terraform.tfvars at runtime.

variable "application_credential_id" {}
variable "application_credential_secret" {}
variable "os_auth_url" {}
variable "os_region" {}

🔑 Step 3 — Managing the SSH Key Pair with ssh-keypair.tf

The file ssh-keypair.tf allows the SSH key pair used to access the VM to be managed directly by Terraform, centralizing all infrastructure as code and eliminating the need to manually register the key on the platform.

resource "openstack_compute_keypair_v2" "<ssh-keypair-resource-id>" {
name = "<name>"
public_key = "<chave-publica>"
}

📖 Field Descriptions

FieldDescription
<ssh-keypair-resource-id>Logical identifier of the resource in Terraform (e.g., keypair_nuvion)
nameName of the key pair displayed on the Nuvion platform (e.g., minha-chave-terraform)
public_keyContent of your public key (e.g., ssh-ed25519 AAAA...) — the same value manually registered in SSH Keys on the platform
💡 Obtaining the public key value

The value of public_key is the content of the file .pub generated by ssh-keygen or PuTTYgen. To display it in the terminal, use:

cat ~/.ssh/id_ed25519.pub

Copy the entire output, including the prefix ssh-ed25519 and the comment at the end.

🔗 Referencing the keypair in the instance

After declaring the resource openstack_compute_keypair_v2, reference it in the instance.tf by the attribute name of the created resource:

key_pair = openstack_compute_keypair_v2.<ssh-keypair-resource-id>.name

This ensures Terraform applies dependencies in the correct order — creating the keypair before provisioning the VM.


🖥️ Step 4 — Defining the VM with instance.tf

The file instance.tf declares all resources necessary to provision the virtual machine: the operating system image, the storage volume, and the compute instance itself.

# -------------------------------------------------------
# 1. Busca a imagem do sistema operacional mais recente
# -------------------------------------------------------
data "openstack_images_image_v2" "<data-resource-id>" {
name = "<nome-da-imagem>"
most_recent = true
}

# -------------------------------------------------------
# 2. Cria o volume de armazenamento (disco da VM)
# -------------------------------------------------------
resource "openstack_blockstorage_volume_v3" "<volume-resource-id>" {
name = "<nome-do-volume>"
size = <tamanho-do-volume>
image_id = data.openstack_images_image_v2.<data-resource-id>.id
}

# -------------------------------------------------------
# 3. Provisiona a instância de computação (VM)
# -------------------------------------------------------
resource "openstack_compute_instance_v2" "<compute-resource-id>" {
name = "<nome-vm>"
flavor_name = "<flavor>"
key_pair = openstack_compute_keypair_v2.<ssh-keypair-resource-id>.name
security_groups = ["default"]

network {
name = "<nome-da-rede>"
}

block_device {
uuid = openstack_blockstorage_volume_v3.<volume-resource-id>.id
source_type = "volume"
destination_type = "volume"
boot_index = 0
delete_on_termination = true
}
}

📖 Field Descriptions

data "openstack_images_image_v2"

FieldDescription
<data-resource-id>Logical identifier of the resource within Terraform (e.g., ubuntu_22)
nameExact name of the image available on the platform (e.g., Ubuntu 22.04)
most_recentWhen true, selects the latest version of the image if multiple matches exist

resource "openstack_blockstorage_volume_v3"

FieldDescription
<volume-resource-id>Logical identifier of the volume in Terraform (e.g., vm_boot_volume)
nameName of the volume displayed on the platform
sizeVolume size in GB (e.g., 50)
image_idReference to the image obtained by the data block above

resource "openstack_compute_instance_v2"

FieldDescription
<compute-resource-id>Logical identifier of the instance in Terraform (e.g., minha_vm)
nameName of the VM displayed on the platform
flavor_nameInstance type defining CPU, RAM, and resources (e.g., m1.small)
key_pairReference to the SSH key pair created by the openstack_compute_keypair_v2 resource
security_groupsList of security groups applied to the instance
network.nameName of the network to which the VM will be connected
block_device.uuidReference to the volume created previously
block_device.source_typeBoot device source — volume indicates a block volume
block_device.destination_typeDevice destination — volume for persistent storage
block_device.boot_indexBoot order — 0 indicates the primary disk
block_device.delete_on_terminationWhen true, the volume is deleted along with the VM when destroying the resource

🚀 Step 4 — Running Terraform

With all files configured, run the following commands in the project directory:

# Inicializa o projeto e baixa o provider OpenStack
terraform init

# Exibe um plano detalhado de todos os recursos que serão criados
terraform plan

# Aplica as configurações e provisiona os recursos na plataforma
terraform apply
💡 Confirmation of apply

The command terraform apply will ask for confirmation before creating resources. Type yes to proceed. Use the -auto-approve flag for CI/CD environments where manual confirmation is not desired.


✅ Workflow Summary

1. Gerar credenciais OpenStack na plataforma Nuvion

2. Criar os arquivos provider.tf, terraform.tfvars e 00-variables.tf

3. Declarar o par de chaves SSH no arquivo ssh-keypair.tf

4. Definir os recursos da VM no arquivo instance.tf

5. Executar terraform init → terraform plan → terraform apply

6. VM provisionada e disponível na plataforma! 🎉

🛡️ Best practices with Terraform
  • Use workspaces to separate development, staging, and production environments.
  • Store the state remotely (e.g., in an S3 bucket or Terraform Cloud) for team collaboration.
  • Never commit the terraform.tfvars with credentials to public repositories.
  • Use terraform plan always before apply to review changes that will be applied.
  • Version your modules to ensure stability over time.

🧠 Questions?

Contact technical support and send your question — we are here to help you!

Official Terraform Documentation