🐧

Ephemeral variables なら terraform apply 時に plan file と一緒に渡せる

に公開

Terraform v1.10 で Ephemeral values がサポートされました。

https://www.hashicorp.com/blog/terraform-1-10-improves-handling-secrets-in-state-with-ephemeral-values

本記事では Ephemeral values を使って terraform apply 実行時に provider の認証情報を変える方法を紹介します。

なお、本記事の内容は自分が Terraform の Community Forum で Terraform のメンテナの方とやり取りした内容そのままになっています。

https://discuss.hashicorp.com/t/how-can-we-change-provider-settings-during-terraform-apply-with-plan-files/71906

やりたいこと

まず以下のことを全部実現したいとします。

  • terraform apply 実行時に plan file を渡す
    • terraform apply による予期せぬ変更 (リソースの削除とか) を防ぎます
  • 公式の AWS Provider を使って複数の AWS アカウントのリソースを同じ Terraform Root Module で管理したい
    • 基本は 1 Root Module = 1 AWS アカウントだが、他のアカウントのリソースを参照・管理したい場合がある
  • terraform plan と apply で IAM Role を分けたい
    • 最小権限の原則。 plan では read only な IAM Role を使いたい

なお、今回は AWS に限定して話をしますが、 Google Cloud (Google Provider) などでも話は同じかと思います。

従来の課題

自分の理解が正しければ、従来は上記の 3 つのことを全部実現するのは困難でした (出来たよという場合は教えてほしいです) 。

複数の AWS アカウントを管理するには、異なるアカウントの IAM Role を assume する必要があります。
そのため、複数の provider block を定義して、 assume_roleassume_role_with_web_identity 属性を使って異なるアカウントの IAM Role を assume する必要があります。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs#argument-reference
https://developer.hashicorp.com/terraform/language/providers/configuration#alias-multiple-provider-configurations

provider "aws" {}

provider "aws" {
  alias = "account_a"
  assume_role {
    role_arn = "arn:aws:iam::123456789012:role/terraform_${var.action}"
  }
}

role_arn をハードコードしてしまうと plan と apply で IAM Role を変えられないので、 Input variables で分けています。
しかし、 plan file と input variable を同時に指定して terraform apply を実行しようとすると失敗します。

$ terraform apply -var action=apply plan.out
╷
│ Error: Can't set variables when applying a saved plan
│ 
│ The -var and -var-file options cannot be used when applying a saved plan file, because a saved plan includes the variable
│ values that were set when it was created.
╵

エラーメッセージを読めば分かる通り、これは Terraform の制約です。
実際 plan file を JSON に変換して中身を見てみると、 input variable や provider の設定がハードコードされており、 apply 時に変更できないようになっています。

よって上記の 3 つを全てクリアするのは従来難しく、どれかを諦める必要がありました。

解決策

これの解決策がないかと思って Forum で問い合わせたところ、メンテナの方から Ephemeral values で解決できると教えてもらいました。

https://discuss.hashicorp.com/t/how-can-we-change-provider-settings-during-terraform-apply-with-plan-files/71906

1.10 リリースのブログでは主に ephemeral resource に目を奪われて見逃していたのですが、 input variable にも ephemeral という属性が追加されています。

https://developer.hashicorp.com/terraform/language/values/variables#exclude-values-from-state

variable "action" {
  type      = string
  ephemeral = true
}

ephemeral = true だとその変数の値は Terraform State や plan file に保存されません。
そのため、 plan file を使って terraform apply を実行する場合でも ephemeral variables なら渡せます。
IAM Role を切り替えるのに使う input variable に ephemeral = true を設定するだけで問題は解決します。

以上、簡単ですが Ephemeral values に関する知見でした。

Discussion