- Prerequisites
- Initialize an OpenTofu state as a backend by using GitLab CI/CD
- Access the state from your local machine
- Migrate to a GitLab-managed OpenTofu state
- Use your GitLab backend as a remote data source
- Manage OpenTofu state files
- Related topics
GitLab-managed Terraform/OpenTofu state
- Support for state names that contain periods introduced in GitLab 15.7 with a flag named
allow_dots_on_tf_state_names
. Disabled by default. - Support for state names that contain periods generally available in GitLab 16.0. Feature flag
allow_dots_on_tf_state_names
removed.
OpenTofu uses state files to store details about your infrastructure configuration. With OpenTofu remote backends, you can store the state file in a remote and shared store.
GitLab provides an OpenTofu HTTP backend to securely store your state files with minimal configuration. The OpenTofu state backend provides automatic versioning and encryption of the state files managed by the GitLab instance.
Prerequisites
For self-managed GitLab, before you can use GitLab for your OpenTofu state files:
- An administrator must set up Terraform/OpenTofu state storage.
- You must turn on the Infrastructure menu for your project:
- Go to Settings > General.
- Expand Visibility, project features, permissions.
- Under Infrastructure, turn on the toggle.
Initialize an OpenTofu state as a backend by using GitLab CI/CD
Prerequisites:
- To lock, unlock, and write to the state by using
tofu apply
, you must have at least the Maintainer role. - To read the state by using
tofu plan -lock=false
, you must have at least the Developer role.
plan.json
or plan.cache
files include sensitive data like passwords, access tokens, or certificates, you should
encrypt the plan output or modify the project visibility settings. You should also disable
public pipelines
and set the artifact’s public flag to false (public: false
).
This setting ensures artifacts are accessible only to GitLab administrators and project members with at least the Reporter role.To configure GitLab CI/CD as a backend:
-
In your OpenTofu project, in a
.tf
file likebackend.tf
, define the HTTP backend:terraform { backend "http" { } }
- In the root directory of your project repository, create a
.gitlab-ci.yml
file. Use the OpenTofu CI/CD component to form your.gitlab-ci.yml
file. - Push your project to GitLab. This action triggers a pipeline, which
runs the
gitlab-tofu init
,gitlab-tofu validate
, andgitlab-tofu plan
commands. - Trigger the manual
deploy
job from the previous pipeline. This action runs thegitlab-tofu apply
command, which provisions the defined infrastructure.
The output from the above commands should be viewable in the job logs.
The gitlab-tofu
CLI is a wrapper around the tofu
CLI.
Customizing your OpenTofu environment variables
You can use OpenTofu HTTP configuration variables when you define your CI/CD jobs.
To customize your init
and override the OpenTofu configuration,
use environment variables instead of the init -backend-config=...
approach.
When you use -backend-config
, the configuration is:
- Cached in the output of the
plan
command. - Usually passed forward to the
apply
command.
This configuration can lead to problems like being unable to lock the state files in CI jobs.
Access the state from your local machine
You can access the GitLab-managed OpenTofu state from your local machine.
- Ensure the OpenTofu state has been initialized for CI/CD.
-
Copy a pre-populated OpenTofu
init
command:- On the left sidebar, select Search or go to and find your project.
- Select Operate > Terraform states.
- Next to the environment you want to use, select Actions () and select Copy Terraform init command.
- Open a terminal and run this command on your local machine.
Migrate to a GitLab-managed OpenTofu state
OpenTofu supports copying the state when the backend changes or is reconfigured. Use these actions to migrate from another backend to GitLab-managed OpenTofu state.
You should use a local terminal to run the commands needed for migrating to GitLab-managed OpenTofu state.
The following example demonstrates how to change the state name. The same workflow is needed to migrate to GitLab-managed OpenTofu state from a different state storage backend.
You should run these commands on your local machine.
Set up the initial backend
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/old-state-name"
tofu init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
Initializing the backend...
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
re-run this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Change the backend
Now that tofu init
has created a .terraform/
directory that knows where
the old state is, you can tell it about the new location:
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/new-state-name"
terraform init \
-migrate-state \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
Initializing the backend...
Backend configuration changed!
Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "http" backend to the
newly configured "http" backend. No existing state was found in the newly
configured "http" backend. Do you want to copy this state to the new "http"
backend? Enter "yes" to copy and "no" to start with an empty state.
Enter a value: yes
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
If you type yes
, it copies your state from the old location to the new
location. You can then go back to running it in GitLab CI/CD.
Use your GitLab backend as a remote data source
You can use a GitLab-managed OpenTofu state backend as an OpenTofu data source.
-
In your
main.tf
or other relevant file, declare these variables. Leave the values empty.variable "example_remote_state_address" { type = string description = "Gitlab remote state file address" } variable "example_username" { type = string description = "Gitlab username to query remote state" } variable "example_access_token" { type = string description = "GitLab access token to query remote state" }
-
To override the values from the previous step, create a file named
example.auto.tfvars
. This file should not be versioned in your project repository.example_remote_state_address = "https://gitlab.com/api/v4/projects/<TARGET-PROJECT-ID>/terraform/state/<TARGET-STATE-NAME>" example_username = "<GitLab username>" example_access_token = "<GitLab personal access token>"
-
In a
.tf
file, define the data source by using OpenTofu input variables:data "terraform_remote_state" "example" { backend = "http" config = { address = var.example_remote_state_address username = var.example_username password = var.example_access_token } }
-
address: The URL of the remote state backend you want to use as a data source.
For example,
https://gitlab.com/api/v4/projects/<TARGET-PROJECT-ID>/terraform/state/<TARGET-STATE-NAME>
. -
username: The username to authenticate with the data source. If you are using
a personal access token for
authentication, this value is your GitLab username. If you are using GitLab CI/CD, this value is
'gitlab-ci-token'
. -
password: The password to authenticate with the data source. If you are using a personal access token for
authentication, this value is the token value (the token must have the API scope).
If you are using GitLab CI/CD, this value is the contents of the
${CI_JOB_TOKEN}
CI/CD variable.
-
address: The URL of the remote state backend you want to use as a data source.
For example,
Outputs from the data source can now be referenced in your Terraform resources
using data.terraform_remote_state.example.outputs.<OUTPUT-NAME>
.
To read the OpenTofu state in the target project, you need at least the Developer role.
Manage OpenTofu state files
To view OpenTofu state files:
- On the left sidebar, select Search or go to and find your project.
- Select Operate > Terraform states.
An epic exists to track improvements to this UI.
Manage individual OpenTofu state versions
Individual state versions can be managed using the GitLab REST API.
If you have at least the Developer role, you can retrieve state versions by using their serial number::
curl --header "Private-Token: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version-serial>"
If you have at least the Maintainer role, you can remove state versions by using their serial number:
curl --header "Private-Token: <your_access_token>" --request DELETE "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version-serial>"
Remove a state file
If you have at least the Maintainer role, you can remove a state file.
- On the left sidebar, select Operate > Terraform states.
- In the Actions column, select Actions () and then Remove state file and versions.
Remove a state file by using the API
You can remove a state file by making a request to the REST API using a personal access token:
curl --header "Private-Token: <your_access_token>" --request DELETE "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"
You can also use CI/CD job token and basic authentication:
curl --user "gitlab-ci-token:$CI_JOB_TOKEN" --request DELETE "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"
You can also use the GraphQL API.