> ## Documentation Index
> Fetch the complete documentation index at: https://www.truefoundry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Terraform Secrets Store Migration

> Move sensitive Terraform values from terraform.tfvars into an external secrets store for improved security.

By default, sensitive values like `tfy_api_key` are stored directly in `terraform.tfvars`. While convenient for initial setup, this is a security risk if the file is committed to version control.

<Info>
  Terraform only **reads** from the secrets backend. You are responsible for creating and updating the secrets outside of Terraform.
</Info>

## Supported Backends

| Backend                     | Best for                                              |
| --------------------------- | ----------------------------------------------------- |
| **AWS Secrets Manager**     | Teams already on AWS who want managed secret rotation |
| **AWS SSM Parameter Store** | Teams on AWS who prefer a simpler key-value store     |
| **HashiCorp Vault**         | Teams using Vault as a central secrets platform       |
| **1Password**               | Teams using 1Password for credential management       |

## How It Works

Every backend follows the same pattern:

1. A `use_remote_credentials` variable (default `true`) controls whether secrets are read from the remote store or fall through to `terraform.tfvars`.
2. Data sources are gated with `count = var.use_remote_credentials ? 1 : 0` — when disabled, no remote calls are made.
3. A `locals` block resolves `tfy_api_key` from either the remote store or `var.tfy_api_key`.
4. `main.tf` references `local.tfy_api_key` — it does **not** need to change when you switch backends.

## Migration Guide

Pick the tab that matches your secrets infrastructure and follow the steps.

