Openstack: Some first steps (Tofu revisited)

Openstack Mar 18, 2026

I wrote an article regarding some initial configuration of Openstack. The very few steps required:

Openstack: Some first steps
This article is a “remake” of an old one, adapted to this new openstack deployment using terraform. Starting with Openstack AdministrationRecently I wrote a post about deploying Openstack using kolla-ansible. I finished the article explaining that it was working based on the results of Openstack’s dashboard. Yes, I can

I strongly recommend reading that article in order to understand. I would also recommend reading the article I wrote about installing Openstack locally using Terraform/OpenTofu.

Provisioning Infrastructure with Terraform and Libvirt for OpenStack Deployment
This article gets deeper building a complete virtual infrastructure using OpenTofu/Terraform and libvirt, which will serve as the foundation for a full OpenStack deployment via Kolla-Ansible. By the end, you’ll have 5 running VMs — one router, one controller, and three compute nodes — with OpenStack up and accessible. So, the

I am going to explain now how can I configure the newly installed Openstack using OpenTofu (Terraform).

As I usually type tofu and terraform, I've created my alias for terraform. Yes, I know, it is clearer if I get used to type tofu, but I got tired of repeating the same command once and again. So, the alias:

alias terraform=tofu

So, what steps will I follow?

  • Review the network configuration after my Openstack installation - There are some limitations in a default configuration of Linux, so I created a couple of scripts to make the Openstack networking properly run.
  • I'll add a couple images to Glance, so I can create later new Virtual Servers.
  • I'll add a few "Flavors", so I can tell my future Virtual Servers how much RAM, vCPUs and disk they can use.
  • I'll create a couple of Networks, for sure my future Virtual machines will love to be accessed and used. They will be happy to connect to internet and watch interesting youtube videos.
  • I'll create a new user. Yes, it is interesting doing things as an admin user, but I'd better create a new non admin user. Simply for security reasons.
  • Finally, as non admin user, I'll show how to create a new Virtual Machines.

Openstack Provider for Terraform/OpenTofu

To configure the driver we need to define the following:

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

and run;

terraform init

The configuration part goes like this:

# Configure the OpenStack Provider
# Not needed if the environment variables are defined before running
# "tofu apply|destroy|state xx"
provider "openstack" {
  user_name   = "admin"
  tenant_name = "admin"
  password    = "xxxx"
  auth_url    = "http://os-admin.openstack.mine:5000/v3"
  region      = "corporario"
}

However, in Openstack, one standard way to configure this is using environment variables - If we use those environment variables, we can skip that configuration for the Openstack provider.

export OS_USERNAME="admin"
export OS_PROJECT_NAME="admin"
export OS_AUTH_URL=http://os-admin.openstack.mine:5000
export OS_REGION_NAME="corporario"
export OS_PROJECT_DOMAIN_ID="default"
export OS_INTERFACE=public
export OS_IDENTITY_API_VERSION=3

# As I deployed Openstack using kolla-ansible, I can get the admin password
# from the "password.yml" file.
export OS_PASSWORD=$(awk '$1 ~ /keystone_admin_password/ {print $2}' /etc/kolla/passwords.yml)

Así que sólo tengo que ejecutarlo con source:

source ~/keystone-rc-admin.sh

Add Images to glance

Manual Image downloads

Terraform is not designed for running local commands. We'll later need download a couple images (something like blueprint templates to create new virtual servers) and upload them to Openstack. Some of these images are compressed and we need to uncompress them before uploading them to openstack.

So, Lets download and uncompress those images - I'll do it in my /var/lib/libvirt/base-image-pool/ directory.

cd /var/lib/libvirt/base-image-pool/

# Download cirros
wget https://download.cirros-cloud.net/0.6.3/cirros-0.6.3-x86_64-disk.img

# Download Ubuntu-noble (24.04)
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

# Download fedora coreos
wget https://builds.coreos.fedoraproject.org/prod/streams/stable/builds/43.20260217.3.1/x86_64/fedora-coreos-43.20260217.3.1-qemu.x86_64.qcow2.xz

# I need to descompress before uploading to Openstack.
unxz fedora-coreos-43.20260217.3.1-qemu.x86_64.qcow2.xz

Upload Image to Glance

In order to upload a new image to glance, I can add the following hclcode:

# basic example - Not used later.

resource "openstack_images_image_v2" "cirros" {
  name             = "cirros"
  image_source_url = "https://download.cirros-cloud.net/0.6.3/cirros-0.6.3-x86_64-disk.img"
  container_format = "bare"
  disk_format      = "qcow2"
  visibility       = "public"

  properties = {
    key = "value"
  }
}

... Three times. Or I could define a new variable with type map and iterate over the elements:

variable "images" {
   description = "List of images to upload with some of their properties"
   type = map(object({
      filename = string
   }))

   default = {
      cirros = {
         filename = "/var/lib/libvirt/base-image-pool/cirros-0.6.3-x86_64-disk.img"
      }
      ubuntu-2404 = {
         filename = "/var/lib/libvirt/base-image-pool/noble-server-cloudimg-amd64.img"
      }
      fedoracore-43 = {
         filename = "//var/lib/libvirt/base-image-pool/fedora-coreos-43.20260217.3.1-qemu.x86_64.qcow2"
      }
   }
}

resource "openstack_images_image_v2" "images" {
  for_each = var.images
  name             = each.key
  local_file_path  = each.value.filename
  container_format = "bare"
  disk_format      = "qcow2"
  visibility       = "public"

  properties = {
    key = "value"
  }
}

After running terraform apply, we'll have the images there:

Tags