📘

HCP Terraform の設定をできる限り HCP Terraform で管理する

2024/09/05に公開

HCP Terraform (昔は Terraform Cloud と呼ばれていたもの)の設定を Terraform で管理したい場合、TFE Provider を用いることで実現が可能です。
https://registry.terraform.io/providers/hashicorp/tfe/latest/docs

この辺については多くのblogなどで書かれている内容です。

個人的な関心事としては、 「TFE Provider を用いた HCP Terraform の管理を、HCP Terraform 上でどこまで実行できるか」 です。
端的に言うと、HCP Terraform 上で terraform apply をするためには、 あらかじめ HCP Terraform 上で terraform apply を動かすための環境構築 が必要です。完全に鶏が先か卵が先か問題で、すべての設定を TFE provider で定義し HCP Terraform 上で実行して構築、というのは難しそうです。

とはいえ一部の環境はローカルからの terraform apply で構築し、一部は HCP Terraform で……という形になると構成も複雑だし手間も増えるので、できる限り HCP Terraform 上で完結するような簡潔な構成にしたいところです。

個人的に試した感じだと、以下のような形にすると、比較的手動での作業を省く形で HCP Terraform の管理ができるようになるのでは、と思います。

事前作業

  • HCP Terraform の環境は用意しておく
    • terraform login も済ませておく
  • organization は作成しておく
    • ここは諦める
    • 手動でも、Terraform をローカル環境(not HCP Terraform)で実行するでも良い
  • Variable set に HCP Terraform の API Token を設定し、適用範囲(scope)を Globally にしておく
    • 以下は terraform/tf_api_token に sensitive data として登録した例

手順

terraform init

terraform init で初期化できるものは、こちらで一通り行います。

terraform block ならびに terraform cloud block に定義した内容が、terraform init 時に HCP Terraform の workspace に反映されるものになると思います。

backend.tf
terraform {
  cloud {
    organization = "my-org"

    workspaces {
      name    = "tfe-terraform"
      project = "tfe-terraform"
    }
  }
}
provider.tf
terraform {
  required_version = "1.9.5"
  required_providers {
    tfe = {
      source  = "hashicorp/tfe"
      version = "0.58.0"
    }
  }
}

variable "tf_api_token" {
  type = string
}

provider "tfe" {
  hostname = "app.terraform.io"
  token    = var.tf_api_token
}

TFE Provider は実行に HCP Terraform の Token 情報が必要なため、あらかじめ Terraform の variable として使用できるように設定を記述しておきます(variable 名はあらかじめ variable set に設定してある内容と揃えます)。

この状態で terraform init を実施すると、設定内容を元に HCP Terraform の workspace が生成されます。

$ terraform init
Initializing HCP Terraform...
Initializing provider plugins...
- Reusing previous version of datadog/datadog from the dependency lock file
- Reusing previous version of hashicorp/tfe from the dependency lock file
- Using previously-installed hashicorp/tfe v0.58.0

HCP Terraform has been successfully initialized!

You may now begin working with HCP Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure.

If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.

Workspace

Terraform のバージョン

TFE provider を使用した TF ファイルの作成

ここでは workspace の設定をまず Terraform の管理下にします。
terraform init ですでに作成済みなので、import block を用いて既存の設定を import するようにします。

workspaces.tf
resource "tfe_workspace" "tfe-terraform" {
  name              = "tfe-terraform"
  organization      = "my-org"
  auto_apply        = false
  force_delete      = false
  queue_all_runs    = false
  terraform_version = "1.9.5"
}
import.tf
import {
  id = "my-org/tfe-terraform"
  to = tfe_workspace.tfe-terraform
}

このような設定をしたうえで terraform plan を実行すると、既存の workspace を import してくれます。

