Skip to content

Instantly share code, notes, and snippets.

What would you like to do?

How to Configure Terraform to Automate OpenStack's Resources


Although the Horizon dashboard provided in OpenStack is useful for most tasks, infrastructure automation tools like Terraform exist to allow you to create your infrastructure as code. This allows your infra teams to follow standard development flows and implement CI/CD to fully automate your cloud.

In this guide, you will configure Terraform to leverage OpenStack with a generated clouds.yaml.

When you're finished, you'll be able to automate your cloud like a pro!


Before you begin this guide you'll need the following:

  • A local machine or jumpstation (control node) with Terraform downloaded and installed.
  • An OpenStack user with access to a project.
  • A text editor or IDE

Step 1 — Generate a clouds.yml from OpenStack

First step is to navigate to the correct area to generate the clouds.yaml.

Once logged into the Horizon dashboard on the top left navigation area, click on the API Access tab.

Next select the dropdown on the "Download OpenStack RC File" and select the option to "OpenStack clouds.yaml file"

The contents of the clouds.yaml should look like the following below. If you want a completely seamless experience you will need to add your password to the auth section.

      auth_url: https://openstack-cluster.url:5000
      username: "docs"
      project_id: 0cbe14b0db11426c8413d9f4eaa13311
      project_name: "docs"
      user_domain_name: "Default"
    region_name: "lax"
    interface: "public"
    identity_api_version: 3

Now that we have the clouds.yaml we can configure terraform to use it.

Step 2 — Configure Terraform with clouds.yaml

First, place the clouds.yaml into the current working directory of your Terraform file. It can also be placed in ~/.config/openstack or /etc/openstack.

Next we will modify the OpenStack provider in Terraform to specify the OpenStack cluster in our clouds.yaml. In our example our cluster is named flex_metal be sure to use whichever cluster name that is specified in your file.

provider "openstack" {
    cloud = "flex_metal"

Once that is modified correctly, you should be able to run terraform init to finish the setup.

root@crees-pc: ~/terraform/openstack # terraform init

Initializing the backend...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Step 3 — Automate your cloud!

Now that everything is configured, you should be able to run your terraform modules or create your own and automate against your OpenStack cluster. Some of the next tasks you can do is to edit your clouds.yaml to add more cluster, and automate against multiple cloud infrastructures all at once!

How to use Swift as your Terraform Backend


In this quick guide we will go over how to use OpenStack Swift as the backend for terraform. We will also go into some details about what a Terraform backend is as well as Terraform states.

What is a terraform backed?

In Terraform, a backend tells how a "state" is loaded and how operations like "plan" and "apply" are executed. A state is the mapping of assets that are created and managed by Terraform, you can think of this as a snapshot of your current cloud infrastructure. By default this state is saved to the local machine that is running Terraform.

While remote backends are completely optional to the operation of Terraform, there are benefits to using one. First it allows for working in a team to be easier. The backend can store the state of a team's cloud and grants the ability to lock the state to prevent any corruption. It allows you to keep any sensitive information off disk. The Terraform state is retrieved from backend when needed and is stored in memory, the only location this exists is where the backend is storing it. You can also use it for remote operations. When working with large infrastructures, operations like 'apply' can take a significant amount of time. Some backend allow for remote operations so that you can apply the change and don't have to worry about any interruptions that can happen on a local machine.

How to configure Terraform to use a swift backend

Configuring Terraform is pretty simple. First you have to do is provide access to your OpenStack cloud via the provider section. For information on how to do this you can see the article here on how to generate and configure a clouds.yaml in OpenStack.

Next you will want to use the backend option with swift. Below is an example of how to do this.

terraform {
  backend "swift" {
    container         = "terraform-state"
    archive_container = "terraform-state-archive"
    cloud = "flex_metal" # Using a clouds.yaml file

After that simply run a terraform init and let it configure the new backend.

root@crees-pc: ~/terraform/openstack # terraform init

Initializing the backend...

Successfully configured the backend "swift"! Terraform will automatically
use this backend unless the backend configuration changes.

Congratulations, you have successfully setup swift as a Terraform backend!

Intro to cloud-init

Cloud-init is an industry standard method for Linux cloud instance initialization. Cloud-init has support across all major Linux distributions, FreeBSD, NetBSD and OpenBSD. It is also supported across all major public cloud providers, provisioning systems for private cloud infrastructure, and bare-metal installations.

Cloud-init will identify the cloud it is running on, using the provided metadata from the cloud, and configure the system accordingly. Tasks can include things like networking configurations, setting up the drives, ssh access, and other server tasks before you even log into the server.

Using a cloud-config script

More than likely you will pass a cloud-config script to the server on provision. This will get picked up by cloud-init and actions in the file are carried out. The cloud-config script is a YAML formatted file. YAML is a human-readable data serialization standard that is generally used for configuration files, but can have various other uses as well.

When creating a cloud-config file you will want to place a special identifier of #cloud-config so that cloud-init can be aware of the set of instructions its about to receive. Below we will go over some examples of cloud-configs.

  - name: chrisb
    groups: sudo
    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
      - ssh-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCaGLKWXz61dB0E5yJrpJ8kcfKHaQQIS91XjjPY/2o8mCkNXoC/XkXiVhvL0mlzyzs6ALeUBmTXS5iy1llFbqQsRNkTaZHIWD3REYyv5lPuHWWFYklgf2Sd0vEWQfQBrGBnqRnvIwL1ajFEEpm0HbNtE1xhukfsH+FAl+JrMkPbYTBkvvCX/6a2g8A8qsUnb5zQ+uEoEdKu85kB54x7i6IQboG9z6u4xEu6ISYArZo+UPSf5HxcLkbv776RJWOQb81tJIDEbLSn+xNS3ThAtC4DgSo2OjP7KgLKk1X5o1PTOaTiL/oq5NHOnwuegwtVkqNrq2mULhN3Tot3ayV2+Efr chris@work_laptop
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCEO/nW7MeFTKETbjesBQFLYhYa/Os9eKBGWiBCuP9ZstzSwkwA9dmNgtseRAnp01OvHMDFyTUcIuaHPBBqxafixF4RnV54QYz8bEIdDR6LpBj1y3ih8foobe9tFPiERzbVmZysP19Hag9e6HkLgJ9OjLqsO1eiR2djC/UGPQt601MYZhk7EpxFJpO8uu28G9nM8BRw0dBqrB525Q4/yKtekMz2nbQnfeYrR6kbmCqbgcvFHlgnBsapeVlP5v9T2qQnz1JfUUDIgJ6Zpyldld+qJCQERU0C9kldUHEijnBvoC68+1BBLJNTT9hUV0XivwCqJ/F6IlMp8bI4sTKCuysX chris@home_desktop
  - touch /done.txt

In this example we are creating a user for chrisb and giving that user sudo access. We also specify some public ssh keys so that ssh access is simple.

package_upgrade: true
  - python3-pip
  - python3-dev
  - build-essential
  - libssl-dev
  - libffi-dev

In this example we make sure that all packages are up to date as well as ensure that some specific packages are installed on the server.

manage-resolv-conf: true
    - '' #quad9
    - '' #google

In our last example we are setting the server's resolvers to the ones specified there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment