Skip to content

Instantly share code, notes, and snippets.

@halkyon
Created March 12, 2026 02:13
Show Gist options
  • Select an option

  • Save halkyon/0d5cae7ed9e0a607edc9fd792c753b8c to your computer and use it in GitHub Desktop.

Select an option

Save halkyon/0d5cae7ed9e0a607edc9fd792c753b8c to your computer and use it in GitHub Desktop.
OpenStack Terraform example
locals {
ssh_key_file = coalesce(
var.ssh_key_file,
fileexists(pathexpand("~/.ssh/id_rsa.pub")) ? "~/.ssh/id_rsa.pub" : "",
fileexists(pathexpand("~/.ssh/id_ed25519.pub")) ? "~/.ssh/id_ed25519.pub" : "",
)
}
data "openstack_networking_network_v2" "external" {
name = var.external_network_name
}
resource "openstack_compute_keypair_v2" "ssh" {
name = "${var.server_name_prefix}-keypair"
public_key = file(pathexpand(local.ssh_key_file))
}
resource "openstack_networking_network_v2" "network" {
name = "${var.server_name_prefix}-network"
admin_state_up = true
}
resource "openstack_networking_subnet_v2" "subnet" {
name = "${var.server_name_prefix}-subnet"
network_id = openstack_networking_network_v2.network.id
cidr = var.network_cidr
ip_version = 4
dns_nameservers = var.dns_nameservers
}
resource "openstack_networking_router_v2" "router" {
name = "${var.server_name_prefix}-router"
admin_state_up = true
external_network_id = data.openstack_networking_network_v2.external.id
}
resource "openstack_networking_router_interface_v2" "router_interface" {
router_id = openstack_networking_router_v2.router.id
subnet_id = openstack_networking_subnet_v2.subnet.id
}
resource "openstack_networking_secgroup_v2" "ssh" {
name = "${var.server_name_prefix}-ssh"
description = "Allow SSH ingress on port 22"
}
resource "openstack_networking_secgroup_rule_v2" "ssh_ingress" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.ssh.id
}
resource "openstack_compute_instance_v2" "servers" {
count = var.server_count
name = format("%s-%02d", var.server_name_prefix, count.index + 1)
image_name = var.image_name
flavor_name = var.flavor_name
key_pair = openstack_compute_keypair_v2.ssh.name
security_groups = [openstack_networking_secgroup_v2.ssh.name]
user_data = <<-EOF
#!/bin/bash
apt-get update
apt-get upgrade -y
apt-get install -y htop curl
EOF
network {
uuid = openstack_networking_network_v2.network.id
}
depends_on = [openstack_networking_router_interface_v2.router_interface]
}
output "server_names" {
description = "Names of the created servers"
value = openstack_compute_instance_v2.servers[*].name
}
output "server_private_ips" {
description = "Private IP addresses of the servers"
value = openstack_compute_instance_v2.servers[*].network[0].fixed_ip_v4
}
output "network_name" {
description = "Name of the private network"
value = openstack_networking_network_v2.network.name
}
output "subnet_cidr" {
description = "CIDR of the private subnet"
value = openstack_networking_subnet_v2.subnet.cidr
}
output "security_group_name" {
description = "Name of the SSH security group"
value = openstack_networking_secgroup_v2.ssh.name
}
variable "server_count" {
description = "Number of servers to create"
type = number
default = 5
}
variable "server_name_prefix" {
description = "Prefix for server names"
type = string
default = "server"
}
variable "image_name" {
description = "Name of the image to use for servers"
type = string
default = "debian-13-generic-amd64-20260220-2394"
}
variable "flavor_name" {
description = "Name of the flavor to use for servers"
type = string
default = "g-1vcpu-2gb"
}
variable "external_network_name" {
description = "Name of the external (public) network for floating IPs and router gateway"
type = string
default = "public"
}
variable "network_cidr" {
description = "CIDR block for the private network subnet"
type = string
default = "10.0.0.0/24"
}
variable "dns_nameservers" {
description = "DNS nameservers for the subnet"
type = list(string)
default = ["8.8.8.8", "8.8.4.4"]
}
variable "ssh_key_file" {
description = "Path to the SSH public key file. Leave empty to auto-detect (~/.ssh/id_rsa.pub then ~/.ssh/id_ed25519.pub)"
type = string
default = ""
}
terraform {
required_version = ">= 1.3.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "~> 3.0"
}
}
}
provider "openstack" {
# add the application credentials, region, etc here, or load them from envs. See https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment