OpenStack private networks enable instances to be reached safely without being exposed to the public internet. Private networks are vital for internal services, database layers, or application layers.

In this post, we’re going to automate private networks and subnets creation using a Terraform module stored in a github repository.

Prerequisites

  • Terraform installed
  • OpenStack credentials and network access
  • OpenStack provider properly configured

Step 1: Install Terraform

If you don’t have terraform installed, run one of the following commands that match your working environment:

# Ubuntu/Debian
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

# CentOS/RHEL
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install terraform

# Fedora
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager addrepo --from-repofile=https://rpm.releases.hashicorp.com/fedora/hashicorp.repo
sudo dnf -y install terraform

# Amazon Linux
sudo yum install -y yum-utils shadow-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo yum -y install terraform

# macOS Homebrew
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

Step 2: Configure Terraform Provider

To authenticate Terraform with OpenStack, define the provider as follows in your main.tf file:

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

# Configure the OpenStack Provider
provider "openstack" {
  user_name   = "admin"
  tenant_name = "admin"
  password    = "pwd"
  auth_url    = "http://myauthurl:5000/v3"
  region      = "RegionOne"
}

For a local statefile, you can configure it as follows:

terraform {
  backend "local" {
    path = "${path.module}/terraform.tfstate"
  }
}

Step 3: The Network Module Overview

The netowork module uses resources such as the openstack_networking_network_v2 to create private networks and subnets. This module creates a private network, a private subnet, a router, and attaches the subnet to the private network.

It utilizes four main configuration files to achieve this:

  • data.tf: Defines data sources
  • main.tf: Contains resource definitions
  • outputs.tf: Declares input variables
  • variables.tf: Defines module outputs

The files are configured as follows:

data.tf

This file defines data sources to retrieve existing OpenStack resources, such as the external network:

# Data source to get the external network ID
data "openstack_networking_network_v2" "external_network" {
  name = var.external_network_name
}
main.tf

This file contains the primary resource definitions for creating the network and subnet:

# Create a private network
resource "openstack_networking_network_v2" "private_network" {
  name           = var.network_name
  admin_state_up = true
}

# Create a private subnet
resource "openstack_networking_subnet_v2" "private_subnet" {
  name            = var.subnet_name
  network_id      = openstack_networking_network_v2.private_network.id
  cidr            = var.subnet_cidr
  ip_version      = 4
  dns_nameservers = var.dns_nameservers
}

# Create a router
resource "openstack_networking_router_v2" "router" {
  name                = "${var.network_name}-router"
  admin_state_up      = true
  external_network_id = data.openstack_networking_network_v2.external_network.id
}

# Attach the private subnet to the router
resource "openstack_networking_router_interface_v2" "router_interface" {
  router_id = openstack_networking_router_v2.router.id
  subnet_id = openstack_networking_subnet_v2.private_subnet.id
}
variables.tf

This file declares the input variables required by the module:

variable "network_name" {
  description = "The name of the private network"
  type        = string
}

variable "subnet_name" {
  description = "The name of the private subnet"
  type        = string
}

variable "subnet_cidr" {
  description = "The CIDR block of the private subnet"
  type        = string
}

variable "external_network_name" {
  description = "The name of the external network"
  type        = string
}

variable "region" {
  description = "The region in which to create the network resources"
  type        = string
  default     = "RegionOne"
}

variable "dns_nameservers" {
  description = "List of DNS nameservers for the subnet"
  type        = list(string)
  default     = ["8.8.8.8", "8.8.4.4"]
}
outputs.tf

This file defines the outputs of the module, which can be used by other modules or resources:

variable "network_name" {
  description = "The name of the private network"
  type        = string
}

variable "subnet_name" {
  description = "The name of the private subnet"
  type        = string
}

variable "subnet_cidr" {
  description = "The CIDR block of the private subnet"
  type        = string
}

variable "external_network_name" {
  description = "The name of the external network"
  type        = string
}

variable "region" {
  description = "The region in which to create the network resources"
  type        = string
  default     = "RegionOne"
}

variable "dns_nameservers" {
  description = "List of DNS nameservers for the subnet"
  type        = list(string)
  default     = ["8.8.8.8", "8.8.4.4"]
}

Step 4: Using the Module

Configure your main.tf file as follows:

module "network" {
  source = "git::https://github.com/cloudspinx/terraform-openstack.git//modules/network?ref=main"

  network_name          = privatenet
  subnet_name           = privatenet_subnet
  subnet_cidr           = 172.34.50.0/24
  external_network_name = public
  region                = RegionOne
  dns_nameservers       = ["8.8.8.8", "8.8.4.4"]
}

Run the following terraform commands to deploy the resources:

terraform init
terraform apply

The private network and subnet should be created on your OpenStack cloud.

Optional: Run the module locally

If you want to customize the module to match your needs, it’s best to clone the repo and run the module locally on your working environment:

git clone https://github.com/cloudspinx/terraform-openstack.git

Create a main.tf file in the root folder for module usage configs.

terraform-openstack/
├── main.tf               # Provider and module usage configs                   
├── modules               # Modules, including kepair
│   ├── network/          # The module you're using
│   │   ├── data.tf
│   │   ├── main.tf       # Define resouces
│   │   ├── variables.tf  # Define any variables
│   │   ├── outputs.tf    # Optional outputs 
│   └── other_modules/

Be sure to reference the module path in your source. See below:

module "network" {
  source = "./modules/network"

  network_name          = privatenet
  subnet_name           = privatenet_subnet
  subnet_cidr           = 172.34.50.0/24
  external_network_name = public
  region                = RegionOne
  dns_nameservers       = ["8.8.8.8", "8.8.4.4"]
}

Run the following commands in your OpenStack environment to verify the resource creation:

openstack network list
openstack subnet list

LEAVE A REPLY

Please enter your comment!
Please enter your name here