# Terraform and OpenTofu on Quake AI

Source: https://docs.quake.ai/docs/automation/concepts/terraform
Markdown: https://docs.quake.ai/docs/automation/concepts/terraform.md

---

# Terraform and OpenTofu on Quake AI

Terraform and OpenTofu use HashiCorp Configuration Language (HCL) to define infrastructure as code. You describe the resources you want (instances, networks, volumes, security groups) in `.tf` files, and the tool creates, updates, or destroys them to match your declared state. Both tools use the same OpenStack provider and produce identical results on Quake AI.

For a comparison of OpenTofu and Terraform, see [IaC on Quake AI](/docs/automation/concepts/iac-comparison). This page focuses on how Terraform and OpenTofu work with Quake AI specifically: provider configuration, authentication, state management, and the resource types available.

## The OpenStack provider

Terraform and OpenTofu interact with Quake AI through the [OpenStack provider](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs). The provider translates HCL resource definitions into OpenStack API calls.

Declare the provider in your `main.tf`:

```hcl
terraform {
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 2.0"
    }
  }
}

provider "openstack" {}
```

The empty `provider "openstack" {}` block tells the provider to read credentials from environment variables, which is the recommended approach.

## Authentication

The provider supports two authentication methods. Both use application credentials generated in the Quake AI console.

### Environment variables (recommended)

Source your application credential file before running any Terraform command:

```bash
source ~/openrc.sh
terraform plan
```

The provider reads `OS_AUTH_URL`, `OS_APPLICATION_CREDENTIAL_ID`, and `OS_APPLICATION_CREDENTIAL_SECRET` from the environment. This keeps credentials out of your `.tf` files and version control.

### Explicit provider configuration

For CI/CD pipelines or environments where sourcing a file is impractical, pass credentials directly:

```hcl
provider "openstack" {
  auth_url                      = "https://keystone.rumble.cloud/v3"
  application_credential_id     = var.credential_id
  application_credential_secret = var.credential_secret
}
```

Use Terraform variables or a secrets manager to inject the values; never hardcode credentials in `.tf` files.



Do not mix environment variables with explicit provider credentials. If both are present, explicit values take precedence, which can cause confusing authentication scope mismatches.



## State management

Terraform tracks the real-world state of your infrastructure in a **state file** (`terraform.tfstate`). This file maps each HCL resource to the corresponding OpenStack resource ID, enabling Terraform to detect drift and plan changes accurately.

### Local state (default)

By default, the state file lives in the working directory. This works for personal projects but breaks down when multiple people or CI pipelines manage the same infrastructure.

### Remote state on Quake AI

Store state in Quake AI object storage for team access and state locking:

```hcl
terraform {
  backend "s3" {
    bucket   = "terraform-state"
    key      = "production/terraform.tfstate"
    endpoint = "https://object.us-east-1.rumble.cloud"  # replace with your region
    region   = "us-east-1"                         # us-east-1 | us-east-2 | us-west-1

    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
  }
}
```

Generate S3 credentials through the console (see [Create S3 credentials](/docs/object/how-to/create-s3-credentials)) and export them as `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` before running `terraform init`.

## Common resource types

The OpenStack provider maps Quake AI services to Terraform resource types. These are the resources you use most frequently:

### Compute

| Resource | Purpose |
|---|---|
| `openstack_compute_instance_v2` | Create and manage virtual machine instances |
| `openstack_compute_keypair_v2` | Import SSH public keys for instance access |
| `openstack_compute_servergroup_v2` | Define affinity and anti-affinity placement policies |
| `openstack_images_image_v2` (data source) | Look up available OS images by name |
| `openstack_compute_flavor_v2` (data source) | Look up instance sizes by name |

### Network

| Resource | Purpose |
|---|---|
| `openstack_networking_network_v2` | Create private networks |
| `openstack_networking_subnet_v2` | Define subnets with CIDR ranges and DNS |
| `openstack_networking_router_v2` | Create routers for internet and inter-network routing |
| `openstack_networking_router_interface_v2` | Connect subnets to routers |
| `openstack_networking_floatingip_v2` | Allocate public IP addresses |
| `openstack_networking_secgroup_v2` | Create security groups |
| `openstack_networking_secgroup_rule_v2` | Define firewall rules |
| `openstack_networking_port_v2` | Create network ports with fixed IPs |

### Storage

| Resource | Purpose |
|---|---|
| `openstack_blockstorage_volume_v3` | Create block storage volumes |
| `openstack_compute_volume_attach_v2` | Attach volumes to instances |

### Public application entry points

