# Run the Teleport Terraform Provider with Long-Lived Credentials

This guide explains how to create a Terraform user and have the Teleport Auth Service sign long-lived credentials for it. The Teleport Terraform Provider can then use those credentials to interact with Teleport.

## How it works

A Teleport administrator defines a role for the Teleport Terraform provider, as well as a role that can [impersonate](https://goteleport.com/docs/zero-trust-access/authentication/impersonation.md) the Terraform provider role. A Teleport user assumes the impersonator role and executes a `tctl` command to instruct the Teleport Auth Service to sign a user certificate for the Terraform provider. The provider then loads the certificate in order to authenticate to your Teleport cluster and manage resources on the Teleport Auth Service backend.

---

WARNING

Long-lived credentials are less secure than other Teleport credentials and their usage is discouraged.

---

You must protect and rotate the credentials as they hold full Teleport administrative access. You should prefer using [`tbot`](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/dedicated-server.md), [native Machine & Workload Identity joining](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/ci-or-cloud.md) in CI or Cloud environments, or [create temporary bots for local use](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/local.md) when possible.

See [the list of possible Terraform provider setups](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider.md) to find which one fits your use-case.

Long-lived credentials are not compatible with MFA for administrative actions (MFA4A) which is an additional security layer that protects Teleport in case of Identity Provider (IdP) compromise.

## Prerequisites

- A running Teleport cluster. If you want to get started with Teleport, [sign up](https://goteleport.com/signup) for a free trial or [set up a demo environment](https://goteleport.com/docs/get-started/deploy-community.md).

- The `tctl` and `tsh` clients.

  Installing `tctl` and `tsh` clients

  1. Determine the version of your Teleport cluster. The `tctl` and `tsh` clients must be at most one major version behind your Teleport cluster version. Send a GET request to the Proxy Service at `/v1/webapi/find` and use a JSON query tool to obtain your cluster version. Replace teleport.example.com:443 with the web address of your Teleport Proxy Service:

     ```
     $ TELEPORT_DOMAIN=teleport.example.com:443
     $ TELEPORT_VERSION="$(curl -s https://$TELEPORT_DOMAIN/v1/webapi/find | jq -r '.server_version')"
     ```

  2. Follow the instructions for your platform to install `tctl` and `tsh` clients:

     **Mac**

     Download the signed macOS .pkg installer for Teleport, which includes the `tctl` and `tsh` clients:

     ```
     $ curl -O https://cdn.teleport.dev/teleport-${TELEPORT_VERSION?}.pkg
     ```

     In Finder double-click the `pkg` file to begin installation.

     ---

     DANGER

     Using Homebrew to install Teleport is not supported. The Teleport package in Homebrew is not maintained by Teleport and we can't guarantee its reliability or security.

     ---

     **Windows - Powershell**

     ```
     $ curl.exe -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-windows-amd64-bin.zip
     Unzip the archive and move the `tctl` and `tsh` clients to your %PATH%
     NOTE: Do not place the `tctl` and `tsh` clients in the System32 directory, as this can cause issues when using WinSCP.
     Use %SystemRoot% (C:\Windows) or %USERPROFILE% (C:\Users\<username>) instead.
     ```

     **Linux**

     All of the Teleport binaries in Linux installations include the `tctl` and `tsh` clients. For more options (including RPM/DEB packages and downloads for i386/ARM/ARM64) see our [installation page](https://goteleport.com/docs/installation.md).

     ```
     $ curl -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ tar -xzf teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ cd teleport
     $ sudo ./install
     Teleport binaries have been copied to /usr/local/bin
     ```

* [Terraform >= 1.0.0+](https://learn.hashicorp.com/tutorials/terraform/install-cli)

  ```
  $ terraform version
  Terraform v1.0.0
  ```

* To check that you can connect to your Teleport cluster, sign in with `tsh login`, then verify that you can run `tctl` commands using your current credentials.

  For example, run the following command, assigning teleport.example.com to the domain name of the Teleport Proxy Service in your cluster and email\@example.com to your Teleport username:

  ```
  $ tsh login --proxy=teleport.example.com --user=email@example.com
  $ tctl status
  Cluster  teleport.example.com
  Version  18.7.3
  CA pin   sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678
  ```

  If you can connect to the cluster and run the `tctl status` command, you can use your current credentials to run subsequent `tctl` commands from your workstation. If you host your own Teleport cluster, you can also run `tctl` commands on the computer that hosts the Teleport Auth Service for full permissions.

## Step 1/3. Create Teleport credentials for Terraform

Terraform needs a signed identity file from the Teleport cluster certificate authority to manage resources in the cluster. You will create a local Teleport user for this purpose.

1. Create a folder called `teleport-terraform` to hold temporary files:

   ```
   $ mkdir -p teleport-terraform
   $ cd teleport-terraform
   ```

2. Create a new file called `terraform.yaml` and open it in an editor.

3. Configure settings for a local Teleport user and role by pasting the following content into the `terraform.yaml` file:

   ```
   kind: user
   metadata:
     name: terraform
   spec:
     roles: ['terraform-provider']
   version: v2

   ```

   Starting with 16.2, Teleport comes with a built-in role for the Terraform provider: `terraform-provider`.

   RBAC for versions before v16.2

   On older versions you will need to create the Terraform role yourself. Write the following `role.yaml` manifest:

   ```
   kind: role
   version: v7
   metadata:
     name: terraform-provider
   spec:
     allow:
       db_labels:
         '*': '*'
       app_labels:
         '*': '*'
       node_labels:
         '*': '*'
       rules:
         - resources:
           - app
           - cluster_auth_preference
           - cluster_networking_config
           - db
           - device
           - github
           - login_rule
           - oidc
           - okta_import_rule
           - role
           - saml
           - session_recording_config
           - token
           - trusted_cluster
           - user
           - access_list
           - node
           verbs: ['list','create','read','update','delete']

   ```

   Use `tctl create -f ./role.yaml` to create the role.

   These settings configure a user and role named `terraform` with the permissions required to manage resources in your Teleport cluster.

4. Create the `terraform` user and role by running the following command:

   ```
   $ tctl create terraform.yaml
   ```

   The `terraform` user can't sign in to get credentials, so you must have another user **impersonate** the `terraform` account to request a certificate.

5. Create a new file called `terraform-impersonator.yaml` and open it in an editor.

6. Configure a role that enables your user to impersonate the Terraform user by pasting the following content into the `terraform-impersonator.yaml` file:

   ```
   kind: role
   version: v7
   metadata:
     name: terraform-impersonator
   spec:
     allow:
       # This impersonate role allows any user assigned to this role to impersonate
       # and generate certificates for the user named "terraform" with a role also
       # named "terraform".
       impersonate:
         users: ['terraform']
         roles: ['terraform-provider']

   ```

7. Create the `terraform-impersonator` role by running the following command:

   ```
   $ tctl create terraform-impersonator.yaml
   ```

8. Assign the `terraform-impersonator` role to your Teleport user by running the appropriate commands for your authentication provider:

   **Local User**

   1. Retrieve your local user's roles as a comma-separated list:

      ```
      $ ROLES=$(tsh status -f json | jq -r '.active.roles | join(",")')
      ```

   2. Edit your local user to add the new role:

      ```
      $ tctl users update $(tsh status -f json | jq -r '.active.username') \
        --set-roles "${ROLES?},terraform-impersonator"
      ```

   3. Sign out of the Teleport cluster and sign in again to assume the new role.

   **GitHub**

   1. Open your `github` authentication connector in a text editor:

      ```
      $ tctl edit github/github
      ```

   2. Edit the `github` connector, adding `terraform-impersonator` to the `teams_to_roles` section.

      The team you should map to this role depends on how you have designed your organization's role-based access controls (RBAC). However, the team must include your user account and should be the smallest team possible within your organization.

      Here is an example:

      ```
        teams_to_roles:
          - organization: octocats
            team: admins
            roles:
              - access
      +       - terraform-impersonator

      ```

   3. Apply your changes by saving and closing the file in your editor.

   4. Sign out of the Teleport cluster and sign in again to assume the new role.

   **SAML**

   1. Retrieve your `saml` configuration resource:

      ```
      $ tctl get --with-secrets saml/mysaml > saml.yaml
      ```

      Note that the `--with-secrets` flag adds the value of `spec.signing_key_pair.private_key` to the `saml.yaml` file. Because this key contains a sensitive value, you should remove the saml.yaml file immediately after updating the resource.

   2. Edit `saml.yaml`, adding `terraform-impersonator` to the `attributes_to_roles` section.

      The attribute you should map to this role depends on how you have designed your organization's role-based access controls (RBAC). However, the group must include your user account and should be the smallest group possible within your organization.

      Here is an example:

      ```
        attributes_to_roles:
          - name: "groups"
            value: "my-group"
            roles:
              - access
      +       - terraform-impersonator

      ```

   3. Apply your changes:

      ```
      $ tctl create -f saml.yaml
      ```

   4. Sign out of the Teleport cluster and sign in again to assume the new role.

   **OIDC**

   1. Retrieve your `oidc` configuration resource:

      ```
      $ tctl get oidc/myoidc --with-secrets > oidc.yaml
      ```

      Note that the `--with-secrets` flag adds the value of `spec.signing_key_pair.private_key` to the `oidc.yaml` file. Because this key contains a sensitive value, you should remove the oidc.yaml file immediately after updating the resource.

   2. Edit `oidc.yaml`, adding `terraform-impersonator` to the `claims_to_roles` section.

      The claim you should map to this role depends on how you have designed your organization's role-based access controls (RBAC). However, the group must include your user account and should be the smallest group possible within your organization.

      Here is an example:

      ```
        claims_to_roles:
          - name: "groups"
            value: "my-group"
            roles:
              - access
      +       - terraform-impersonator

      ```

   3. Apply your changes:

      ```
      $ tctl create -f oidc.yaml
      ```

   4. Sign out of the Teleport cluster and sign in again to assume the new role.

9. Request a signed identity file for the Terraform user by running the following command:

   ```
   $ tctl auth sign --user=terraform --out=terraform-identity
   ```

   After running this command, you have a `terraform-identity` file with credentials for the Terraform user.

## Step 2/3. Prepare a Terraform configuration file

To prepare a Terraform configuration file:

1. Create a new file called `main.tf` and open it in an editor.

2. Define an example user and role using Terraform by pasting the following content into the `main.tf` file, replacing teleport.example.com:443 with the host and port of the Teleport Proxy Service:

   ```
   terraform {
      required_providers {
         teleport = {
            source  = "terraform.releases.teleport.dev/gravitational/teleport"
            version = "~> 18.0"
         }
      }
   }

   provider "teleport" {
      addr               = 'teleport.example.com:443'
      identity_file_path = "terraform-identity"
   }

   # We must create a test role, if we don't declare resources, Terraform won't try to
   # connect to Teleport and we won't be able to validate the setup.
   resource "teleport_role" "test" {
      version = "v7"
      metadata = {
         name        = "test"
         description = "Dummy role to validate Terraform Provider setup"
         labels = {
            test = "yes"
         }
      }

      spec = {}
   }

   ```

## Step 3/3. Apply the configuration

To apply the configuration:

1. Check the contents of the `teleport-terraform` folder:

   ```
   $ ls
   main.tf  terraform-identity  terraform-impersonator.yaml  terraform.yaml
   ```

2. Initialize the working directory that contains Terraform configuration files by running the following command:

   ```
   $ terraform init
   Initializing the backend...

   Initializing provider plugins...
   - Finding terraform.releases.teleport.dev/gravitational/teleport versions matching ...
   ```

3. Execute the Terraform plan defined in the configuration file by running the following command:

   ```
   $ terraform apply
   Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
   + create

   Terraform will perform the following actions:

   teleport_role.test will be created
   + resource "teleport_role" "test" {
      + id       = (known after apply)
      + kind     = (known after apply)
      + metadata = {
         + name      = "test"
         + namespace = (known after apply)
           }
      + spec     = {}
      + version  = "v7"
        }

   Plan: 1 to add, 0 to change, 0 to destroy.
   ```

## Next steps

- Explore the full list of supported [Terraform provider resources](https://goteleport.com/docs/reference/infrastructure-as-code/terraform-provider.md).
- Learn [how to manage users and roles with IaC](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/managing-resources/user-and-role.md)
- Read more about [impersonation](https://goteleport.com/docs/zero-trust-access/authentication/impersonation.md).