<Tabs>
  <Tab title="AWS Secrets Manager">
    <AccordionGroup>
      <Accordion title="Prerequisites">
        * **AWS IAM permissions** — the identity running Terraform needs:
          * `secretsmanager:GetSecretValue`
          * `secretsmanager:DescribeSecret`
      </Accordion>

      <Accordion title="Migration Steps">
        <Steps>
          <Step title="Create the secret in AWS Secrets Manager">
            Before running Terraform, manually create a secret in AWS Secrets Manager. The secret value must be a JSON object containing all the credentials you want to manage:

            ```json theme={"dark"}
            {
              "tfy_api_key": "eyJhbGciOi...",
              "license_key": "your-license-key"
            }
            ```

            **Via the AWS Console:**

            1. Open **AWS Secrets Manager** → click **Store a new secret**.
            2. Choose **Other type of secret**.
            3. Select **Plaintext** and paste the JSON above (with your actual value).
            4. Name the secret (e.g. `truefoundry/<your-cluster-name>/terraform-secrets`).
            5. Complete the wizard and note the secret name.
          </Step>

          <Step title="Add secrets.tf">
            Create a file named `secrets.tf` in your Terraform root directory with the following contents:

            ```hcl secrets.tf theme={"dark"}
            variable "use_remote_credentials" {
              type        = bool
              description = "When true, pull secrets from AWS Secrets Manager. When false, use values from terraform.tfvars directly."
              default     = true
            }

            variable "tfy_credentials_name" {
              type        = string
              description = "Name of the Secrets Manager secret that stores TrueFoundry credentials"
            }

            data "aws_secretsmanager_secret_version" "tfy_secrets" {
              count     = var.use_remote_credentials ? 1 : 0
              secret_id = var.tfy_credentials_name
            }

            locals {
              secrets     = var.use_remote_credentials ? jsondecode(data.aws_secretsmanager_secret_version.tfy_secrets[0].secret_string) : {}
              tfy_api_key = var.use_remote_credentials ? local.secrets["tfy_api_key"] : var.tfy_api_key
              license_key = var.use_remote_credentials ? local.secrets["license_key"] : var.license_key
            }
            ```

            Add a line to `locals` for each key in your secret. The fallback variables (e.g. `var.license_key`) are only used when `use_remote_credentials = false`.
          </Step>

          <Step title="Configure terraform.tfvars">
            ```hcl terraform.tfvars theme={"dark"}
            use_remote_credentials = true
            tfy_credentials_name   = "truefoundry/<your-cluster-name>/terraform-secrets"
            ```
          </Step>

          <Step title="Update main.tf and apply">
            Replace references to `var.tfy_api_key` with `local.tfy_api_key` (and similarly for any other secrets):

            ```diff theme={"dark"}
             module "platform-integrations" {
               # ...
            -  tfy_api_key = var.tfy_api_key
            +  tfy_api_key = local.tfy_api_key
               # ...
             }
            ```

            Then initialize and apply:

            ```bash theme={"dark"}
            tofu init
            tofu plan        # review — no new resources, just data source reads
            tofu apply
            ```
          </Step>
        </Steps>
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="AWS SSM Parameter Store">
    <AccordionGroup>
      <Accordion title="Prerequisites">
        * **AWS IAM permissions** — the identity running Terraform needs:
          * `ssm:GetParameter`
          * `kms:Decrypt` (for `SecureString` parameters)
        * **Parameter name format** — SSM parameter names must begin with `/` when using a hierarchical path format.
      </Accordion>

      <Accordion title="Migration Steps">
        <Steps>
          <Step title="Create the parameter in SSM Parameter Store">
            Before running Terraform, manually create a parameter. The value must be a JSON string containing all the credentials you want to manage:

            ```json theme={"dark"}
            {
              "tfy_api_key": "eyJhbGciOi...",
              "license_key": "your-license-key"
            }
            ```

            **Via the AWS Console:**

            1. Open **Systems Manager** → **Parameter Store** → click **Create parameter**.
            2. Set the **Name** (e.g. `/truefoundry/<your-cluster-name>/terraform-secrets`).
            3. Choose **Type** → **SecureString**.
            4. Paste the JSON above (with your actual value) as the **Value**.
            5. Click **Create parameter**.
          </Step>

          <Step title="Add secrets.tf">
            Create a file named `secrets.tf` in your Terraform root directory with the following contents:

            ```hcl secrets.tf theme={"dark"}
            variable "use_remote_credentials" {
              type        = bool
              description = "When true, pull secrets from SSM Parameter Store. When false, use values from terraform.tfvars directly."
              default     = true
            }

            variable "tfy_credentials_name" {
              type        = string
              description = "Name of the SSM parameter that stores TrueFoundry credentials"
              default     = "/truefoundry/terraform-secrets"
            }

            data "aws_ssm_parameter" "tfy_secrets" {
              count           = var.use_remote_credentials ? 1 : 0
              name            = var.tfy_credentials_name
              with_decryption = true
            }

            locals {
              secrets     = var.use_remote_credentials ? jsondecode(data.aws_ssm_parameter.tfy_secrets[0].value) : {}
              tfy_api_key = var.use_remote_credentials ? local.secrets["tfy_api_key"] : var.tfy_api_key
              license_key = var.use_remote_credentials ? local.secrets["license_key"] : var.license_key
            }
            ```

            Add a line to `locals` for each key in your parameter. The fallback variables (e.g. `var.license_key`) are only used when `use_remote_credentials = false`.
          </Step>

          <Step title="Configure terraform.tfvars">
            ```hcl terraform.tfvars theme={"dark"}
            use_remote_credentials = true
            tfy_credentials_name   = "/truefoundry/<your-cluster-name>/terraform-secrets"
            ```
          </Step>

          <Step title="Update main.tf and apply">
            Replace references to `var.tfy_api_key` with `local.tfy_api_key` (and similarly for any other secrets):

            ```diff theme={"dark"}
             module "platform-integrations" {
               # ...
            -  tfy_api_key = var.tfy_api_key
            +  tfy_api_key = local.tfy_api_key
               # ...
             }
            ```

            Then initialize and apply:

            ```bash theme={"dark"}
            tofu init
            tofu plan        # review — no new resources, just data source reads
            tofu apply
            ```
          </Step>
        </Steps>
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="HashiCorp Vault">
    <AccordionGroup>
      <Accordion title="Prerequisites">
        * **A running Vault server** accessible from where Terraform runs.
        * **Vault KV v2 secret engine** enabled at a known mount path (default: `secret`).
        * **Vault authentication** — set the following environment variables before running Terraform:
          * `VAULT_ADDR` — URL of the Vault server (e.g. `https://vault.example.com:8200`)
          * `VAULT_TOKEN` — a valid Vault token with read access to the secret path
        * **Vault policy** — the token must have at least the `read` capability on the secret path:
          ```hcl theme={"dark"}
          path "secret/data/truefoundry/terraform-secrets" {
            capabilities = ["read"]
          }
          ```
        * **Terraform** — must be compatible with the Vault provider `hashicorp/vault` (version `= 4.8.0`).
      </Accordion>

      <Accordion title="Migration Steps">
        <Steps>
          <Step title="Create the secret in Vault">
            Store all the credentials you want to manage in a single Vault secret. This can be done manually via console or using the CLI. For example, store `tfy_api_key` and `license_key` as keys in the secret.
          </Step>

          <Step title="Add secrets.tf">
            Create a file named `secrets.tf` in your Terraform root directory with the following contents:

            ```hcl secrets.tf theme={"dark"}
            terraform {
              required_providers {
                vault = {
                  source  = "hashicorp/vault"
                  version = "4.8.0"
                }
              }
            }

            provider "vault" {}

            variable "use_remote_credentials" {
              type        = bool
              description = "When true, pull secrets from Vault. When false, use values from terraform.tfvars directly."
              default     = true
            }

            variable "vault_secret_mount" {
              type        = string
              description = "Vault KV v2 mount path where TrueFoundry credentials are stored"
              default     = "secret"
            }

            variable "vault_secret_path" {
              type        = string
              description = "Path within the Vault KV v2 mount for TrueFoundry credentials. The secret must contain key: tfy_api_key"
              default     = "truefoundry/terraform-secrets"
            }

            data "vault_kv_secret_v2" "tfy" {
              count = var.use_remote_credentials ? 1 : 0
              mount = var.vault_secret_mount
              name  = var.vault_secret_path
            }

            locals {
              secrets     = var.use_remote_credentials ? data.vault_kv_secret_v2.tfy[0].data : {}
              tfy_api_key = var.use_remote_credentials ? local.secrets["tfy_api_key"] : var.tfy_api_key
              license_key = var.use_remote_credentials ? local.secrets["license_key"] : var.license_key
            }
            ```

            Add a line to `locals` for each key in your Vault secret. The fallback variables (e.g. `var.license_key`) are only used when `use_remote_credentials = false`.
          </Step>

          <Step title="Configure terraform.tfvars">
            ```hcl terraform.tfvars theme={"dark"}
            use_remote_credentials = true
            vault_secret_mount     = "secret"
            vault_secret_path      = "truefoundry/terraform-secrets"
            ```
          </Step>

          <Step title="Update main.tf and apply">
            Replace references to `var.tfy_api_key` with `local.tfy_api_key` (and similarly for any other secrets):

            ```diff theme={"dark"}
             module "platform-integrations" {
               # ...
            -  tfy_api_key = var.tfy_api_key
            +  tfy_api_key = local.tfy_api_key
               # ...
             }
            ```

            Then initialize and apply:

            ```bash theme={"dark"}
            export VAULT_ADDR="https://vault.example.com:8200"
            export VAULT_TOKEN="your-vault-token"

            tofu init        # downloads the hashicorp/vault provider
            tofu plan        # review — no new resources, just data source reads
            tofu apply
            ```
          </Step>
        </Steps>
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="1Password">
    <AccordionGroup>
      <Accordion title="Prerequisites">
        * **1Password CLI** installed (optional, for creating the item).
        * **1Password Service Account** with access to the vault containing your credentials.
        * **Service Account Token** — set the following environment variable before running Terraform:
          * `OP_SERVICE_ACCOUNT_TOKEN` — your 1Password service account token
        * **Terraform** — must be compatible with the 1Password provider (`1Password/onepassword`, version `>= 2.1.0`).
      </Accordion>

      <Accordion title="Migration Steps">
        <Steps>
          <Step title="Create the 1Password item">
            Create a **Secure Note** in your 1Password vault with custom text fields for each credential:

            | Field Label   | Value                    |
            | ------------- | ------------------------ |
            | `tfy_api_key` | Your TrueFoundry API key |
            | `license_key` | Your license key         |

            This can be done via the 1Password web app, desktop app, or CLI. Note down the **vault UUID** and **item UUID** — the values are the actual vault name and item name.
          </Step>

          <Step title="Add secrets.tf">
            Create a file named `secrets.tf` in your Terraform root directory with the following contents:

            ```hcl secrets.tf theme={"dark"}
            terraform {
              required_providers {
                onepassword = {
                  source  = "1Password/onepassword"
                  version = ">= 2.1.0"
                }
              }
            }

            provider "onepassword" {}

            variable "use_remote_credentials" {
              type        = bool
              description = "When true, pull secrets from 1Password. When false, use values from terraform.tfvars directly."
              default     = true
            }

            variable "op_vault_uuid" {
              type        = string
              description = "UUID of the 1Password vault containing TrueFoundry credentials"
            }

            variable "op_item_uuid" {
              type        = string
              description = "UUID of the 1Password item containing TrueFoundry credentials"
            }

            data "onepassword_item" "tfy" {
              count = var.use_remote_credentials ? 1 : 0
              vault = var.op_vault_uuid
              uuid  = var.op_item_uuid
            }

            locals {
              secrets     = var.use_remote_credentials ? { for f in data.onepassword_item.tfy[0].section[0].field : f.label => f.value } : {}
              tfy_api_key = var.use_remote_credentials ? local.secrets["tfy_api_key"] : var.tfy_api_key
              license_key = var.use_remote_credentials ? local.secrets["license_key"] : var.license_key
            }
            ```

            Add a line to `locals` for each field in your 1Password item. The fallback variables (e.g. `var.license_key`) are only used when `use_remote_credentials = false`.
          </Step>

          <Step title="Configure terraform.tfvars">
            ```hcl terraform.tfvars theme={"dark"}
            use_remote_credentials = true
            op_vault_uuid          = "<your-vault-uuid>"
            op_item_uuid           = "<your-item-uuid>"
            ```

            Replace `<your-vault-uuid>` and `<your-item-uuid>` with the actual UUIDs from your 1Password vault and item.
          </Step>

          <Step title="Update main.tf and apply">
            Replace references to `var.tfy_api_key` with `local.tfy_api_key` (and similarly for any other secrets):

            ```diff theme={"dark"}
             module "platform-integrations" {
               # ...
            -  tfy_api_key = var.tfy_api_key
            +  tfy_api_key = local.tfy_api_key
               # ...
             }
            ```

            Then initialize and apply:

            ```bash theme={"dark"}
            export OP_SERVICE_ACCOUNT_TOKEN="your-service-account-token"

            tofu init        # downloads the 1Password/onepassword provider
            tofu plan        # review — no new resources, just data source reads
            tofu apply
            ```

            <Note>
              The 1Password provider requires the `OP_SERVICE_ACCOUNT_TOKEN` environment variable to be set **even during `tofu init`** when the provider block is present.
            </Note>
          </Step>
        </Steps>
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

