Uploading Terraform states to Yandex Object Storage
This guide describes the steps for uploading a Terraform state to Object Storage.
A Terraform state describes the current deployed infrastructure and is stored in files with the .tfstate
extension. The state file is created after the infrastructure is deployed and can be immediately uploaded to Object Storage. The uploaded state file is updated as the infrastructure you created changes.
In this example, the saved state allows other users to get the ID of one of the created subnets to connect a new VM to it.
To configure Terraform state storage in Object Storage and use it to create new resources:
- Prepare your cloud.
- Required paid resources.
- Install and configure Terraform.
- Configure the backend.
- Deploy the configuration.
- Check the saved state.
- Retrieve the state from the backend.
If you no longer need the resources you created, delete them.
Terraform and its providers are distributed under the Business Source License
Prepare your cloud
Sign up for Yandex Cloud and create a billing account:
- Go to the management console
and log in to Yandex Cloud or create an account if you do not have one yet. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVE
orTRIAL_ACTIVE
status. If you do not have a billing account, create one.
If you have an active billing account, you can go to the cloud page
Learn more about clouds and folders.
Required paid resources
The cost of infrastructure support for uploading Terraform states to Yandex Object Storage includes data storage fees (see Object Storage pricing).
Follow this guide to create three VMs with public IP addresses, a virtual network, and two subnets representing an example of an infrastructure deployed through Terraform. The cost of supporting this infrastructure includes:
- Fee for disks and continuously running VMs (see Yandex Compute Cloud pricing).
- Fee for using a dynamic public IP address (see Yandex Virtual Private Cloud pricing).
Create a service account and static access key
- Create a service account with the editor role for the folder specified in the provider settings.
- Get a static access key. Save the key ID and secret key: you will need them at the next steps.
Create a bucket
Create a bucket with restricted access. This bucket will store the Terraform state file.
Install and configure Terraform
Install Terraform
Use one of the following methods:
-
Download the Terraform distribution
and follow this guide to install it. -
Install Terraform using the Chocolatey
package manager and the command below:choco install terraform
Download the Terraform distribution
Use one of the following methods:
-
Download the Terraform distribution
and follow this guide to install it. -
Install Terraform using the Homebrew
package manager and the command below:brew install terraform
Get the authentication credentials
Use a service account to manage the Yandex Cloud infrastructure using Terraform. It will help you flexibly configure access permissions to resources.
You can also access Terraform from your Yandex account,, or a federated account, but this method is less secure. For more information, see the end of this section.
-
If you do not have the Yandex Cloud command line interface, install it.
-
Set up the CLI profile to run operations on behalf of the service account:
CLI-
Create an authorized key for your service account and save the file:
yc iam key create \ --service-account-id <service_account_ID> \ --folder-name <service_account_folder_name> \ --output key.json
Where:
service-account-id
: Service account ID.folder-name
: Name of the folder in which the service account was created.output
: Name of the file with the authorized key.
Result:
id: aje8nn871qo4******** service_account_id: ajehr0to1g8b******** created_at: "2022-09-14T09:11:43.479156798Z" key_algorithm: RSA_2048
-
Create a CLI profile to run operations on behalf of the service account. Name the profile:
yc config profile create <profile_name>
Result:
Profile 'sa-terraform' created and activated
-
Set the profile configuration:
yc config set service-account-key key.json yc config set cloud-id <cloud_ID> yc config set folder-id <folder_ID>
Where:
-
-
Add the credentials to the environment variables:
BashPowerShellexport YC_TOKEN=$(yc iam create-token) export YC_CLOUD_ID=$(yc config get cloud-id) export YC_FOLDER_ID=$(yc config get folder-id)
Where:
YC_TOKEN
: IAM token.YC_CLOUD_ID
: Cloud ID.YC_FOLDER_ID
: Folder ID.
$Env:YC_TOKEN=$(yc iam create-token) $Env:YC_CLOUD_ID=$(yc config get cloud-id) $Env:YC_FOLDER_ID=$(yc config get folder-id)
Where:
YC_TOKEN
: IAM token.YC_CLOUD_ID
: Cloud ID.YC_FOLDER_ID
: Folder ID.
Note
The IAM token lifetime does not exceed 12 hours; however, we recommend requesting it more often, such as once per hour.
Managing resources on behalf of a Yandex account or a federated account
Warning
Managing resources under a user's Yandex account or federated account is less secure than under a service account.
If you do not have the Yandex Cloud command line interface yet, install and initialize it.
The folder specified in the CLI profile is used by default. You can specify a different folder using the --folder-name
or --folder-id
parameter.
If you use a federated account, authenticate with the CLI on behalf of the federated user.
Add the credentials to the environment variables:
export YC_TOKEN=$(yc iam create-token)
export YC_CLOUD_ID=$(yc config get cloud-id)
export YC_FOLDER_ID=$(yc config get folder-id)
Where:
YC_TOKEN
: IAM token.YC_CLOUD_ID
: Cloud ID.YC_FOLDER_ID
: Folder ID.
$Env:YC_TOKEN=$(yc iam create-token)
$Env:YC_CLOUD_ID=$(yc config get cloud-id)
$Env:YC_FOLDER_ID=$(yc config get folder-id)
Where:
YC_TOKEN
: IAM token.YC_CLOUD_ID
: Cloud ID.YC_FOLDER_ID
: Folder ID.
Note
The IAM token lifetime does not exceed 12 hours; however, we recommend requesting it more often, such as once per hour.
Create a Terraform configuration file
- Create a directory with any name, for example,
cloud-terraform
. It will store the Terraform configuration files. - Create a configuration file with the
.tf
extension in this directory, for example,example.tf
.
Configure a provider
Note
These settings apply to Terraform 0.13
and higher. We recommend using the latest stable version of Terraform.
-
If you previously configured a provider from the HashiCorp registry, save its settings:
Linux/macOSWindowsmv ~/.terraformrc ~/.terraformrc.old
mv $env:APPDATA/terraform.rc $env:APPDATA/terraform.rc.old
-
Specify the source the provider will be installed from.
Linux/macOSWindowsOpen the Terraform CLI configuration file:
nano ~/.terraformrc
Note
The
.terraformrc
file must be in the user's home root folder, e.g.,/home/user/
or/User/user/
.Open the Terraform CLI configuration file named
terraform.rc
in your user's%APPDATA%
folder.To find out the absolute path to the
%APPDATA%
folder, run theecho %APPDATA%
command for cmd or the$env:APPDATA
command for PowerShell.Add the following section to the file:
provider_installation { network_mirror { url = "https://terraform-mirror.yandexcloud.net/" include = ["registry.terraform.io/*/*"] } direct { exclude = ["registry.terraform.io/*/*"] } }
For more information about setting up mirrors, see the documentation
. -
Add the following sections at the top of the
.tf
configuration file:terraform { required_providers { yandex = { source = "yandex-cloud/yandex" } } required_version = ">= 0.13" } provider "yandex" { zone = "<default_availability_zone>" }
Where:
source
: Provider's global source address .required_version
: Minimum Terraform version the provider is compatible with.provider
: Provider name.zone
: Availability zone where all cloud resources will be created by default.
-
Run the
terraform init
command in the folder containing the.tf
configuration file. This command initializes the providers specified in the configuration files and allows you to work with the provider resources and data sources.
If the provider installation failed, create a support request
If you used the .terraform.lock.hcl
file, prior to the initialization, run the terraform providers lock
command specifying the URL of the mirror to upload the provider from and the platforms the configuration will run on:
terraform providers lock -net-mirror=https://terraform-mirror.yandexcloud.net -platform=<platform_1_name> -platform=<platform_2_name> yandex-cloud/yandex
Where:
-net-mirror
: Address of the mirror to upload the provider from.-platform
: Platforms to use the configuration on. The possible values include:windows_amd64
: 64-bit Windowslinux_amd64
: 64-bit Linuxdarwin_arm64
: 64-bit macOS
If you used the Terraform modules, first run terraform init
, then delete the lock file. After that, run the terraform providers lock
command.
For more information about the terraform providers lock
command, see the Terraform documentation
Configure the backend
Note
The backend settings apply to Terraform 1.6.3
and higher.
-
Add the previously obtained key ID and secret key to environment variables:
BashPowerShellexport ACCESS_KEY="<key_ID>" export SECRET_KEY="<secret_key>"
$ACCESS_KEY="<key_ID>" $SECRET_KEY="<secret_key>"
-
Add the provider and backend settings to the configuration file:
terraform { required_providers { yandex = { source = "yandex-cloud/yandex" } } backend "s3" { endpoints = { s3 = "https://storage.yandexcloud.net" } bucket = "<bucket_name>" region = "ru-central1" key = "<path_to_state_file_in_bucket>/<state_file_name>.tfstate" skip_region_validation = true skip_credentials_validation = true skip_requesting_account_id = true # This option is required for Terraform 1.6.1 or higher. skip_s3_checksum = true # This option is required to describe backend for Terraform version 1.6.3 or higher. } } provider "yandex" { zone = "<default_availability_zone>" }
To read more about the state storage backend, see the Terraform website
. -
Run the following command in the folder with the configuration file:
terraform init -backend-config="access_key=$ACCESS_KEY" -backend-config="secret_key=$SECRET_KEY"
Deploy the configuration
In this example, we will create two VMs: terraform1
and terraform2
. They will be connected to a subnet named subnet-1
in the ru-central1-a
availability zone. The subnet will belong to the network-1
cloud network.
The VMs will have different vCPU and RAM configurations: 1 vCPU and 2 GB of RAM for terraform1
and 2 vCPUs and 4 GB of RAM for terraform2
. The VMs will automatically get public and private IP addresses from the 192.168.10.0/24
range in subnet-1
. The VMs will run Ubuntu OS and host the public part of the key to enable SSH access to the VMs.
-
Save the following configuration to
example.tf
:terraform { required_providers { yandex = { source = "yandex-cloud/yandex" } } backend "s3" { endpoints = { s3 = "storage.yandexcloud.net" } bucket = "<bucket_name>" region = "ru-central1" key = "<path_to_state_file_in_bucket>/<state_file_name>.tfstate" skip_region_validation = true skip_credentials_validation = true skip_requesting_account_id = true # This option is required to describe backend for Terraform version 1.6.1 or higher. skip_s3_checksum = true # This option is required to describe backend for Terraform version 1.6.3 or higher. } } provider "yandex" { zone = "ru-central1-a" } resource "yandex_compute_image" "ubuntu_2004" { source_family = "ubuntu-2004-lts" } resource "yandex_compute_disk" "boot-disk-vm1" { name = "boot-disk-1" type = "network-hdd" zone = "ru-central1-a" size = "20" image_id = yandex_compute_image.ubuntu_2004.id } resource "yandex_compute_disk" "boot-disk-vm2" { name = "boot-disk-2" type = "network-hdd" zone = "ru-central1-a" size = "20" image_id = yandex_compute_image.ubuntu_2004.id } resource "yandex_compute_instance" "vm-1" { name = "terraform1" resources { cores = 2 memory = 2 } boot_disk { disk_id = yandex_compute_disk.boot-disk-vm1.id } network_interface { subnet_id = yandex_vpc_subnet.subnet-1.id nat = true } metadata = { ssh-keys = "ubuntu:${file("<path_to_public_SSH_key>")}" } } resource "yandex_compute_instance" "vm-2" { name = "terraform2" resources { cores = 2 memory = 4 } boot_disk { disk_id = yandex_compute_disk.boot-disk-vm2.id } network_interface { subnet_id = yandex_vpc_subnet.subnet-1.id nat = true } metadata = { ssh-keys = "ubuntu:${file("<path_to_public_SSH_key>")}" } } resource "yandex_vpc_network" "network-1" { name = "network1" } resource "yandex_vpc_subnet" "subnet-1" { name = "subnet1" zone = "ru-central1-a" network_id = yandex_vpc_network.network-1.id v4_cidr_blocks = ["192.168.10.0/24"] } output "internal_ip_address_vm_1" { value = yandex_compute_instance.vm-1.network_interface.0.ip_address } output "internal_ip_address_vm_2" { value = yandex_compute_instance.vm-2.network_interface.0.ip_address } output "external_ip_address_vm_1" { value = yandex_compute_instance.vm-1.network_interface.0.nat_ip_address } output "external_ip_address_vm_2" { value = yandex_compute_instance.vm-2.network_interface.0.nat_ip_address } output "subnet-1" { value = yandex_vpc_subnet.subnet-1.id }
Where:
bucket
: Bucket name.key
: Object key in the bucket (name and path to the Terraform state file in the bucket).ssh-keys
: Path to the file with a public SSH key to authenticate the user on the VM. For more information, see Creating an SSH key pair.
-
Check the configuration using the
terraform plan
command. -
Deploy the configuration using the
terraform apply
command.
Check the saved state
Make sure the state file is uploaded to Yandex Object Storage:
- Go to the management console
and select the folder containing the bucket you created. - Select Object Storage.
- In the bucket list, select the bucket you saved the Terraform state to.
- Make sure the state file is in the bucket.
Retrieve the state from the backend
You can request the Object Storage state saved in Terraform from another configuration to expand the infrastructure you created.
Create another configuration and use the saved state to create another VM in one of the existing subnets:
-
Create the
remote-state
directory. -
Go to the created directory and create the
remote-state.tf
configuration file:terraform { required_providers { yandex = { source = "yandex-cloud/yandex" } } } provider "yandex" { zone = "ru-central1-a" } data "terraform_remote_state" "vpc" { backend = "s3" config = { endpoints = { s3 = "https://storage.yandexcloud.net" } bucket = "<bucket_name>" region = "ru-central1" key = "<path_to_state_file_in_bucket>/<state_file_name>.tfstate" skip_region_validation = true skip_credentials_validation = true skip_requesting_account_id = true # This option is required to describe backend for Terraform version 1.6.1 or higher. access_key = "<key_ID>" secret_key = "<secret_key>" } } resource "yandex_compute_image" "ubuntu_2004" { source_family = "ubuntu-2004-lts" } resource "yandex_compute_disk" "boot-disk-vm3" { name = "boot-disk-3" type = "network-hdd" zone = "ru-central1-a" size = "20" image_id = yandex_compute_image.ubuntu_2004.id } resource "yandex_compute_instance" "vm-3" { name = "terraform3" resources { cores = 2 memory = 2 } boot_disk { disk_id = yandex_compute_disk.boot-disk-vm3.id } network_interface { subnet_id = data.terraform_remote_state.vpc.outputs.subnet-1 nat = true } metadata = { ssh-keys = "ubuntu:${file("<path_to_public_SSH_key>")}" } }
Where:
bucket
: Bucket name.key
: Object key in the bucket (name and path to the Terraform state file in the bucket).access_key
: Secret key ID of the service account to access the bucket.secret_key
: Service account secret key value.
-
Run the
terraform init
command. -
Run the
terraform plan
command. The terminal will display the plan for creating the VM. -
Run the
terraform apply
command. -
Go to the management console and make sure you can see the
terraform3
instance in the Compute Cloud section.
Delete the resources you created
To delete the resources you created, run the terraform destroy
command; start with the second configuration, and then proceed to the first.