|
| 1 | +--- |
| 2 | +title: "How to use Terraform with OPCP" |
| 3 | +excerpt: "Learn how to generate an Application Credential from Horizon and automate the deployment of your OPCP resources with Terraform" |
| 4 | +updated: 2026-04-29 |
| 5 | +--- |
| 6 | + |
| 7 | +## Objective |
| 8 | + |
| 9 | +[Terraform](https://www.terraform.io/) is an open source **Infrastructure as Code (IaC)** tool developed by [HashiCorp](https://www.hashicorp.com/). It allows you to describe and provision your infrastructure declaratively from configuration files written in *HashiCorp Configuration Language* (HCL). |
| 10 | + |
| 11 | +Since the **OPCP** offer is based on **OpenStack**, you can use the **Terraform OpenStack provider** to automate the deployment of your resources: instances, networks, volumes, key pairs, etc. |
| 12 | + |
| 13 | +> [!primary] |
| 14 | +> This guide also applies to [**OpenTofu**](https://opentofu.org/), the open source fork of Terraform maintained by the Linux Foundation. OpenTofu is compatible with the HCL syntax and Terraform providers: simply replace the `terraform` command with `tofu` in the examples below. |
| 15 | +
|
| 16 | +**This guide details the steps required to generate an *Application Credential* from Horizon, configure Terraform and deploy a first server on your OPCP infrastructure.** |
| 17 | + |
| 18 | +## Requirements |
| 19 | + |
| 20 | +- An active [OPCP](/links/hosted-private-cloud/onprem-cloud-platform) service. |
| 21 | +- A **user account** with sufficient rights to log in to Horizon on the OPCP offer. |
| 22 | +- [Terraform installed](https://developer.hashicorp.com/terraform/install) (version >= 1.0) or [OpenTofu](https://opentofu.org/docs/intro/install/) on your workstation. |
| 23 | +- An **SSH key pair** on your local workstation to access your instance. |
| 24 | +- A **private network** previously created in your OPCP project (see the guide [How to install an instance from the Horizon interface](/pages/hosted_private_cloud/opcp/opcp-setup-instance)). |
| 25 | + |
| 26 | +## Instructions |
| 27 | + |
| 28 | +### 1. Creating an Application Credential from Horizon |
| 29 | + |
| 30 | +To allow Terraform to communicate with your OPCP infrastructure, you need to generate an **Application Credential** pair (`id` / `secret`) from the Horizon interface. This mechanism avoids using your Keycloak credentials directly and provides dedicated authentication for your automation workflows, with a permissions scope limited to the current project. |
| 31 | + |
| 32 | +#### Logging in to Horizon |
| 33 | + |
| 34 | +Log in to the **Horizon** interface of your OPCP environment, then select the **project** in which you want to deploy your resources via Terraform. For more information, refer to the [Getting started with your OPCP](/pages/hosted_private_cloud/opcp/opcp-getting-started) guide. |
| 35 | + |
| 36 | +#### Creating the Application Credential |
| 37 | + |
| 38 | +In the left-hand menu, click on `Identity`{.action}, then on `Application Credentials`{.action}.<br><br> |
| 39 | +{.thumbnail} |
| 40 | + |
| 41 | +Click on `+ Create Application Credential`{.action}.<br><br> |
| 42 | +{.thumbnail} |
| 43 | + |
| 44 | +Fill in the following fields: |
| 45 | + |
| 46 | +| Field | Description | |
| 47 | +|--------|--------------| |
| 48 | +| **Name** | Enter a name for your Application Credential (e.g.: *terraform-cred*). | |
| 49 | +| **Description** | Optional. Add a description if needed. | |
| 50 | +| **Secret** | Optional. If left blank, a secret will be generated automatically. | |
| 51 | +| **Expiration Date / Expiration Time** | Optional. Set an expiration date. | |
| 52 | +| **Roles** | Select the roles to associate with the credential (e.g.: *member*, *admin*). | |
| 53 | +| **Access Rules** | Optional. Allows you to restrict the authorised actions. | |
| 54 | +| **Unrestricted** | Leave unchecked to limit the possible actions. | |
| 55 | + |
| 56 | +Click on `Create Application Credential`{.action}. |
| 57 | + |
| 58 | +> [!warning] |
| 59 | +> Once the window is closed, the **secret will no longer be accessible**. Download the `clouds.yaml` or `openrc` file offered by Horizon, or copy the `id` and `secret` values to a secure location. |
| 60 | +
|
| 61 | +{.thumbnail} |
| 62 | + |
| 63 | +> [!primary] |
| 64 | +> For the rest of this tutorial, **download the `openrc` file**: it will be used in the next step to authenticate Terraform against your OPCP infrastructure. |
| 65 | +
|
| 66 | +### 2. Preparing the Terraform environment |
| 67 | + |
| 68 | +#### Creating the working directory |
| 69 | + |
| 70 | +Create a directory dedicated to your Terraform project: |
| 71 | + |
| 72 | +```bash |
| 73 | +mkdir terraform-opcp && cd terraform-opcp |
| 74 | +``` |
| 75 | + |
| 76 | +#### Defining the OpenStack provider |
| 77 | + |
| 78 | +In a file named `provider.tf`, add the following lines: |
| 79 | + |
| 80 | +```hcl |
| 81 | +terraform { |
| 82 | + required_version = ">= 1.0" |
| 83 | + required_providers { |
| 84 | + openstack = { |
| 85 | + source = "terraform-provider-openstack/openstack" |
| 86 | + version = ">= 3.0.0" |
| 87 | + } |
| 88 | + } |
| 89 | +} |
| 90 | +
|
| 91 | +provider "openstack" { |
| 92 | + |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +No parameters are required in the `provider`{.action} block: the OpenStack provider automatically retrieves the authentication information from the `OS_*` environment variables. |
| 97 | + |
| 98 | +#### Loading OpenStack environment variables |
| 99 | + |
| 100 | +When you created your Application Credential, Horizon offered to download a `clouds.yaml` or `openrc` file. The simplest approach is to source this `openrc.sh` file in your shell before running Terraform: |
| 101 | + |
| 102 | +```bash |
| 103 | +source openrc.sh |
| 104 | +``` |
| 105 | + |
| 106 | +> [!primary] |
| 107 | +> The `openrc.sh` file exports `OS_AUTH_URL`, `OS_REGION_NAME`, `OS_APPLICATION_CREDENTIAL_ID` and `OS_APPLICATION_CREDENTIAL_SECRET`, among others. These variables will automatically be used by the Terraform OpenStack provider. |
| 108 | +
|
| 109 | +#### Initialisation |
| 110 | + |
| 111 | +Download the OpenStack provider plugins: |
| 112 | + |
| 113 | +```bash |
| 114 | +terraform init |
| 115 | +``` |
| 116 | + |
| 117 | +### 3. Creating a server |
| 118 | + |
| 119 | +In a `main.tf` file, declare the resources required to create an instance attached to an existing private network: |
| 120 | + |
| 121 | +```hcl |
| 122 | +# Variables related to the instance |
| 123 | +variable "instance_name" { |
| 124 | + description = "Name of the instance that will be created in OPCP" |
| 125 | + type = string |
| 126 | + default = "instance-terraform-name" |
| 127 | +} |
| 128 | +
|
| 129 | +variable "image_name" { |
| 130 | + description = "Name of the image to use for the instance (e.g.: Debian 12 OPCP)" |
| 131 | + type = string |
| 132 | + default = "Debian 12 OPCP" |
| 133 | +} |
| 134 | +
|
| 135 | +variable "flavor_name" { |
| 136 | + description = "Baremetal flavor defining the hardware resources of the instance (e.g.: scale-1, scale-2, etc.)" |
| 137 | + type = string |
| 138 | + default = "scale-1" |
| 139 | +} |
| 140 | +
|
| 141 | +variable "network_name" { |
| 142 | + description = "Name of the existing network to which the instance will be attached" |
| 143 | + type = string |
| 144 | + default = "<your-network-name>" |
| 145 | +} |
| 146 | +
|
| 147 | +variable "key_name" { |
| 148 | + description = "Name of the SSH key pair to associate with the instance" |
| 149 | + type = string |
| 150 | + default = "terraform-key" |
| 151 | +} |
| 152 | +
|
| 153 | +# Creating an instance |
| 154 | +resource "openstack_compute_instance_v2" "terraform_instance" { |
| 155 | + name = var.instance_name |
| 156 | + image_name = var.image_name |
| 157 | + flavor_name = var.flavor_name |
| 158 | + key_pair = var.key_name |
| 159 | +
|
| 160 | + network { |
| 161 | + name = var.network_name |
| 162 | + } |
| 163 | +
|
| 164 | + lifecycle { |
| 165 | + # Prevents Terraform from detecting drift when the base image is updated |
| 166 | + ignore_changes = [ |
| 167 | + image_name |
| 168 | + ] |
| 169 | + } |
| 170 | +
|
| 171 | + # Useful metadata |
| 172 | + metadata = { |
| 173 | + environment = "production" |
| 174 | + managed_by = "terraform" |
| 175 | + } |
| 176 | +
|
| 177 | + # Longer timeouts (baremetal provisioning is slow) |
| 178 | + timeouts { |
| 179 | + create = "60m" |
| 180 | + delete = "30m" |
| 181 | + } |
| 182 | +} |
| 183 | +
|
| 184 | +# Useful outputs after creation |
| 185 | +output "instance_id" { |
| 186 | + value = openstack_compute_instance_v2.terraform_instance.id |
| 187 | +} |
| 188 | +
|
| 189 | +output "instance_ip" { |
| 190 | + value = openstack_compute_instance_v2.terraform_instance.access_ip_v4 |
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +> [!primary] |
| 195 | +> The names of available images, flavors and networks can be listed from Horizon or with the OpenStack CLI (`openstack image list`, `openstack flavor list`, `openstack network list`). To configure the CLI, refer to the guide [How to use the API and get credentials](/pages/hosted_private_cloud/opcp/opcp-use-api-get-credentials). |
| 196 | +
|
| 197 | +#### Reviewing the plan |
| 198 | + |
| 199 | +Before any deployment, preview the actions that will be performed: |
| 200 | + |
| 201 | +```bash |
| 202 | +terraform plan |
| 203 | +``` |
| 204 | + |
| 205 | +#### Applying the configuration |
| 206 | + |
| 207 | +Deploy the instance with the following command: |
| 208 | + |
| 209 | +```bash |
| 210 | +terraform apply |
| 211 | +``` |
| 212 | + |
| 213 | +Confirm with `yes` when Terraform asks you to. Once the creation is complete, the instance is visible in the Horizon interface, in the `Compute`{.action} > `Instances`{.action} section. |
| 214 | + |
| 215 | +### 4. Additional node-level configurations (RAID, LACP) |
| 216 | + |
| 217 | +Some configurations must be applied **on the baremetal node** before deploying the instance and are not covered by the Terraform OpenStack provider. They require **admin** Ironic rights (or nodes transferred to your project) and must be performed via the OpenStack CLI. |
| 218 | + |
| 219 | +> [!primary] |
| 220 | +> **Software RAID**: to configure software RAID on a baremetal node, refer to the guide [How to set up software RAID on a node](/pages/hosted_private_cloud/opcp/how-to-setup-softraid-on-node). The `target_raid_config` attribute is not exposed by the `openstack_baremetal_node_v1` resource. This operation must be performed **before** the `terraform apply` that deploys the instance, and the configured node should then be targeted via `availability_zone = "nova::<node-id>"`. |
| 221 | +
|
| 222 | +> [!primary] |
| 223 | +> **LACP / bonding**: to aggregate several network interfaces of a node, refer to the guide [How to set up LACP on a node](/pages/hosted_private_cloud/opcp/how-to-setup-lacp-on-node). Baremetal port and bonding configuration cannot be managed declaratively by the Terraform OpenStack provider. This operation must be performed **before** the `terraform apply` that deploys the instance. |
| 224 | +
|
| 225 | +### 5. Removing the infrastructure |
| 226 | + |
| 227 | +To delete all resources created via Terraform: |
| 228 | + |
| 229 | +```bash |
| 230 | +terraform destroy |
| 231 | +``` |
| 232 | + |
| 233 | +> [!warning] |
| 234 | +> `terraform destroy` does not reset the RAID or LACP configurations applied to the node. To remove them, follow the dedicated section of the corresponding guide using the OpenStack CLI. |
| 235 | +
|
| 236 | +### 6. Troubleshooting |
| 237 | + |
| 238 | +| Issue | Possible cause | Solution | |
| 239 | +|-----------|----------------|-----------| |
| 240 | +| `Authentication failed` | Wrong `application_credential_id` or `secret` | Check the credentials in Horizon (`Identity`{.action} > `Application Credentials`{.action}). | |
| 241 | +| `Could not find image` | The image name does not match | List the available images via `openstack image list` or from Horizon. | |
| 242 | +| `No suitable endpoint could be found` | Wrong `auth_url` URL or non-existent region | Check the Keystone URL and the region in `Project`{.action} > `API Access`{.action}. | |
| 243 | +| `Network not found` | Private network missing in the project | Create a private network beforehand from Horizon (`Network`{.action} > `Networks`{.action}). | |
| 244 | + |
| 245 | +### 7. References |
| 246 | + |
| 247 | +- [Official Terraform documentation](https://developer.hashicorp.com/terraform) |
| 248 | +- [Official OpenTofu documentation](https://opentofu.org/docs/) |
| 249 | +- [Terraform OpenStack provider](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs) |
| 250 | +- [openstack_compute_instance_v2 resource](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/compute_instance_v2) |
| 251 | +- [OpenStack Application Credentials](https://docs.openstack.org/keystone/latest/user/application_credentials.html) |
| 252 | + |
| 253 | +## Go further |
| 254 | + |
| 255 | +If you need training or technical assistance for the implementation of our solutions, contact your sales representative or click [this link](/links/professional-services) to request a quote and have your project analyzed by our Professional Services team experts. |
| 256 | + |
| 257 | +Join our [community of users](/links/community). |
0 commit comments