仕事柄、プロジェクトごとに複数アカウントを切り替えて HCP Terraform (旧称 Terraform Cloud) を使っている。

HCP Terraform ではローカル環境などで terraform plan する前に terraform login で Plan を実行するアカウントのトークンを取得しておく必要がある。 しかし、terraform login で取得したトークンは 1 アカウント分しか保存されないので、アカウント切り替え時に都度トークンを取得する手間が発生する。

そこで、HCP Terraform のアカウントを使い分ける方法を紹介する。

要約

  • 環境変数 TF_CLI_CONFIG_FILE を使用して CLI 設定ファイルを切り替え
  • プロジェクトごとに .terraformrc ファイルを用意
  • direnv で自動的に環境変数を切り替え
  • オプションとして ghq + peco と組み合わせて効率化

HCP Terraform のトークン

Terraform ではコマンド実行時に CLI 設定ファイルが読み込まれる。 デフォルトでは $HOME/.terraformrc$HOME/.terraform.d/credentials.tfrc.json というファイルを読み込む。

これらのファイルに設定されているトークンが HCP Terraform の認証に使われるが、使われるトークンの優先順位は次のようになる。

  1. $HOME/.terraform.d/credentials.tfrc.json
  2. $HOME/.terraformrc

.terraform.d/credentials.tfrc.json

.terraform.d/credentials.tfrc.json は HCP Terraform のトークンを格納するファイル。 terraform login で取得されたトークンがこのファイルへ自動的に登録される。

ファイルの中身は以下のようになっており、HCP Terraform のドメイン app.terraform.io または Terraform Enterprise (HCP Terraform のセルフホスト版) のドメインが設定される。

{
  "credentials": {
    "app.terraform.io": {
      "token": "<HCP Terraform トークン>"
    }
  }
}

Terraform コマンド実行時は、設定ファイルのドメイン部分が Terrform 構成で定義された terraform{}.cloud ブロックの hostname と比較される。 hostname が Terraform Enterprise の場合は個別のドメインに紐づくトークンが利用されるらしい。

しかし、HCP Terraform の場合はドメインが共通の app.terraform.io になる。 そして app.terraform.io の設定は最新の terraform login で取得したトークンで上書きされていく。 そのため、HCP Terraform では自動的にアカウントを使い分けることができない。

ちなみに、以下のように credentials を並べて書くことはできるが、必ず後ろ側のトークンが利用されるため、トークンを使い分けることはできなかった。

{
  "credentials": {
    "app.terraform.io": {
      "token": "<アカウント A の HCP Terraform トークン>"
    }
  },
  "credentials": {
    "app.terraform.io": {
      "token": "<アカウント B の HCP Terraform トークン>"
    }
  }
}

.terraformrc

一方、.terraformrc は Terraform の CLI に関する設定をするファイルで、すべての Terraform 作業ディレクトリに適用される。 このファイルにはトークンの他に Terraform プロバイダの取得に関する設定などを HCL で記述する。

Create a Terraform CLI configuration file | Terraform | HashiCorp Developer

Learn how to create a `.terraformrc` or `terraform.rc` file to define Terraform CLI settings, including credentials, plugin caching, and provider installation.
icon
developer.hashicorp.com

先ほどと同じように、トークンを設定する場合は接続先のドメインも合わせて設定する。 .terraformrc には terraform login で自動的にトークンが設定されることはないため、手動で設定する必要がある。

credentials "app.terraform.io" {
  token = "<HCP Terraform トークン>"
}

また、こちらも同じドメインに対して複数トークンを設定できるが、やはり後ろ側のトークンが利用されるため使い分けはできない。

credentials "app.terraform.io" {
  token = "<アカウント A の HCP Terraform トークン>"
}

credentials "app.terraform.io" {
  token = "<アカウント B の HCP Terraform トークン>"
}

.terraform.d/credentials.tfrc.json.terraformrc ともにアカウントを切り替えるためには都度トークンを書き換える必要がある。