$ terraform plan
(snip.)
Terraform will perform the following actions:

  # tfe_workspace.tfe-terraform will be imported
    resource "tfe_workspace" "tfe-terraform" {
        agent_pool_id                 = null
        allow_destroy_plan            = true
        assessments_enabled           = false
        auto_apply                    = false
        auto_apply_run_trigger        = false
        auto_destroy_at               = null
        description                   = null
        execution_mode                = "remote"
        file_triggers_enabled         = true
        global_remote_state           = false
        html_url                      = "https://app.terraform.io/app/my-org/workspaces/tfe-terraform"
        id                            = "ws-XXXXXX"
        name                          = "tfe-terraform"
        operations                    = true
        organization                  = "my-org"
        project_id                    = "prj-XXXXXX"
        queue_all_runs                = false
        remote_state_consumer_ids     = []
        resource_count                = 0
        source_name                   = null
        source_url                    = null
        speculative_enabled           = true
        ssh_key_id                    = null
        structured_run_output_enabled = true
        tag_names                     = []
        terraform_version             = "1.9.5"
        trigger_patterns              = []
        trigger_prefixes              = []
        working_directory             = null
    }

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

この状態で terraform apply をすると、HCP Terraform の workspace の内容が Terraform の State に取り込まれます。
以後は Terraform 管理下でコントローラブルな状態になるので、 tf ファイル側で設定を変更することで HCP Terraform 側の設定を変更できます。

任意の値の変更

現場によって設定内容や管理したい値は様々だと思います。
ここでは以下について値を追加しています。

  • 通知関連
    • tfe_notification_configuration
  • Variable Set 関連
    • tfe_variable
    • tfe_variable_set
    • tfe_workspace_variable_set
workspaces.tf
resource "tfe_workspace" "tfe-terraform" {
  name              = "tfe-terraform"
  organization      = "my-org"
  auto_apply        = false
  force_delete      = false
  queue_all_runs    = false
  terraform_version = "1.9.5"
}

resource "tfe_notification_configuration" "tfe-terraform" {
  name             = "HCP Terraform"
  enabled          = true
  workspace_id     = tfe_workspace.tfe-terraform.id
  destination_type = "slack"
  triggers         = ["run:applying", "run:completed", "run:errored"]
  url              = "https://hooks.slack.com/services/....."
}
variable_sets.tf
resource "tfe_variable_set" "sada" {
  name         = "sada"
  organization = var.organization
}

resource "tfe_variable" "sada-sada" {
  key             = "sada"
  value           = "masashi"
  category        = "terraform"
  variable_set_id = tfe_variable_set.sada.id
}

resource "tfe_variable" "sada-masashi" {
  key             = "masashi"
  value           = "sada"
  category        = "terraform"
  sensitive       = true
  variable_set_id = tfe_variable_set.sada.id
}

resource "tfe_workspace_variable_set" "sada" {
  variable_set_id = tfe_variable_set.sada.id
  workspace_id    = tfe_workspace.tfe-terraform.id
}

注意点

HCP Terraform の設定を TFE provider で設定しようとする際の、個人的に気になる点を記載します。

Terraform でハンドリングできない/し辛い設定

たとえば Version Control の設定(GitHub などとの連携)については Terraform の TF ファイル単体で定義するのは難しそうです。
そういう値については、Terraform 管理下に置いたうえで

  • HCP Terraform の画面から設定変更
  • 設定変更内容を TF ファイルに取り込む

という対応をしていくことになりそうです。

Variable set の sensitive data 問題

現状、Variable set の sensitive data を登録しようとした場合、TF ファイル上では平文で記載する必要がありそうです。
GitHub Actions Secrets みたいに暗号化の方法が公開されているのであれば暗号化済みの情報を管理できるのでやりやすいのですが、HCP Terraform についてはそのような状態ではなさそうです。
https://zenn.dev/moaikids/articles/9cc5f976c9b890

ということで、TF ファイルは基本的に GitHub などでソース管理をすることになり、平文で Credential 的な情報を書く事ができないため、この辺の管理については工夫が必要そうです。
この辺を嫌って、Variable set の値については TFE provider / terraform で管理しない、という対応も現場によっては十分にありえるのかなとは思います。

Discussion