Creating a network in OpenStack with OpenTofu

I really like that there is a free and Open Source fork of Terraform now. For me, the future is Open Source, and specifically Free and Open Source.

I don't believe this because I like to not have to pay for software. I believe this because it is no other way to move forward with digital transformation at a high pace effectively. Very much so in the public sector, but also for organizations in general.

OpenStack is my platform of choice. First off, it is Open Source, and second off, a lot of public cloud providers deploy OpenStack. So there are a lot of places to put your infrastructure.

And this is where a cool thing about infrastructure as code comes through. It is so easy to deploy resources to different providers and platforms that it was almost lost on me. I had to try it out and then I started to get it.

But, anyhow, lets do something with OpenTofu and OpenStack.

The basic stuff first

We are doing this without extra tools like Terragrunt and Gitlab. I usually create a variable to hold all parameters to connect to OpenStack. I keep the sensitive part, the application credential secret in a separate file called connect.auto.tfvars. This way, that file, containing the secret will be read by OpenTofu at plan, apply, destroy and so on.

But, when working in a team, this would preferably be read from a secret manager of some sort or in your build server so that you don't even need to store the secret locally.

Below is the file I call main.tf because it is the starting point in my mind with the provider connection parameters and the OpenTofu configuration.

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

provider "openstack" {
  application_credential_id     = var.connection.application_credential_id
  application_credential_secret = var.application_credential_secret
  auth_url                      = var.connection.auth_url
  region                        = var.connection.region
  endpoint_type                 = var.connection.endpoint_type
}

To use the main.tf file we also need a variables.tf file. You could call this whatever you want, but I will probably add more variables to this file, so instead of calling it connect.tf to categorize it with the connect.auto.tfvarsfile, I just call it varibles.tf.

I use Binero as the public cloud provider. Binero is based in Sweden, as am I.

I use an application credential instead of a user account because I like to differentiate using user accounts from API oriented accounts. Application credentials were designed for this purpose.

variable "connection" {
  type = object({
    application_credential_id = string
    auth_url                  = string
    endpoint_type             = string
    region                    = string
  })

  default = {
    application_credential_id = "application_id"
    auth_url                  = "https://auth.binero.cloud:5000/v3"
    region                    = "europe-se-1"
    endpoint_type             = "public"
  }
}

variable "application_credential_secret" {
  type      = string
  sensitive = true
}

Create a network

So with a main.tfvars and variables.tf accompanied with the connect.auto.tfvars file we have all we need to make some resources with OpenTofu.

In this case I will create a network and a subnet to that network.

I add a variable for the network cidr in the variables.tf. This could be more comprehensive, but works for our example.

variable "main_network_cidr" {
  type    = string
  default = "10.10.10.0/24"
}

And we use the above variable in the resource declaration in network.tf:

resource "openstack_networking_network_v2" "main" {
  name           = "main"
  description    = "Main network for general purpose."
  admin_state_up = "true"
}

resource "openstack_networking_subnet_v2" "main" {
  name        = "main"
  description = "Main network subnet for general purpose."
  network_id  = openstack_networking_network_v2.main.id
  cidr        = var.main_network_cidr
  ip_version  = 4
}

I would normally create input variables for all the above arguments in the resource blocks. But again, this is just an example. The idea of using a variable for each argument is that you then can re-use the resource block in other projects and create a module of it. And it makes it possible to add variables when performing tofu apply.

The above should get you running with creating a network and subnet in OpenStack. Remember that the connection arguments might differ between OpenStack providers.

Also, this is just an example, I will create more comprehensive projects in the future where I will gear towards something that is production ready. I will also share my code in a public repository (as soon as my public repository is ready for that)

I hope you found this useful. As stated, more is to come.

#terraform #opentofu #openstack #network

Joakim Durehed