環境変数 TF_CLI_CONFIG_FILE

terraform login でトークンが登録される .terraform.d/credentials.tfrc.json のファイルパスは固定になっているが、CLI 設定ファイルとして読み込まれる .terraformrcTF_CLI_CONFIG_FILE という環境変数で上書きできる。

$HOME/.terraformrc-custom ファイルを読み込む場合は次のようになる。

$ export TF_CLI_CONFIG_FILE="$HOME/.terraformrc-custom"

$ TF_LOG=debug terraform plan
2025-02-17T02:43:43.186+0900 [INFO]  Terraform version: 1.10.5
2025-02-17T02:43:43.186+0900 [DEBUG] using github.com/hashicorp/go-tfe v1.70.0
2025-02-17T02:43:43.186+0900 [DEBUG] using github.com/hashicorp/hcl/v2 v2.23.0
2025-02-17T02:43:43.186+0900 [DEBUG] using github.com/hashicorp/terraform-svchost v0.1.1
2025-02-17T02:43:43.186+0900 [DEBUG] using github.com/zclconf/go-cty v1.16.2
2025-02-17T02:43:43.186+0900 [INFO]  Go runtime version: go1.23.3
2025-02-17T02:43:43.186+0900 [INFO]  CLI args: []string{"/Users/nnstt1/.local/share/aquaproj-aqua/pkgs/github_archive/github.com/tfutils/tfenv/v3.0.0/tfenv-3.0.0/versions/1.10.5/terraform", "plan"}
2025-02-17T02:43:43.186+0900 [DEBUG] Attempting to open CLI config file: /Users/nnstt1/.terraformrc-custom    <- 環境変数で指定した設定ファイルを読み込む
2025-02-17T02:43:43.186+0900 [DEBUG] File doesn't exist, but doesn't need to. Ignoring.
2025-02-17T02:43:43.186+0900 [DEBUG] Not reading CLI config directory because config location is overridden by environment variable
There are some problems with the CLI configuration:
│ Warning: Unable to open CLI configuration file
│ The CLI configuration file at "/Users/nnstt1/.terraformrc-custom" does not
│ exist.

2025-02-17T02:43:43.186+0900 [DEBUG] ignoring non-existing provider search directory terraform.d/plugins
2025-02-17T02:43:43.186+0900 [DEBUG] ignoring non-existing provider search directory /Users/nnstt1/.terraform.d/plugins
2025-02-17T02:43:43.186+0900 [DEBUG] ignoring non-existing provider search directory /Users/nnstt1/Library/Application Support/io.terraform/plugins
2025-02-17T02:43:43.186+0900 [DEBUG] ignoring non-existing provider search directory /Library/Application Support/io.terraform/plugins
2025-02-17T02:43:43.186+0900 [INFO]  CLI command args: []string{"plan"}
2025-02-17T02:43:43.187+0900 [DEBUG] checking for provisioner in "."
2025-02-17T02:43:43.187+0900 [DEBUG] checking for provisioner in "/Users/nnstt1/.local/share/aquaproj-aqua/pkgs/github_archive/github.com/tfutils/tfenv/v3.0.0/tfenv-3.0.0/versions/1.10.5"
2025-02-17T02:43:43.187+0900 [INFO]  backend/local: starting Plan operation
│ Error: No configuration files
│ Plan requires configuration to be present. Planning without a configuration would mark everything for destruction, which is normally not what is desired. If you would like to destroy everything, run plan with the -destroy option. Otherwise, create a Terraform configuration file (.tf
│ file) and try again.

アカウントに対応した CLI 設定ファイルを用意しておくことで、環境変数を書き換えて HCP Terraform で使うアカウントを切り替えられるようになる。

しかし、このままではアカウント切替時に環境変数を書き換える手間は残ってしまう。 そこで direnv を使う。

direnv を使う

direnv はカレントディレクトリに応じて環境変数を自動で設定してくれるツール。 インストール方法や初期設定はここでは省略。

