[Yandex Cloud documentation](../../index.md) > [Tutorials](../index.md) > [Basic infrastructure](../infrastructure/index.md) > Tools > Using Yandex Cloud modules in Terraform

# Using Yandex Cloud modules in Terraform


Yandex Cloud provides a ![](../../_assets/overview/solution-library-icon.svg)[set of modules for Terraform](https://github.com/terraform-yc-modules). Terraform modules combine a number of cloud resources that should work together. Modules simplify the cloud infrastructure configuration, make it easier to reuse its blocks, and allow you to specify any parameters required for creating resources in variables. 

This page explains how to enable the modules and use them to create a test infrastructure with a [cloud network](../../vpc/concepts/network.md#network), three [Yandex Virtual Private Cloud](../../vpc/index.md) [subnets](../../vpc/concepts/network.md#subnet), and a [Yandex Managed Service for Kubernetes cluster](../../managed-kubernetes/concepts/index.md#kubernetes-cluster).

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 data](#get-credentials).
1. [Create a Terraform configuration file](#configure-terraform).
1. [Configure your provider](#configure-provider).

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 the [Managed Service for Kubernetes highly available master](../../managed-kubernetes/concepts/index.md#master) (see [Managed Service for Kubernetes pricing](../../managed-kubernetes/pricing.md)).
* Fee for continuously running [VMs](../../compute/concepts/vm.md) in the [Managed Service for Kubernetes node group](../../managed-kubernetes/concepts/index.md#node-group) (see [Yandex Compute Cloud pricing](../../compute/pricing.md)).
* Fee for using dynamic [public IP addresses](../../vpc/concepts/address.md#public-addresses) (see [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}

Use a [service account](../../iam/concepts/users/service-accounts.md) to manage the Yandex Cloud infrastructure via Terraform. It will help you flexibly configure access permissions to resources.

You can also use Terraform under your [Yandex account](../../iam/concepts/users/accounts.md#passport), [federated](../../iam/concepts/users/accounts.md#saml-federation) or [local user](../../iam/concepts/users/accounts.md#local) account, but this method is less secure. For more information, see the end of this section.
1. If you do not have the Yandex Cloud CLI yet, [install it](../../cli/quickstart.md#install).
1. If you do not have a service account, create one:

   {% list tabs group=instructions %}

   - Management console {#console}

     1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) where you want to create your service account.
     1. Navigate to **Identity and Access Management**.
     1. Click **Create service account**.
     1. Enter a name for the service account.

        The naming requirements are as follows:

        * 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.

     1. Click **Create**.

   - CLI {#cli}

     The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

     To create a service account, run the following command:

     ```bash
     yc iam service-account create --name <service_account_name>
     ```

     Where `name` is the service account name in the following format:

     * 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.

     Result:

     ```text
     id: ajehr0to1g8b********
     folder_id: b1gv87ssvu49********
     created_at: "2022-09-14T09:03:11.665153755Z"
     name: sa-terraform
     ```

   - API {#api}

     To create a service account, use the [ServiceAccountService/Create](../../iam/api-ref/grpc/ServiceAccount/create.md) gRPC API call or the [create](../../iam/api-ref/ServiceAccount/create.md) REST API method for the `ServiceAccount` resource.

    {% endlist %}

1. Assign, to the service account, the following [roles](../../iam/concepts/access-control/roles.md) needed to manage Yandex Cloud resources:

   You can [assign roles](../../iam/operations/sa/assign-role-for-sa.md#binding-role-resource) 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](../../iam/operations/sa/assign-role-for-sa.md#binding-role-organization) for the entire organization.

   {% list tabs group=instructions %}

   - Management console {#console}

     To assign a role for a folder to a service account:

     1. In the [management console](https://console.yandex.cloud), click ![image](../../_assets/console-icons/layout-side-content-left.svg) or ![image](../../_assets/console-icons/chevron-down.svg) in the top panel and select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder).
     1. Navigate to the **Access bindings** tab.
     1. Click **Configure access**.
     1. In the window that opens, select **Service accounts**.
     1. Select a service account from the list or use the search.
     1. Click ![image](../../_assets/console-icons/plus.svg) **Add role** and select the role in the folder.
     1. Click **Save**.

   - CLI {#cli}

     1. Find out the ID of the service account (the `ID` column) you want to assign the role to:

        ```bash
        yc iam service-account list
        ```

        Result:

        ```text
        +----------------------+--------------+--------+---------------------+-----------------------+
        |          ID          |     NAME     | LABELS |     CREATED AT      | LAST AUTHENTICATED AT |
        +----------------------+--------------+--------+---------------------+-----------------------+
        | ajeg2b2et02f******** | terraform-sa |        | 2024-09-08 18:59:45 | 2025-08-21 06:40:00   |
        | ajegtlf2q28a******** | default-sa   |        | 2023-06-27 16:18:18 | 2025-08-21 06:30:00   |
        +----------------------+--------------+--------+---------------------+-----------------------+
        ```

     1. Assign the role for the resource to the service account:

        ```bash
        yc <service-name> <resource> add-access-binding <resource-name>|<resource-id> \
          --role <role-id> \
          --subject serviceAccount:<service-account-id>
        ```

        Where:
        * `<service-name>`: Name of the [service](../../cli/cli-ref/index.md#service-manage) for whose resource you want to assign the role, e.g., `resource-manager`.
        * `<resource>`: Resource category, e.g., `cloud` to assign a role for the entire [cloud](../../resource-manager/concepts/resources-hierarchy.md#cloud), or `folder` to assign a role for a [folder](../../resource-manager/concepts/resources-hierarchy.md#folder).
        * `<resource-name>`: Resource name. You can specify a resource by its name or ID (cloud or folder name).
        * `<resource-id>`: Resource ID (cloud or folder ID).
        * `<role-id>`: Role, e.g., `resource-manager.clouds.owner`.
        * `<service-account-id>`: ID of the service account you are assigning the role to.

        >Here is an example:
        > 
        >```bash
        >yc resource-manager folder add-access-binding **********9n9hi2qu --role editor --subject serviceAccount:**********qhi2qu
        >```
        >
        >Result:
        >
        >```text
        >done (1s)
        >```

   - API {#api}

     To assign the service account a role for a cloud or folder, use the `updateAccessBindings` REST API method for the [Cloud](../../resource-manager/api-ref/Cloud/index.md) or [Folder](../../resource-manager/api-ref/Folder/index.md) resource:
     
     1. Select the 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](../../iam/roles-reference.md).
     1. [Get](../../resource-manager/operations/folder/get-id.md) the ID of the service accounts folder.
     1. [Get](../../iam/operations/iam-token/create.md) an IAM token for authentication in the Yandex Cloud API.
     1. Get a list of folder service accounts to find out their IDs:
     
         ```bash
         export FOLDER_ID=b1gvmob95yys********
         export IAM_TOKEN=CggaATEVAgA...
         curl \
           --header "Authorization: Bearer ${IAM_TOKEN}" \
           "https://iam.api.cloud.yandex.net/iam/v1/serviceAccounts?folderId=${FOLDER_ID}"
         ```
     
         Result:
     
     
         ```json
         {
          "serviceAccounts": [
           {
            "id": "ajebqtreob2d********",
            "folderId": "b1gvmob95yys********",
            "createdAt": "2018-10-18T13:42:40Z",
            "name": "my-robot",
            "description": "my description"
           }
          ]
         }
         ```
     
     1. Create the request body, e.g., in the `body.json` file. Set the `action` property to `ADD` and `roleId` to the appropriate role, such as `editor`, and specify the `serviceAccount` type and service account ID in the `subject` property:
     
         **body.json:**
         ```json
         {
           "accessBindingDeltas": [{
             "action": "ADD",
             "accessBinding": {
               "roleId": "editor",
               "subject": {
                 "id": "ajebqtreob2d********",
                 "type": "serviceAccount"
               }
             }
           }]
         }
         ```
     1. Assign a role to a service account. For example, for a folder with the `b1gvmob95yys********` ID:
        
        ```bash
        export FOLDER_ID=b1gvmob95yys********
        export IAM_TOKEN=CggaAT********
        curl \
          --request POST \
          --header "Content-Type: application/json" \
          --header "Authorization: Bearer ${IAM_TOKEN}" \
          --data '@body.json' \
          "https://resource-manager.api.cloud.yandex.net/resource-manager/v1/folders/${FOLDER_ID}:updateAccessBindings"
        ```

   {% endlist %}

1. Add credentials into environment variables. When creating an [IAM token](../../iam/concepts/authorization/iam-token.md), use the [impersonation](../../iam/concepts/access-control/impersonation.md) of the service account you created earlier, specifying its ID in the `--impersonate-service-account-id` parameter:

    {% 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 %}

    {% list tabs group=programming_language %}

    - 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)
      ```

      Where:
      * `YC_TOKEN`: Service account [IAM token](../../iam/concepts/authorization/iam-token.md).
      * `YC_CLOUD_ID`: Cloud ID.
      * `YC_FOLDER_ID`: 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)
      ```

      Where:
      * `YC_TOKEN`: Service account [IAM token](../../iam/concepts/authorization/iam-token.md).
      * `YC_CLOUD_ID`: Cloud ID.
      * `YC_FOLDER_ID`: Folder ID.

    {% endlist %}

    {% note info %}

    The IAM token [lifetime](../../iam/concepts/authorization/iam-token.md#lifetime) does not exceed 12 hours; however, we recommend requesting a token more often, e.g., every hour.
    
    To have the IAM token reissued automatically, the `export IAM_TOKEN=$(yc iam create-token)` script can be used.

    {% endnote %}

{% cut "Managing resources under a Yandex account or a federated account" %}

{% note warning %}

Managing resources under a user's [Yandex account](../../iam/concepts/users/accounts.md#passport), [local account](../../iam/concepts/users/accounts.md#local), or [federated account](../../iam/concepts/users/accounts.md#saml-federation) is less secure than under a [service account](../../iam/concepts/users/service-accounts.md).

{% endnote %}

If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).

The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

If you use a federated or local account, get authenticated in the [CLI](../../cli/index.md):

* [As a federated user](../../cli/operations/authentication/federated-user.md)
* [As a local user](../../cli/operations/authentication/local-user.md)

Add your credentials to the 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)
   ```

   Where:
   * `YC_TOKEN`: [IAM token](../../iam/concepts/authorization/iam-token.md).
   * `YC_CLOUD_ID`: Cloud ID.
   * `YC_FOLDER_ID`: 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)
   ```

   Where:
   * `YC_TOKEN`: [IAM token](../../iam/concepts/authorization/iam-token.md).
   * `YC_CLOUD_ID`: Cloud ID.
   * `YC_FOLDER_ID`: Folder ID.

{% endlist %}

{% note info %}

The IAM token [lifetime](../../iam/concepts/authorization/iam-token.md#lifetime) does not exceed 12 hours; however, we recommend requesting a token more often, e.g., every hour.

To have the IAM token reissued automatically, the `export IAM_TOKEN=$(yc iam create-token)` script can be used.

{% endnote %}

{% endcut %}

## 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 about setting up mirrors, see the [documentation](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.

For more information about the `terraform providers lock` command, see [this Terraform article](https://developer.hashicorp.com/terraform/cli/commands/providers/lock).

## Enable the virtual network management module {#vpc-module}

Add the `terraform-yc-vpc` module to the configuration. You can use this module to manage your [cloud](../../resource-manager/concepts/resources-hierarchy.md#cloud) network infrastructure, including networks, subnets, [gateways](../../vpc/concepts/gateways.md), and other Virtual Private Cloud objects. Create a test network with three subnets in different [availability zones](../../overview/concepts/geo-scope.md):

```hcl
module "yc-vpc" {
  source              = "github.com/terraform-yc-modules/terraform-yc-vpc.git"
  network_name        = "test-module-network"
  network_description = "Test network created with module"
  private_subnets = [{
    name           = "subnet-1"
    zone           = "ru-central1-a"
    v4_cidr_blocks = ["10.10.0.0/24"]
  },
  {
    name           = "subnet-2"
    zone           = "ru-central1-b"
    v4_cidr_blocks = ["10.11.0.0/24"]
  },
  {
    name           = "subnet-3"
    zone           = "ru-central1-d"
    v4_cidr_blocks = ["10.12.0.0/24"]
  }
  ]
}
```

## Enable Managed Service for Kubernetes {#k8s-module}

Add the `terraform-yc-vpc` module to the configuration. Also, add the Managed Service for Kubernetes cluster configuration with a highly available master and two node groups:

```hcl
module "kube" {
  source     = "github.com/terraform-yc-modules/terraform-yc-kubernetes.git"
  network_id = "${module.yc-vpc.vpc_id}"

  master_locations  = [
    for s in module.yc-vpc.private_subnets:
      {
        zone      = s.zone,
        subnet_id = s.subnet_id
      }
    ]

  master_maintenance_windows = [
    {
      day        = "monday"
      start_time = "23:00"
      duration   = "3h"
    }
  ]

  node_groups = {
    "yc-k8s-ng-01"  = {
      description   = "Kubernetes nodes group 01"
      fixed_scale   = {
        size = 3
      }
      node_labels   = {
        role        = "worker-01"
        environment = "testing"
      }
    },

    "yc-k8s-ng-02"  = {
      description   = "Kubernetes nodes group 02"
      auto_scale    = {
        min         = 2
        max         = 4
        initial     = 2
      }
      node_labels   = {
        role        = "worker-02"
        environment = "dev"
      }

      max_expansion   = 1
      max_unavailable = 1
    }
  }
}
```

## 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**.

## See also {#see-also}

* [Getting started with Terraform](terraform-quickstart.md).
* [Uploading Terraform states to Object Storage](terraform-state-storage.md).
* [Locking Terraform states using Managed Service for YDB](terraform-state-lock.md).
* [Terraform data sources](terraform-data-sources.md).