[Yandex Cloud documentation](../../index.md) > [Tutorials](../index.md) > [Basic infrastructure](../infrastructure/index.md) > Tools > Getting started with Terraform

# Getting started with Terraform


With [Terraform](https://www.terraform.io/), you can quickly create a cloud infrastructure in Yandex Cloud and manage it using configuration files. These files store the infrastructure description written in HashiCorp Configuration Language (HCL). If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.

Terraform is distributed under the [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE). The [Yandex Cloud provider for Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) is distributed under the [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/) license.

For more information about the provider resources, see the guides on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../terraform/index.md).

To create your first infrastructure in Yandex Cloud using Terraform:
1. [Get your cloud ready](#before-you-begin).
1. [Install Terraform](#install-terraform).
1. [Get the authentication credentials](#get-credentials).
1. [Create a Terraform configuration file](#configure-terraform).
1. [Configure your provider](#configure-provider).
1. [Prepare an infrastructure plan](#prepare-plan).
1. [Check and format your configuration files](#check-resources).
1. [Create resources](#create-resources).

If you no longer need the resources, [delete them](#delete-resources).

## Get your cloud ready {#before-you-begin}

Sign up for Yandex Cloud and create a [billing account](../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../billing/quickstart/index.md) and [link](../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../resource-manager/concepts/resources-hierarchy.md).

### Required paid resources {#paid-resources}

The cost of support for the infrastructure deployed through Terraform in this tutorial includes:
* Fee for continuously running [VMs](../../compute/concepts/vm.md) (see [Yandex Compute Cloud pricing](../../compute/pricing.md)).
* Fee for using a dynamic [public IP address](../../vpc/concepts/address.md#public-addresses) (see [Yandex Virtual Private Cloud pricing](../../vpc/pricing.md)).

## Install Terraform {#install-terraform}

### From a mirror {#from-yc-mirror}

{% note alert %}

The mirror may be unavailable.

{% endnote %}

You can download a Terraform distribution for your platform from a [mirror](https://hashicorp-releases.yandexcloud.net/terraform/). When the download is complete, add the path to the folder with the executable to the `PATH` variable:

```bash
export PATH=$PATH:/path/to/terraform
```

### From the HashiCorp website {#from-hashicorp-site}

{% list tabs group=operating_system %}

- Windows {#windows}

   Use one of the following methods:
   * [Download the Terraform distribution](https://www.terraform.io/downloads.html) and follow [this guide](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started) to install it.
   * Install Terraform using the [Chocolatey](https://chocolatey.org/install) package manager and the command below:

      ```bash
      choco install terraform
      ```

- Linux {#linux}

   [Download the Terraform distribution](https://www.terraform.io/downloads.html) and follow [this guide](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started) to install it.

- macOS {#macos}

   Use one of the following methods:
   * [Download the Terraform distribution](https://www.terraform.io/downloads.html) and follow [this guide](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started) to install it.
   * Install Terraform using the [Homebrew](https://brew.sh) package manager and the command below:

      ```bash
      brew install terraform
      ```

{% endlist %}

## Get the authentication credentials {#get-credentials}

To authenticate and manage your Yandex Cloud infrastructure, you can use Terraform under a [service account](../../iam/concepts/users/service-accounts.md) or user accounts (a [Yandex account](../../iam/concepts/users/accounts.md#passport), a [federated account](../../iam/concepts/users/accounts.md#saml-federation), or a [local user](../../iam/concepts/users/accounts.md#local)).

{% list tabs group=authentication %}

- Service account {#service-account}

  A service account using [impersonation](../../iam/concepts/access-control/impersonation.md) is the recommended and most secure way to get authenticated.
  
  When creating an IAM token, impersonate the service account you created by specifying its ID in the `--impersonate-service-account-id` parameter. As a result, Terraform will manage the folder's resources under the service account and use the service account's IAM token.
  
  {% note info %}
  
  To use impersonation, the user must have the `iam.serviceAccounts.tokenCreator` [role](../../iam/security/index.md#iam-serviceAccounts-tokenCreator) for the service account.
  
  {% endnote %}
  
  To authenticate as a service account:
  
  1. If you do not have the Yandex Cloud CLI yet, [install it](../../cli/operations/install-cli.md).
  
  1. In the Yandex Cloud CLI, [create](../../cli/operations/profile/profile-create.md) a new profile or [activate](../../cli/operations/profile/profile-activate.md) a previously created one.
  
  1. Authenticate under your [Yandex account](../../cli/operations/authentication/user.md), [federated](../../cli/operations/authentication/federated-user.md) account, or [local](../../cli/operations/authentication/local-user.md) user account.
  
  1. If you do not have a service account, [create](../../iam/operations/sa/create.md) one.
  
  1. [Assign](../../iam/operations/sa/assign-role-for-sa.md) the service account the roles needed to manage Yandex Cloud resources.
  
  1. Write the credentials to the environment variables using impersonation:
  
      - Bash {#bash}
  
        ```bash
        export YC_TOKEN=$(yc iam create-token --impersonate-service-account-id <service_account_ID>)
        export YC_CLOUD_ID=$(yc config get cloud-id)
        export YC_FOLDER_ID=$(yc config get folder-id)
        ```
  
      - PowerShell {#powershell}
  
        ```powershell
        $Env:YC_TOKEN=$(yc iam create-token --impersonate-service-account-id <service_account_ID>)
        $Env:YC_CLOUD_ID=$(yc config get cloud-id)
        $Env:YC_FOLDER_ID=$(yc config get folder-id)
        ```
  
      {% endlist %}
  
      Where `<service_account_ID>` is the service account ID.
  
  As a result, the service account's IAM token, cloud ID, and folder ID will be saved in the environment variables.
  
  {% note info %}
  
  This IAM token will be used to authenticate each operation until the end of the token's [lifetime](../../iam/concepts/authorization/iam-token.md) (not more than 12 hours). After this, you will need to authenticate again. To have the IAM token reissued automatically, use a script or other means of automation. 
  
  To extend the period during which you do not have to authenticate in the browser, use [refresh tokens](../../iam/concepts/authorization/refresh-token.md), which allow you to reissue IAM tokens without entering the browser. Do it by enabling refresh tokens [at the organization level](../../iam/concepts/authorization/refresh-token.md#token-enabling) and [initializing DPoP protection](../../iam/concepts/authorization/refresh-token.md#enabling-dpop) in the CLI.
  
  {% endnote %}
  
  When specifying provider settings in a Terraform configuration file with no sensitive data disclosed, keep this in mind:
  
  
  ```hcl
  provider "yandex" {
    # Do not specify `cloud_id`, `folder_id`, or `token`, as
    # your provider automatically fetches them from the environment variables
  
    zone = "<availability_zone>"
  }
  ```
  
  
  
  Where `zone` is the default [availability zone](../../overview/concepts/geo-scope.md) for all your cloud resources.
  
  When employing such a configuration, use Terraform free of any additional flags, as your provider automatically fetches them from the environment variables.

- Yandex account, federated user, or local user {#yandex-account}

  {% note warning %}
  
  It is less secure to manage resources as a user account than as a service account.
  
  {% endnote %}
  
  To authenticate as a user account:
  
  1. If you do not have the Yandex Cloud CLI yet, [install it](../../cli/operations/install-cli.md).
  
  1. In the Yandex Cloud CLI, [create](../../cli/operations/profile/profile-create.md) a new profile or [activate](../../cli/operations/profile/profile-activate.md) a previously created one.
  
  1. Authenticate as a [Yandex account](../../cli/operations/authentication/user.md), [federated](../../cli/operations/authentication/federated-user.md) user, or [local](../../cli/operations/authentication/local-user.md) user.
  
  1. Write your profile’s sensitive data, namely IAM token, cloud and folder IDs, into environment variables:
     
     {% list tabs group=programming_language %}
     
     - Bash {#bash}
     
       ```bash
       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)
       ```
     
     - PowerShell {#powershell}
     
       ```powershell
       $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)
       ```
     
     {% endlist %}
     
     Where:
     
     `yc iam create-token`: Getting an IAM token for the current session.
     `yc config get cloud-id`: Getting the cloud ID from the current CLI profile.
     `yc config get folder-id`: Getting the folder ID from the current CLI profile.
     
     
     As the result, the IAM token, cloud ID, and folder ID will be saved in the environment variables.
  
  {% note info %}
  
  This IAM token will be used to authenticate each operation until the end of the token's [lifetime](../../iam/concepts/authorization/iam-token.md) (not more than 12 hours). After this, you will need to authenticate again. To have the IAM token reissued automatically, use a script or other means of automation. 
  
  To extend the period during which you do not have to authenticate in the browser, use [refresh tokens](../../iam/concepts/authorization/refresh-token.md), which allow you to reissue IAM tokens without entering the browser. Do it by enabling refresh tokens [at the organization level](../../iam/concepts/authorization/refresh-token.md#token-enabling) and [initializing DPoP protection](../../iam/concepts/authorization/refresh-token.md#enabling-dpop) in the CLI.
  
  {% endnote %}
  
  When specifying provider settings in a Terraform configuration file with no sensitive data disclosed, keep this in mind:
  
  
  ```hcl
  provider "yandex" {
    # Do not specify `cloud_id`, `folder_id`, or `token`, as
    # your provider automatically fetches them from the environment variables
  
    zone = "<availability_zone>"
  }
  ```
  
  
  
  Where `zone` is the default [availability zone](../../overview/concepts/geo-scope.md) for all your cloud resources.
  
  When employing such a configuration, use Terraform free of any additional flags, as your provider automatically fetches them from the environment variables.

{% endlist %}

## Create a Terraform configuration file {#configure-terraform}

1. Create a new directory with any name, for example, `cloud-terraform`. It stores the configuration files and saved states for Terraform and your infrastructure.

   {% note warning %}

   Each configuration must be in a separate directory.

   {% endnote %}

1. Create a configuration file with the `.tf` extension in this directory, such as `main.tf`.

## Configure your provider {#configure-provider}

{% note info %}

These settings apply to Terraform `0.13` and higher. We recommend using the latest stable version of Terraform.

{% endnote %}

1. If you previously configured a provider from the HashiCorp registry, save its settings:

   {% list tabs group=operating_system %}

   - Linux/macOS {#linux-macos}

     ```bash
     mv ~/.terraformrc ~/.terraformrc.old
     ```

   - Windows {#windows}

     ```powershell
     mv $env:APPDATA/terraform.rc $env:APPDATA/terraform.rc.old
     ```

   {% endlist %}

1. Specify the source the provider will be installed from.

   {% list tabs group=operating_system %}

   - Linux/macOS {#linux-macos}

     Open the Terraform CLI configuration file:

     ```bash
     nano ~/.terraformrc
     ```

     {% note info %}
     
     The `.terraformrc` file must be in the user's home root folder, e.g., `/home/user/` or `/User/user/`.
     
     {% endnote %}

   - Windows {#windows}

     Open the Terraform CLI `terraform.rc` configuration file in your user's `%APPDATA%` folder.

     To find out the absolute path to the `%APPDATA%` folder, run the `echo %APPDATA%` command for `cmd` or the `$env:APPDATA` command for PowerShell.

   {% endlist %}

   Add the following section to the file:

   ```hcl
   provider_installation {
     network_mirror {
       url = "https://terraform-mirror.yandexcloud.net/"
       include = ["registry.terraform.io/*/*"]
     }
     direct {
       exclude = ["registry.terraform.io/*/*"]
     }
   }
   ```

   For more information on mirror settings, see [this guide](https://www.terraform.io/cli/config/config-file#explicit-installation-method-configuration).
1. At the beginning of the `.tf` configuration file, add the following sections:

   
   ```hcl
   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](https://www.terraform.io/docs/language/providers/requirements.html#source-addresses).
   * `required_version`: Minimum Terraform version the provider is compatible with.
   * `provider`: Provider name.
   * `zone`: Default [availability zone](../../overview/concepts/geo-scope.md) for all your cloud resources.
1. Run the `terraform init` command in the folder with 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](https://center.yandex.cloud/support) request indicating the provider name and version.

If you used the `.terraform.lock.hcl` file, run the `terraform providers lock` command prior to the initialization specifying the URL of the mirror to upload the provider from and the platforms the configuration will run on:

```bash
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 are:
  * `windows_amd64`: Windows 64-bit.
  * `linux_amd64`: Linux 64-bit.
  * `darwin_arm64`: macOS 64-bit.

If you used the [Terraform modules](terraform-modules.md), first run `terraform init`, then delete the lock file. After that, run the `terraform providers lock` command.

Learn more about the `terraform providers lock` command in [this Terraform guide](https://developer.hashicorp.com/terraform/cli/commands/providers/lock).

## Prepare an infrastructure plan {#prepare-plan}

With Terraform in Yandex Cloud, you can create cloud resources of any type: VMs, [disks](../../compute/concepts/disk.md), [images](../../compute/concepts/image.md), etc. For more information about the resources you can create with Terraform, see [this provider guide](../../terraform/index.md).

To create a resource, specify a set of required and optional parameters that define the resource properties. Such resource descriptions make up the infrastructure plan.

The plan includes creating two VMs, `terraform1` and `terraform2`, as well as a [cloud network](../../vpc/concepts/network.md#network) named `network-1` with a [subnet](../../vpc/concepts/network.md#subnet) named `subnet-1`.

Resource names must meet the following requirements:

* Length: between 3 and 63 characters.
* It can only contain lowercase Latin letters, numbers, and hyphens.
* It must start with a letter and cannot end with a hyphen.

The VMs will have different [vCPU and memory configurations](../../compute/concepts/vm.md#types): 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](../../vpc/concepts/address.md#internal-addresses) from the `192.168.10.0/24` range in `subnet-1` located in the `ru-central1-d` [availability zone](../../overview/concepts/geo-scope.md) 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](../../cli/quickstart.md) command:

```bash
yc compute image list --folder-id standard-images
```

To access the VMs over SSH, [generate an SSH key pair](../../compute/operations/vm-connect/ssh.md#creating-ssh-keys) and communicate the public key to the VM in the `ssh-keys` parameter of the `metadata` section.

Resource configurations are specified immediately after the provider's configuration:


```hcl
terraform {
  required_providers {
    yandex = {
      source = "yandex-cloud/yandex"
    }
  }
}

provider "yandex" {
  zone = "<default_availability_zone>"
}

resource "yandex_compute_instance" "vm-1" {
  name = "terraform1"
}
```



{% list tabs group=operating_system %}

- Creating a Linux VM {#linux}

  According to the plan, the following resources are created:
  * `network-1` [cloud network](../../vpc/concepts/network.md#network) with a [subnet](../../vpc/concepts/network.md#subnet) named `subnet-1` in the `ru-central1-d` [availability zone](../../overview/concepts/geo-scope.md).
  * Two Linux [VMs](../../compute/concepts/vm.md): 2 vCPUs and 2 GB of RAM for `terraform1` and 4 vCPUs and 4 GB of RAM for `terraform2`. They will automatically get [public and private IP addresses](../../vpc/concepts/address.md#internal-addresses) from the `192.168.10.0/24` range in the `subnet-1` subnet.
  1. Get the ID of the boot disk [image](../../compute/concepts/image.md) from Yandex Cloud Marketplace, such as [Ubuntu 16.04 LTS](https://yandex.cloud/en/marketplace/products/yc/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](../../cli/index.md):
  
     ```bash
     yc compute image list --folder-id standard-images
     ```
  
  1. Generate an [SSH key pair](../../compute/operations/vm-connect/ssh.md#creating-ssh-keys) to connect to your VM over SSH.
  1. Describe the resource parameters in the `main.tf` file:
     * In the `ssh-keys` parameter under `metadata`, specify the path to the public part of the SSH key.
     * In the `image_id` parameter, set the boot disk image ID.
  
     {% cut "main.tf file" %}
  
     ```hcl
     <provider_settings>
  
     resource "yandex_compute_disk" "boot-disk-1" {
       name     = "boot-disk-1"
       type     = "network-hdd"
       zone     = "ru-central1-d"
       size     = "20"
       image_id = "fd87va5cc00gaq2f5qfb"
     }
  
     resource "yandex_compute_disk" "boot-disk-2" {
       name     = "boot-disk-2"
       type     = "network-hdd"
       zone     = "ru-central1-d"
       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("<path_to_public_part_of_SSH_key>")}"
       }
     }
  
     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-d"
       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
     }
     ```
  
     {% endcut %}

- Creating a Windows VM {#windows}

  According to the plan, the following resources are created:
  * `ya-network` [cloud network](../../vpc/concepts/network.md#network) with a [subnet](../../vpc/concepts/network.md#subnet) named `ya-network` in the default [availability zone](../../overview/concepts/geo-scope.md).
  * Windows [VM](../../compute/concepts/vm.md): 2 vCPUs and 4 GB of RAM for `terraform1` and 4 vCPUs and 4 GB of RAM for `terraform2`. It will automatically get public and [private IP addresses](../../vpc/concepts/address.md#internal-addresses) from the `192.168.10.0/24` range in the `ya-network` subnet.
  
  Create the following files:
  1. `main.tf`: Main infrastructure description file.
  
      {% cut "Contents of the `main.tf` file" %}
  
      ```hcl
      terraform {
        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
      }
  
      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 {
          initialize_params {
            image_id = data.yandex_compute_image.default.id
            size     = var.disk_size
            type     = var.disk_type
          }
        }
  
        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
      }
      ```
  
      {% endcut %}
  
  1. `variables.tf`: File describing the variables for the new resources.
  
      {% cut "variables.tf" %}
  
      ```hcl
      variable "zone" {
        type    = string
        default = "ru-central1-d"
      }
  
      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"
      }
      ```
  
     {% endcut %}
  
  1. `terraform.tfvars`: File storing access tokens and variable values for accounts created inside the VM.
  
      {% cut "terraform.tfvars" %}
  
      ```hcl
      name       = "<my_server_name>"
      user_name  = "<my_user>"
      user_pass  = "<my_password>"
      admin_pass = "<my_password>"
      ```
  
     {% endcut %}

{% endlist %}

### Create users {#users}

{% list tabs group=operating_system %}

- Linux {#linux}

  Yandex Cloud uses the [cloud-init](https://cloud-init.io) mechanism to add users and change many other parameters of the new [virtual machine's](../../compute/concepts/vm.md) OS. To do this, provide the `cloud-init` configuration text in the `user-data` parameter under `metadata`. In our case, these will be system users:
  1. Create a UTF-8 encoded text file containing the metadata, for example:
  
     ```bash
        #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 user name.
        * `ssh_authorized_keys`: List of public SSH keys for VM access.
           
          Key example: `ssh-ed25519 AAAAB3Nza...Pu00jRN`.
  
  1. In the `main.tf` file, replace `ssh-keys` with the `user-data` parameter and specify the metadata file path:
  
     ```hcl
     metadata = {
       user-data = "${file("<path_to_file>/meta.txt")}"
     }
     ```
  
  For more information about working with metadata, see [VM metadata](../../compute/concepts/vm-metadata.md).

- Windows {#windows}

  You can create a user and set the Administrator account password on a [VM](../../compute/concepts/vm.md) in Yandex Cloud using the [cloudbase-init](https://cloudbase-init.readthedocs.io/en/latest/) agent. To do this, create a script named `init.ps1` that the agent will run on the initial boot of the system. Variables from the `variables.tf` file will be used as credentials.
  
  {% cut "init.ps file" %}
  
  ```cloudinit
  #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
  ```
  
  {% endcut %}

{% endlist %}

## Check and format the configuration files {#check-resources}

1. Check the configuration using this command:

   ```bash
   terraform validate
   ```

   If the configuration is valid, you will get this message:

   ```text
   Success! The configuration is valid.
   ```

1. Format the configuration files in the current folder and subfolders:

   ```bash
   terraform fmt
   ```

   Result:

   ```text
   main.tf
   variables.tf
   ```

## Create resources {#create-resources}

1. After checking the configuration, run the command:

   ```bash
   terraform plan
   ```

   The terminal will display a list of resources with parameters. This is a test step; no resources will be created. If the configuration contains any errors, Terraform will point them out.

   {% note alert %}

   You will be charged for all the resources created with Terraform. Check the pricing plan carefully.

   {% endnote %}

1. To create resources, run the command:

   ```bash
   terraform apply
   ```

1. Confirm creating the resources: type `yes` in the terminal and press **Enter**.

   Terraform will create all the required resources and the terminal will display the [IP addresses](../../vpc/concepts/address.md) of the created [VMs](../../compute/concepts/vm.md). You can check the new resources and their configuration using the [management console](https://console.yandex.cloud).

## How to delete the resources you created {#delete-resources}

To delete the resources created with Terraform:
1. Run this command:

   ```bash
   terraform destroy
   ```

   {% note alert %}

   Terraform will delete all the resources you created in the current configuration, such as clusters, [networks](../../vpc/concepts/network.md#network), [subnets](../../vpc/concepts/network.md#subnet), and [VMs](../../compute/concepts/vm.md).

   {% endnote %}

   After the command is executed, the terminal will display a list of resources to be deleted.
1. Type `yes` and press **Enter**.

You can check the deletion of the resources using the [management console](https://console.yandex.cloud).

#### See also {#see-also}

* [Uploading Terraform states to Object Storage](terraform-state-storage.md).
* [Locking Terraform states using Managed Service for YDB](terraform-state-lock.md).
* [Using Yandex Cloud modules in Terraform](terraform-modules.md).
* [Terraform data sources](terraform-data-sources.md).
* [IaC: Terraform](https://yandex.cloud/ru/training/terraform?utm_source=inhouse&utm_medium=telegram&utm_campaign=announcement): Training course on managing a cloud infrastructure using Terraform.