GitHub - direnv/direnv: unclutter your .profile

unclutter your .profile. Contribute to direnv/direnv development by creating an account on GitHub.
icon
github.com

また、最近よく目にする mise というツールにも direnv と同じ環境変数の管理機能があるらしいが、今回は対象外とする。

GitHub - jdx/mise: dev tools, env vars, task runner

dev tools, env vars, task runner. Contribute to jdx/mise development by creating an account on GitHub.
icon
github.com

direnv で使う .envrc と、プロジェクトで使うアカウントのトークンを設定した CLI 設定ファイル .terraformrc をプロジェクトごとのディレクトリ直下に配置する。

./
├── project-alpha/
│   ├── .envrc
│   ├── .terraformrc
│   ├── repo-1/
│   │   ├── main.tf
│   │   └── terraform.tf
│   └── repo-2/
│       ├── main.tf
│       └── terraform.tf
└── project-beta/
    ├── .envrc
    ├── .terraformrc
    └── repo-3/
        ├── main.tf
        └── terraform.tf

例えば、project-alpha.envrc には次のような環境変数を設定しておく。

export TF_CLI_CONFIG_FILE=~/project-alpha/.terraformrc

このようにすることで、project-alpha/repo-1project-alpha/repo-2 のどちらにいても project-alpha/.terraformrc に設定されたトークンを使って Terraform を実行できる。

注意点は、HCP Terraform でのトークン発行時に有効期限を設定していると定期的に .terraformrc 内のトークン書き換え作業は発生すること。 トークンを無期限にして発行することもできるがセキュリティとのトレードオフになるので、各自の条件に応じて使い分けてもらいたい。

ghq + peco と組み合わせる

上記のようなプロジェクトディレクトリに .envrc を配置するターンは必須ではないが、プロジェクトごとにディレクトリを分けて置くと ghq + peco を組み合わせたときにより便利になる。

ghq は Git リポジトリを効率的に管理するツールで、peco はインタラクティブなフィルタリングツール。 これらを組み合わせることでリポジトリの管理や移動が楽になる。

ghqでリポジトリ管理を簡単にする

icon
zenn.dev

ghq は Git リポジトリの取得元に応じて格納するディレクトリを分けてくれるが、自分は一番上の階層でプロジェクト単位の管理とする設定を gitconfig に入れている。 GitHub から取得する際も Organization で判断してプロジェクトごとに格納先を分けるようにし、1 つのプロジェクトでバージョン管理に複数のサービスを使っている場合でも同じプロジェクトのディレクトリに格納されるようにしている。

以下の例では、project-alpha は GitHub と Azure DevOps のそれぞれに Terraform 用リポジトリを持っているが、利用している HCP Terraform は 1 環境のみ。 ghq で新たにリポジトリを取ってきて peco でディレクトリを移動してすぐに terraform planproject-alpha/.terraformrc のトークンを使って認証できる。

./
├── project-alpha/
│   ├── .envrc
│   ├── .terraformrc
│   ├── dev.azure.com/
│   │   └── org-alpha/
│   │       └── proj-alpha/
│   │           └── repo-1/
│   │               ├── main.tf
│   │               └── terraform.tf
│   └── github.com/
│       └── org-alpha/
│           └── repo-2/
│               ├── main.tf
│               └── terraform.tf
└── project-beta/
    ├── .envrc
    ├── .terraformrc
    └── github.com/
        └── org-beta/
            └── repo-3/
                ├── main.tf
                └── terraform.tf

プロジェクトごとに HCP Terraform のアカウントを使い分ける場合、現状この構成が一番しっくりきている。

まとめ

  • HCP Terraform の認証で使うトークンはそのままでは使い分けできない
  • direnv を使ってプロジェクトごとに異なる CLI 設定ファイルを参照してアカウントを使い分ける
  • ghq + peco と組み合わせることでプロジェクトごとの HCP Terraform のアカウント使い分けがより簡単になる