A real-world OpenStack infrastructure repository for the talk: "Lesson Learned: Things You Should Know Before Your First IaC Setup" at OpenInfra Days 2025.
This repo demonstrates a first-hand experience implementing Infrastructure as Code using OpenTofu with OpenStack — covering provider authentication, remote state management via Swift (S3-compatible), and compute instance provisioning through a reusable module.
Resources: Linktree — Sintia In OID 2025 · Presentation slides
- Overview
- Key Lessons
- Project Structure
- State Management
- Module: nova
- Getting Started
- Important Notes
- References
What this repo demonstrates:
- First-time IaC setup experience using OpenTofu with OpenStack
- Provider authentication — different cloud providers have different auth mechanisms
- State management: migrating from local to remote (Swift/S3)
- Understanding the services you want to create: compute, network, storage, etc.
- Using
--targetto apply specific resources during development - Analyzing
planoutput before applying changes - Reusable nova module for compute instance provisioning
- Cloud-init user data for instance bootstrapping
The thesis: Getting assigned to set up IaC for a project can be nerve-wracking — especially for production. Understanding documentation, choosing the right provider, managing state properly, and knowing your target services are fundamentals that will save you hours of debugging later.
This repo was built alongside the talk to demonstrate real challenges faced during a first IaC implementation:
| Lesson | What I Learned |
|---|---|
| Documentation first | Read the provider docs thoroughly — small misconfigurations cause silent failures |
| Provider matters | Different cloud providers have different authentication methods (env vars, clouds.yaml, etc.) |
| State is sacred | Start with local state, migrate to remote (Swift/S3) once the setup is stable |
| Know your services | Understand what you're provisioning (compute, network, database) before writing config |
Use --target wisely |
Apply specific resources during development to iterate faster; don't forget to remove it |
| Plan before you apply | Always review plan output — it's your last chance to catch mistakes |
openstack-tofu/
├── main.tf # Root config: provider, backend, state container
├── io.tf # Root variables
├── terraform.auto.tfvars.example # Credentials template
├── .gitignore
│
├── modules/
│ └── nova/
│ ├── main.tf # Compute instance resource + keypair
│ ├── io.tf # Module variables & outputs
│ └── templates/ # Cloud-init user_data templates
│
└── README.md
The project uses an S3-compatible Swift backend to store Terraform state remotely:
terraform {
backend "s3" {
bucket = "openstack-state-bucket"
key = "dev/terraform.tfstate"
region = "RegionOne"
endpoint = "http://10.0.0.7:8080"
skip_credentials_validation = true
skip_metadata_api_check = true
force_path_style = true
}
}A dedicated Swift container is created for state storage:
resource "openstack_objectstorage_container_v1" "states_bucket" {
name = "openstack-state-buckets"
metadata = {
"purpose" = "terraform-state"
}
}To use local state instead, comment out the
backend "s3"block and uncommentbackend "local"inmain.tf.
The modules/nova/ module provisions an OpenStack compute instance via the OpenStack Nova API.
| Variable | Description | Required |
|---|---|---|
instance_name |
Name of the OpenStack instance | yes |
image_name |
Image name used for booting the VM | yes |
flavor_name |
Flavor (instance type) used | yes |
key_name |
SSH keypair name registered in OpenStack | yes |
security_group_name |
Security group name for the VM | yes |
network_id |
Network UUID to attach to the instance | yes |
hostname |
Optional hostname override | no |
user_data |
Cloud-init template file and variables | yes |
common_tags |
Additional metadata tags to apply | no |
| Output | Description |
|---|---|
instance_id |
ID of the created instance |
instance_name |
Name of the created instance |
instance_ip |
First IP address of the instance |
- OpenTofu 1.6+
- Access to an OpenStack cloud (Keystone v3 auth)
- OpenStack credentials (username, password, tenant, auth URL)
# 1. Clone the repo
git clone https://github.com/sintiasnn/openstack-tofu.git
cd openstack-tofu
# 2. Configure credentials
cp terraform.auto.tfvars.example terraform.auto.tfvars
# 3. Edit terraform.auto.tfvars with your OpenStack credentials:
# user_name = "your-username"
# tenant_name = "your-tenant"
# password = "your-password"
# auth_url = "https://your-openstack-auth-url:5000/v3"
# region = "RegionOne"
# 4. Initialize and apply
tofu init
tofu plan
tofu apply# Apply only specific resources during development
tofu apply -target=openstack_objectstorage_container_v1.states_bucket
# Always review the plan before applying
tofu plantofu workspace new staging
tofu workspace select staging
tofu apply⚠️ This repo is a demo for the OpenInfra Days 2025 talk — not production-ready without review.⚠️ Different OpenStack providers may have different authentication methods. Check your provider's docs.⚠️ Credentials interraform.auto.tfvarsare not tracked by git (.gitignoreexcludes*.tfvarsfiles), but keep them secure.⚠️ Start withbackend "local"first, then migrate to remote state once stable.- ✅ Always run
tofu planand review the output beforetofu apply. - ✅ Use the
--targetflag during development, but don't rely on it in production.
Ni Putu Sintia Wati
- GitHub: @sintiasnn
- Talk: OpenInfra Days 2025 — Lesson Learned: Things You Should Know Before Your First IaC Setup