| Resource | Purpose |
|---|---|
| `openstack_networking_port_v2` | Create a dedicated port for an edge proxy or API gateway instance |
| `openstack_networking_floatingip_v2` | Allocate a stable public address for the edge instance |
| `openstack_networking_floatingip_associate_v2` | Associate the public address with the edge instance port |
| `openstack_networking_secgroup_rule_v2` | Allow HTTP, HTTPS, and restricted administration traffic |

### Automation (legacy Heat)

| Resource | Purpose |
|---|---|
| `openstack_orchestration_stack_v1` | Manage existing Heat stacks from OpenTofu |

## The plan/apply workflow

<Figure size="sm" caption="Lifecycle of a Terraform/OpenTofu project: init once, then loop plan and apply; destroy is the explicit teardown">

```mermaid
stateDiagram-v2
    accTitle: OpenTofu/Terraform plan-apply-destroy lifecycle
    accDescr: A project moves from init through repeated plan and apply cycles, with destroy as the explicit teardown path

    [*] --> Init: tofu init
    Init --> Planned: tofu plan
    Planned --> Applied: tofu apply
    Applied --> Planned: edit .tf
    Applied --> Destroyed: tofu destroy
    Destroyed --> [*]
```

</Figure>

Each infrastructure change follows the same cycle:

1. **`terraform init`**: download the OpenStack provider plugin and configure the backend. Run once per project or when you change providers.
2. **`terraform plan`**: compare the declared state in your `.tf` files against the real state in `terraform.tfstate`. Terraform prints a diff showing what it creates, modifies, or destroys.
3. **`terraform apply`**: execute the planned changes. Terraform prompts for confirmation before making any API calls.
4. **`terraform destroy`**: tear down all resources managed by the current configuration. Use this to clean up test environments.

Review the plan output before applying. Terraform distinguishes between in-place updates (modifying a resource's attributes) and replacements (destroying and recreating a resource). Replacements can cause downtime; look for `forces replacement` in the plan output.

## Project structure

A typical Quake AI Terraform project splits configuration across files by concern:

```text
.
├── main.tf           # Provider configuration
├── variables.tf      # Input variables
├── data.tf           # Data sources (images, networks, flavors)
├── compute.tf        # Instance definitions
├── network.tf        # Networks, subnets, routers, security groups
├── storage.tf        # Volumes and attachments
├── outputs.tf        # Output values (IPs, IDs)
└── terraform.tfvars  # Variable values (not committed to version control)
```

Terraform loads all `.tf` files in the working directory automatically; the file names are for human organization, not tool requirements.

## Operational best practices

**Pin the provider version.** Use `version = "~> 2.0"` to allow patch updates while preventing breaking changes. Run `terraform init -upgrade` when you want to pick up a new minor version.

**Use variables for everything that changes between environments.** Instance counts, flavors, network CIDRs, and image names should be variables. Hardcoded values create drift between staging and production.

**Use `terraform.tfvars` for environment-specific values.** Keep one `.tfvars` file per environment and pass it with `terraform plan -var-file=production.tfvars`.

**Never commit `terraform.tfstate` or `.tfvars` files.** The state file contains resource IDs and may contain sensitive attributes. The `.tfvars` file may contain credentials. Add both to `.gitignore`.

**Use anti-affinity server groups.** When deploying multiple instances of the same role, place them in a `soft-anti-affinity` server group. This distributes instances across physical hosts for fault tolerance.

**Tag resources consistently.** Use the `tags` attribute on networks, ports, and other resources that support it. Tags make it possible to identify Terraform-managed resources in the console and CLI.

## Further reading

**On this platform:**

- [IaC on Quake AI](/docs/automation/concepts/iac-comparison): comparison of OpenTofu and Terraform
- [How to create application credentials](/docs/tools/generate-app-credentials): generate the credentials Terraform needs
- [Simple VM Terraform example](/docs/automation/how-to/terraform-simple): minimal working configuration
- [Full-stack Terraform example](/docs/automation/how-to/terraform-full-stack): multi-tier infrastructure with a self-managed edge proxy
- [Validated IaC templates](/docs/platform/validation#how-infrastructure-templates-are-checked) in the [template library](/resources/iac-templates)
- [Terraform error handling](/docs/automation/how-to/terraform-error-handling): diagnose common Terraform failures

**External resources:**

- [OpenStack Terraform provider documentation](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs): full resource and data source reference
- [Terraform documentation](https://developer.hashicorp.com/terraform/docs): language reference, CLI commands, state management
- [OpenTofu documentation](https://opentofu.org/docs/): open-source fork with identical syntax and provider support
