Getting started with Terraform
With Terraform
For more information about the provider resources, see the documentation on the Terraform
If you change the configuration files, Terraform automatically determines which part of your configuration is already deployed and what should be added or removed.
To create your first infrastructure in Yandex Cloud using Terraform:
- Prepare your cloud.
- Install Terraform.
- Get the authentication data
- Create a Terraform configuration file.
- Configure a provider.
- Prepare an infrastructure plan.
- Check and format your configuration files.
- Create resources.
If you no longer need the resources, delete them.
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 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 resources created with Terraform includes:
- Fee for continuously running virtual machines (see Yandex Compute Cloud pricing).
- Fee for using a dynamic public IP address (see Yandex Virtual Private Cloud pricing).
Install Terraform
From a mirror
You can download a Terraform distribution for your platform from a mirrorPATH
variable:
export PATH=$PATH:/path/to/terraform
From the Hashicorp website
Use one of the following methods:
-
Download a Terraform distribution
and follow this guide to install it. -
Install Terraform using the Chocolatey
package manager and the command below:choco install terraform
Download a Terraform distribution
Use one of the following methods:
-
Download a 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 to flexibly configure access rights for 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.
-
If you do not have a service account, create one:
Management consoleCLIAPI-
In the management console
, select a folder where you want to create a service account. -
In the Service accounts tab, click Create service account.
-
Enter a name for the service account.
The name format requirements are as follows:
- The name must be from 3 to 63 characters long.
- It may contain lowercase Latin letters, numbers, and hyphens.
- The first character must be a letter and the last character cannot be a hyphen.
-
Click Create.
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.Run the command to create a service account:
yc iam service-account create --name <service_account_name>
Where
name
is the name of the service account in the following format:- The name must be from 3 to 63 characters long.
- It may contain lowercase Latin letters, numbers, and hyphens.
- The first character must be a letter and the last character cannot be a hyphen.
Result:
id: ajehr0to1g8b******** folder_id: b1gv87ssvu49******** created_at: "2022-09-14T09:03:11.665153755Z" name: sa-terraform
To create a service account, use the method ServiceAccountService/Create from the gRPC API or the create method for the
ServiceAccount
resource from the REST API. -
-
Assign, to the service account, the following roles needed to manage Yandex Cloud resources:
You can assign roles to a service account for any resources in any cloud if these resources belong to the same organization as the service account. You can also assign roles to a service account for the organization.
Management consoleCLIAPITo assign a service account a role for the folder:
- In the management console
, select the appropriate folder. - Go to the Access bindings tab.
- Click Assign bindings.
- In the window that opens, click
- Select the required service account from the list or use the search.
- Click
- Select a role in the folder.
- Click Save.
-
Find the ID of the service account you want to assign the role to (the
ID
column):yc iam service-account list
Result:
+----------------------+--------------+ | ID | NAME | +----------------------+--------------+ | aje6ij7qvdhb******** | sa-terraform | +----------------------+--------------+
-
Assign the service account the role for the resource.
yc <service_name> <resource_type> add-access-binding <resource_name_or_ID> \ --role <role> \ --subject serviceAccount:<service_account_ID>
Where:
<service_name>
: Name of the service for whose resource you want to assign the role, e.g.,resource-manager
.<resource_type>
: Resource category. E.g., for theresource-manager
service, specifycloud
to assign a role for the entire cloud orfolder
to assign a role for a folder.<resource_name_or_ID>
: Resource (cloud or folder) name or ID.<role>
: Assigned role, e.g.,resource-manager.editor
.<service_account_ID>
: ID of the service account the role is being assigned to.
For example:
yc resource-manager folder add-access-binding b1gv87ssvu49******** \ --role resource-manager.editor \ --subject serviceAccount:aje6ij7qvdhb********
Result:
done (1s)
To assign the service account a role for a cloud or folder, use the
updateAccessBindings
REST API method for the Cloud or Folder resource:-
Select a role to assign to the service account. You can find the description of the roles in the Yandex Identity and Access Management documentation in the Yandex Cloud role reference.
-
Get the ID of the service accounts folder.
-
Get an IAM token required for authorization in the Yandex Cloud API.
-
Get a list of folder service accounts to find out their IDs:
export FOLDER_ID=b1gvmob95yys******** export IAM_TOKEN=CggaATEVAgA... curl -H "Authorization: Bearer ${IAM_TOKEN}" \ "https://iam.api.cloud.yandex.net/iam/v1/serviceAccounts?folderId=${FOLDER_ID}"
Result:
{ "serviceAccounts": [ { "id": "ajebqtreob2d********", "folderId": "b1gvmob95yys********", "createdAt": "2018-10-18T13:42:40Z", "name": "my-robot", "description": "my description" } ] }
-
Create the request body, for example, in the
body.json
file. Set theaction
property toADD
and theroleId
property to the appropriate role, such aseditor
, and specify theserviceAccount
type and service account ID in thesubject
property:body.json:
{ "accessBindingDeltas": [{ "action": "ADD", "accessBinding": { "roleId": "editor", "subject": { "id": "ajebqtreob2d********", "type": "serviceAccount" } } }] }
-
Assign a role to a service account. For example, for a folder with the
b1gvmob95yys********
ID:export FOLDER_ID=b1gvmob95yys******** export IAM_TOKEN=CggaAT******** curl -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${IAM_TOKEN}" \ -d '@body.json' \ "https://resource-manager.api.cloud.yandex.net/resource-manager/v1/folders/${FOLDER_ID}:updateAccessBindings"
- In the management console
-
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 <name_of_folder_with_service_account> \ --output key.json
Where:
service-account-id
: ID of your service account.folder-name
: Name of the folder the service account was created in.output
: Name of the file with the authorized key.
Result:
id: aje8nn871qo4******** service_account_id: ajehr0to1g8******** 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 doesn't exceed 12 hours, but we recommend requesting the token more often, like once per hour.
Warning
Managing resources on behalf of the user's Yandex account or a federated account is less secure than on behalf of the 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, log in to 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 doesn't exceed 12 hours, but we recommend requesting the token more often, like once per hour.
Create a Terraform configuration file
-
Create a directory with any name, for example,
cloud-terraform
. It stores the configuration files and saved states for Terraform and your infrastructure.Warning
Each configuration must be in a separate directory.
-
Create a configuration file with the
.tf
extension in this directory, such asmain.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 had a provider from the Hashicorp registry configured, 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.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
: The minimum version of Terraform the provider is compatible with. -
provider
: The 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
If you used the .terraform.lock.hcl
file, run the terraform providers lock
command before initializing, specifying the URL of the mirror that the provider will be uploaded from and the platforms that the configuration will be used on:
terraform providers lock -net-mirror=https://terraform-mirror.yandexcloud.net -platform=<platform_name_1> -platform=<platform_name_2> 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
Prepare an infrastructure plan
Using Terraform in Yandex Cloud, you can create cloud resources of any type, such as VMs, disks, and images. For more information about the resources you can create with Terraform, see the provider documentation
To create a resource, specify a set of required and optional parameters that define the resource properties. Such resource descriptions make up an infrastructure plan.
The plan includes creating two VMs: terraform1
and terraform2
, as well as a cloud network called network-1
with a subnet named subnet-1
.
Resource names must meet the following requirements:
- The name must be from 3 to 63 characters long.
- It may contain lowercase Latin letters, numbers, and hyphens.
- The first character must be a letter and the last character cannot be a hyphen.
The VMs will have different vCPU and memory configurations: 2 vCPUs and 2 GB of RAM for terraform1
and 4 vCPUs and 4 GB of RAM for terraform2
. The VMs will be automatically assigned public and private IP addresses from the 192.168.10.0/24
range in subnet-1
located in the ru-central1-a
availability zone and belonging to the network-1
cloud network. The VMs will run Ubuntu OS and host the public part of the key to enable SSH access to the VMs.
In the VM configuration, you will need to specify the boot disk image ID. You can get a list of available public images using this CLI command:
yc compute image list --folder-id standard-images
To access the VMs over SSH, generate an SSH key pair and include the public key to the VM in the ssh-keys
parameter in the metadata
section.
Resource configurations are specified immediately after the provider's configuration:
terraform {
required_providers {
yandex = {
source = "yandex-cloud/yandex"
}
}
}
provider "yandex" {
zone = "<default availability zone>"
}
resource "yandex_compute_instance" "vm-1" {
name = "terraform1"
}
According to the plan, the following resources are created:
Network-1
cloud network with a subnet namedsubnet-1
in theru-central1-a
availability zone.- Two Linux VMs:
terraform1
(2 cores and 2 GB of RAM) andterraform2
(4 cores and 4 GB of RAM). The VMs are automatically assigned public and private IP addresses from the192.168.10.0/24
range insubnet-1
.
-
Get the ID of the boot disk image from Yandex Cloud Marketplace, such as Ubuntu 16.04 LTS, that will be installed on the VM. Get a list of available public images by running the following command in the CLI.
yc compute image list --folder-id standard-images
-
Generate an SSH key pair to connect to your VM over SSH.
-
Describe the resource parameters in the
main.tf
file:- In the
ssh-keys
parameter undermetadata
, specify the path to the public part of the SSH key. - In the
image_id
parameter, set the boot disk image ID.
main.tf file<provider_settings> resource "yandex_compute_disk" "boot-disk-1" { name = "boot-disk-1" type = "network-hdd" zone = "ru-central1-a" size = "20" image_id = "fd87va5cc00gaq2f5qfb" } resource "yandex_compute_disk" "boot-disk-2" { name = "boot-disk-2" type = "network-hdd" zone = "ru-central1-a" size = "20" image_id = "fd87va5cc00gaq2f5qfb" } resource "yandex_compute_instance" "vm-1" { name = "terraform1" resources { cores = 2 memory = 2 } boot_disk { disk_id = yandex_compute_disk.boot-disk-1.id } network_interface { subnet_id = yandex_vpc_subnet.subnet-1.id nat = true } metadata = { ssh-keys = "ubuntu:${file("~/.ssh/id_ed25519.pub")}" } } resource "yandex_compute_instance" "vm-2" { name = "terraform2" resources { cores = 4 memory = 4 } boot_disk { disk_id = yandex_compute_disk.boot-disk-2.id } network_interface { subnet_id = yandex_vpc_subnet.subnet-1.id nat = true } metadata = { ssh-keys = "ubuntu:${file("~/.ssh/id_ed25519.pub")}" } } 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 }
- In the
According to the plan, the following resources are created:
- A cloud network named
ya-network
with a subnet namedya-network
in the default availability zone. - Two Windows VMs:
terraform1
(2 cores and 4 GB of RAM) andterraform2
(4 cores and 4 GB of RAM). The VM will automatically get public and private IP addresses from the range192.168.10.0/24
in theya-network
subnet.
Create the following files:
-
main.tf
: The main infrastructure description file.Contents of the main.tf fileterraform { required_providers { yandex = { source = "yandex-cloud/yandex" } } } provider "yandex" { zone = var.zone } resource "yandex_vpc_network" "default" { name = var.network } resource "yandex_vpc_subnet" "default" { network_id = yandex_vpc_network.default.id name = var.subnet v4_cidr_blocks = var.subnet_v4_cidr_blocks zone = var.zone } data "yandex_compute_image" "default" { family = var.image_family } resource "yandex_compute_disk" "boot-disk" { name = "boot-disk" type = var.disk_type zone = "ru-central1-a" size = var.disk_size image_id = yandex_compute_image.default.id } data "template_file" "default" { template = file("${path.module}/init.ps1") vars = { user_name = var.user_name user_pass = var.user_pass admin_pass = var.admin_pass } } resource "yandex_compute_instance" "default" { name = var.name hostname = var.name zone = var.zone resources { cores = var.cores memory = var.memory } boot_disk { disk_id = yandex_compute_disk.boot-disk.id } network_interface { subnet_id = yandex_vpc_subnet.default.id nat = var.nat } metadata = { user-data = data.template_file.default.rendered } timeouts { create = var.timeout_create delete = var.timeout_delete } } output "name" { value = yandex_compute_instance.default.name } output "address" { value = yandex_compute_instance.default.network_interface.0.nat_ip_address }
-
variables.tf
: File describing the variables for the new resources.variables.tfvariable "zone" { type = string default = "ru-central1-a" } variable "network" { type = string default = "ya-network" } variable "subnet" { type = string default = "ya-network" } variable "subnet_v4_cidr_blocks" { type = list(string) default = ["192.168.10.0/16"] } variable "nat" { type = bool default = true } variable "image_family" { type = string default = "windows-2019-dc-gvlk" } variable "name" { type = string } variable "cores" { type = number default = 2 } variable "memory" { type = number default = 4 } variable "disk_size" { type = number default = 50 } variable "disk_type" { type = string default = "network-nvme" } variable "user_name" { default = "" type = string } variable "user_pass" { default = "" type = string } variable "admin_pass" { default = "" type = string } variable "timeout_create" { default = "10m" } variable "timeout_delete" { default = "10m" }
-
terraform.tfvars
: File storing the values of variables for accounts created inside the VM and access tokens.terraform.tfvarsname = "<my_server_name>" user_name = "<my_user>" user_pass = "<my_password>" admin_pass = "<my_password>"
Create users
To add a user to a VM being created, under metadata
, include the user-data
parameter with the user metadata. To do this:
-
Create a UTF-8 encoded text file containing the metadata, for example:
#cloud-config users: - name: <username> groups: sudo shell: /bin/bash sudo: 'ALL=(ALL) NOPASSWD:ALL' ssh-authorized-keys: - <public_SSH_key_1> - <public_SSH_key_2> - ...
Where:
-
name
: VM username. -
ssh-authorized-keys
(orssh_authorized_keys
): List of public SSH keys for VM access.Sample key:
ssh-ed25519 AAAAB3Nza......Pu00jRN user@desktop
.
-
-
In the
main.tf
file, replacessh-keys
with theuser-data
parameter and specify the metadata file path:metadata = { user-data = "${file("<file path>/meta.txt")}" }
For more information about working with metadata, see VM instance metadata.
You can create a user and set the Administrator account password on a VM in Yandex Cloud using the cloudbase-initinit.ps1
that the agent will run on the initial boot of the system. Variables from the variables.tf
file will be used as credentials.
#ps1
# ^^^ 'ps1' is only for cloudbase-init, some sort of sha-bang in linux
# logging
Start-Transcript -Path "$ENV:SystemDrive\provision.txt" -IncludeInvocationHeader -Force
"Bootstrap script started" | Write-Host
# inserting value's from terraform
$MyUserName = "${ user_name }"
$MyPlainTextPassword = "${ user_pass }"
if (-not [string]::IsNullOrEmpty($MyUserName) -and -not [string]::IsNullOrEmpty($MyPlainTextPassword)) {
"Create user" | Write-Host
$MyPassword = $MyPlainTextPassword | ConvertTo-SecureString -AsPlainText -Force
$MyUser = New-LocalUser -Name $MyUserName -Password $MyPassword -PasswordNeverExpires -AccountNeverExpires
$MyUser | Add-LocalGroupMember -Group 'Administrators'
$MyUser | Add-LocalGroupMember -Group 'Remote Management Users'
}
# inserting value's from terraform
$MyAdministratorPlainTextPassword = "${ admin_pass }"
if (-not [string]::IsNullOrEmpty($MyAdministratorPlainTextPassword)) {
"Set local administrator password" | Write-Host
$MyAdministratorPassword = $MyAdministratorPlainTextPassword | ConvertTo-SecureString -AsPlainText -Force
# S-1-5-21domain-500 is a well-known SID for Administrator
# https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows
$MyAdministrator = Get-LocalUser | Where-Object -Property "SID" -like "S-1-5-21-*-500"
$MyAdministrator | Set-LocalUser -Password $MyAdministratorPassword
}
"Bootstrap script ended" | Write-Host
Check and format the configuration files
-
Check the configuration using the command:
terraform validate
If the configuration is valid, the following message is returned:
Success! The configuration is valid.
-
Format the configuration files in the current folder and subfolders:
terraform fmt
Result:
main.tf variables.tf
Create resources
-
After checking the configuration, run the command:
terraform plan
The terminal will display a list of resources with parameters. This is a test step. No resources are created. If there are errors in the configuration, Terraform points them out.
Alert
You're charged for all resources created using Terraform. Check the plan carefully.
-
To create resources, run the command:
terraform apply
-
Confirm the resource creation: type
yes
in the terminal and press Enter.Terraform will create all the required resources and the terminal will display the IP addresses of the created VMs. You can check resource availability and their settings in the management console
.
How to delete the resources you created
To delete the resources created with Terraform:
-
Run the command:
terraform destroy
Alert
Terraform deletes all the resources that you created in the current configuration, such as clusters, networks, subnets, and VMs.
After the command is executed, the terminal will display a list of resources to be deleted.
-
Type the word
yes
, then press Enter.
You can use the management console