電通総研 テックブログ

電通総研が運営する技術ブログ

TerraformのCustom ConditionsとChecksの紹介

こんにちは。X(クロス)イノベーション本部クラウドイノベーションセンターの柴田です。

この記事は 電通国際情報サービス Advent Calendar 2023 の5日目の投稿です。
前日の記事は宮澤さんの「Jira Automationで作成した変数のスコープについて」でした。

はじめに

Terraformでインフラストラクチャを構築する際、変数やリソースが期待する条件を満たしているか検証したいケースがあると思います。

この記事では変数やオブジェクトの検証に役立つTerraformの以下の機能を紹介します。

  • 入力変数の検証
  • オブジェクトの事前条件と事後条件の検証
  • 構築したインフラストラクチャの check による検証

なお、この記事の内容は以下のバージョンのTerraformを前提とします。

$ terraform version
Terraform v1.6.3
on linux_amd64

入力変数の検証

概要

入力変数の値が指定した条件を満たしているか validation を用いて検証します。

この機能はTerraform v0.13.0以降で利用できます。

設定方法

variable に1つ以上の validation を設定します。
中身は以下の表のとおりです。
入力変数の検証の場合 condition が参照できる変数は自身のみです。

項目 説明
condition 満たすべき条件。 true なら検証成功、 false なら検証失敗。
error_message 検証に失敗した場合に表示されるエラーメッセージ。
variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    condition     = can(regex("^ami-", var.image_id))
    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
  }
}

検証

planとapplyの実行時に各 variablecondition が評価されます。
conditionfalse になるとTerraformは error_message を含むエラーを表示して異常終了します。

