🏗️ 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
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.

Click Generate Credentials to start creating the access credentials.

Fill out the form with the required information:
| Field | Description |
|---|---|
| Name | Friendly identifier for the credential |
| Project | Project to which the credential will be linked |
| Region | Region where the credential will operate |
| Expiration Date | Leave blank for the credential to never expire |
| Description | Optional field to describe the credential's use |

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
The Credentials Secret is shown only once. If not saved at this moment, you will need to generate a new pair of credentials.

📁 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"
terraform.tfvarsThis 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
| Field | Description |
|---|---|
<ssh-keypair-resource-id> | Logical identifier of the resource in Terraform (e.g., keypair_nuvion) |
name | Name of the key pair displayed on the Nuvion platform (e.g., minha-chave-terraform) |
public_key | Content of your public key (e.g., ssh-ed25519 AAAA...) — the same value manually registered in SSH Keys on the platform |
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.
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"
| Field | Description |
|---|---|
<data-resource-id> | Logical identifier of the resource within Terraform (e.g., ubuntu_22) |
name | Exact name of the image available on the platform (e.g., Ubuntu 22.04) |
most_recent | When true, selects the latest version of the image if multiple matches exist |
resource "openstack_blockstorage_volume_v3"
| Field | Description |
|---|---|
<volume-resource-id> | Logical identifier of the volume in Terraform (e.g., vm_boot_volume) |
name | Name of the volume displayed on the platform |
size | Volume size in GB (e.g., 50) |
image_id | Reference to the image obtained by the data block above |
resource "openstack_compute_instance_v2"
| Field | Description |
|---|---|
<compute-resource-id> | Logical identifier of the instance in Terraform (e.g., minha_vm) |
name | Name of the VM displayed on the platform |
flavor_name | Instance type defining CPU, RAM, and resources (e.g., m1.small) |
key_pair | Reference to the SSH key pair created by the openstack_compute_keypair_v2 resource |
security_groups | List of security groups applied to the instance |
network.name | Name of the network to which the VM will be connected |
block_device.uuid | Reference to the volume created previously |
block_device.source_type | Boot device source — volume indicates a block volume |
block_device.destination_type | Device destination — volume for persistent storage |
block_device.boot_index | Boot order — 0 indicates the primary disk |
block_device.delete_on_termination | When 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
applyThe 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! 🎉
- 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.tfvarswith credentials to public repositories. - Use
terraform planalways beforeapplyto 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!