## FAQ

<AccordionGroup>
  <Accordion title="How do I update secrets after migration?">
    Update the secret value directly in your secrets store (AWS Secrets Manager, SSM, Vault, or 1Password), then run `tofu apply` to propagate the new values.
  </Accordion>

  <Accordion title="How do I fall back to terraform.tfvars?">
    All four backends support a quick fallback without removing `secrets.tf`. Set:

    ```hcl theme={"dark"}
    use_remote_credentials = false
    ```

    in your `terraform.tfvars` and provide the `tfy_api_key` value directly. The remote data source will be skipped entirely (`count = 0`) — no network calls to the secrets backend will be made.
  </Accordion>

  <Accordion title="How do I switch between backends?">
    1. Replace the contents of `secrets.tf` with the new backend's configuration from the relevant tab above.
    2. Update `terraform.tfvars` with the new backend's variables and remove the old backend's variables.
    3. Re-initialize and apply:

    ```bash theme={"dark"}
    tofu init -upgrade    # install any new providers
    tofu plan
    tofu apply
    ```

    <Warning>
      The `secrets.tf` file should contain only one backend's configuration at a time.
    </Warning>
  </Accordion>
</AccordionGroup>

## Quick Reference

| Backend                     | Auth Method                           | Extra Providers         | Variables in `terraform.tfvars`                                     |
| --------------------------- | ------------------------------------- | ----------------------- | ------------------------------------------------------------------- |
| **AWS Secrets Manager**     | AWS IAM (existing)                    | None                    | `use_remote_credentials`, `tfy_credentials_name`                    |
| **AWS SSM Parameter Store** | AWS IAM (existing)                    | None                    | `use_remote_credentials`, `tfy_credentials_name`                    |
| **HashiCorp Vault**         | `VAULT_ADDR` + `VAULT_TOKEN` env vars | `hashicorp/vault`       | `use_remote_credentials`, `vault_secret_mount`, `vault_secret_path` |
| **1Password**               | `OP_SERVICE_ACCOUNT_TOKEN` env var    | `1Password/onepassword` | `use_remote_credentials`, `op_vault_uuid`, `op_item_uuid`           |