$ terraform plan -var image_id=123

Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: Invalid value for variable
│
│   on variables.tf line 1:
│    1: variable "image_id" {
│     ├────────────────
│     │ var.image_id is "123"
│
│ The image_id value must be a valid AMI id, starting with "ami-".
│
│ This was checked by the validation rule at variables.tf:5,3-13.
╵

オブジェクトの事前条件と事後条件の検証

概要

各オブジェクトを評価する前後に、指定した条件を満たしているかを検証します。
事前条件は precondition 、事後条件は postcondition を使用します。

この機能はTerraform v1.2.0以降で利用できます。

ユースケース

事前条件には特定のオブジェクトを評価するために満たすべき前提条件を記述します。

事後条件には特定のオブジェクトが評価後に保証すべき条件を記述します。

設定方法

以下のオブジェクトに事前条件と事後条件を設定できます。

  • リソース( resource
  • データソース( data
  • 出力( output ) ※事前条件のみ利用可能

リソース、データソース

resource または datalifecycle に事前条件 precondition または事後条件 postcondition を設定します。
それぞれ中身は先ほどと同じです。
入力変数の検証と異なり condition は他のオブジェクトを参照できます。

resource "aws_instance" "example" {
  instance_type = "t3.micro"
  ami           = data.aws_ami.example.id

  lifecycle {
    precondition {
      condition     = data.aws_ami.example.architecture == "x86_64"
      error_message = "The selected AMI must be for the x86_64 architecture."
    }

    postcondition {
      condition     = self.public_dns != ""
      error_message = "EC2 instance must be in a VPC that has public DNS hostnames enabled."
    }
  }
}

上の例ではリソース aws_instance.example に対して以下の条件を設定しています。

  • リソースを作成するためにAMIのアーキテクチャx86_64 でなければなりません。
  • リソースの作成後にパブリックDNSが設定されていることを保証します。

self は評価中のオブジェクト自身を参照するオブジェクトです。事後条件でのみ利用できます。

事前条件と事後条件は countfor_each と併用できます。

出力

output に事前条件 precondition を設定します。
事後条件 postcondition は設定できません。
中身は先ほどと同じです。

output "ami_id" {
  value = data.aws_ami.example.id

  precondition {
    condition     = data.aws_ami.example.architecture == "x86_64"
    error_message = "The selected AMI must be for the x86_64 architecture."
  }
}

検証

planとapplyの実行時に各オブジェクトの事前条件 precondition と事後条件 postconditioncondition が評価されます。

各オブジェクトの検証のライフサイクルは以下のとおりです。

  1. 事前条件の検証
  2. オブジェクトの評価
  3. 事後条件の検証

事後条件は「apply後に評価される条件」ではなく「オブジェクトの評価後に評価される条件」です。
そのためplanの実行時にも事後条件は評価されます。

condition に未確定の値が含まれる場合、その condition の評価は値が確定するまで保留されます。
特に known after apply な値を含む condition はplanの実行時には評価されません。

conditionfalse になると、以降の処理は中断され、Terraformは error_message を含むエラーを表示して異常終了します。
ただし作成済みのリソースは削除されません。

$ terraform plan
data.aws_ami.example: Reading...
data.aws_ami.example: Read complete after 0s [id=ami-0d8d9f072b1e8e8fe]

Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: Resource precondition failed
│
│   on condition.tf line 17, in resource "aws_instance" "example":
│   17:       condition     = data.aws_ami.example.architecture == "x86_64"
│     ├────────────────
│     │ data.aws_ami.example.architecture is "arm64"
│
│ The selected AMI must be for the x86_64 architecture.
╵

構築したインフラストラクチャの check による検証

概要

planとapplyの実行の終わりに指定した条件が満たされているか check を用いて検証します。

check の検証は、これまで説明した他の検証機能と異なり、検証に失敗してもplanやapplyの実行は中断されません。

この機能はTerraform v1.5.0以降で利用できます。

ユースケース

構築したインフラストラクチャが指定した条件を満たしているか検証します。

check は事後条件と似ていますが

  • 特定のオブジェクトではなくインフラストラクチャ全体を検証したい場合
  • 検証に失敗した際にエラーを発生させて処理を中断したくない場合

には事後条件よりも check を使うとよいでしょう。

設定方法

  • 0〜1個のデータソース
  • 1個以上の assert

を含む check を設定します。

check 内のデータソースはスコープ付きデータソースと呼ばれ、以下の特徴があります。

  • check の外側からは参照できません。
  • for_eachcount との併用はできません。

assert の中身は先ほどと同じです。

check "health_check" {
  data "http" "alb" {
    url = "https://${aws_lb.example.dns_name}"
  }

  assert {
    condition = data.http.alb.status_code == 200
    error_message = "${data.http.alb.url} returned an unhealthy status code"
  }
}

検証

planとapplyの実行の終わりに condition が評価されます。

事前条件や事後条件と同じく known after apply な値に依存する condition はplanの実行時には評価されません。

インフラストラクチャがまだ構築されていないplan時に check を評価したくない場合は、リソースが実際に作成された後にスコープ付きデータソースおよび condition が評価されるよう、スコープ付きデータソースからリソースへの依存関係を depends_on などを使って設定するとよいでしょう。

conditionfalse になった場合、またはスコープ付きデータソースのproviderでエラーが発生した場合、Terraformは error_message を含む警告を表示して処理を継続します。

$ terraform plan

# (中略)

╷
│ Warning: Error making request
│
│   with data.http.alb,
│   on main.tf line 14, in check "health_check":
│   14:   data "http" "alb" {
│
│ Error making request: GET https://example.com.invalid giving up after 1 attempt(s): Get "https://example.com.invalid": dial tcp: lookup example.com.invalid on 127.0.0.53:53: no such host
╵

まとめ

以下の表はここまでの内容をまとめたものです。

主なユースケース 記述箇所 検証されるタイミング count , for_each の併用 conditionfalse になった場合の挙動
入力変数の検証 入力変数の検証 variable variable の評価前 不可 異常終了
オブジェクトの事前条件の検証 特定のオブジェクトを評価するために満たすべき前提条件の検証 resource , data , output 各オブジェクトの評価前 異常終了。作成済みのリソースは削除されない。
オブジェクトの事後条件の検証 特定のオブジェクトが評価後に保証すべき条件の検証 resource , data 各オブジェクトの評価後 異常終了。作成済みのリソースは削除されない。
構築したインフラストラクチャの check による検証 構築したインフラストラクチャの検証 check (スコープ付きデータソースを利用) planとapplyの終わり 不可 警告を表示して処理を継続する

おわりに

この記事ではTerraformの変数やオブジェクトが期待する条件を満たしているか検証する方法として以下の機能を紹介しました。

  • 入力変数の検証
  • オブジェクトの事前条件と事後条件の検証
  • 構築したインフラストラクチャの check による検証

他にもTerraform v1.6で Tests の機能が導入されるなど、最近はTerraformの検証・テストに関する機能がどんどん充実していると感じます。
これらの機能を活用してより安全にインフラストラクチャを構築したいですね。

ここまで読んでいただきありがとうございました。

参考

私たちは一緒に働いてくれる仲間を募集しています!

クラウドアーキテクト

執筆:@shibata.takao、レビュー:@fukutake.hiroaki
Shodoで執筆されました