templatestring関数 — リモートから取得したテンプレートを動的にレンダリングする

Terraformでインフラを管理していると、設定ファイルの内容を環境によって変えたいケースが頻繁に発生します。templatefile関数でローカルファイルをテンプレートとして使う方法は広く知られていますが、S3やAPIから取得したリモートのテンプレート文字列を使いたい場合はどうすれば良いのでしょうか。

Terraform v1.5で追加されたtemplatestring関数が、まさにこのユースケースのために設計された関数です。

templatestring関数とは

templatestringは、モジュール内の変数・データソース・ローカル値として参照できる文字列をTerraformテンプレートとして評価する関数です。

templatefileとの根本的な違いはテンプレートの取得元です:

  • templatefile → ローカルファイルを読み込む
  • templatestring → モジュール内オブジェクト(データソース等)が持つ文字列をテンプレートとして使う

この違いにより、templatestringはS3・SSM Parameter Store・外部APIから取得した動的なテンプレートを処理できます。

構文

templatestring(ARG1, ARG2)
引数必須説明
ARG1モジュール内オブジェクトへの参照(直接リテラル文字列は不可)
ARG2テンプレート変数を格納したオブジェクト

重要な制約: 第1引数には必ずモジュール内のオブジェクト参照(data.xxx.yyylocal.xxxvar.xxx等)を指定します。テンプレート文字列を直接リテラルとして渡すことはできません。

なぜこの制約があるのか? Terraformはプランフェーズで式の評価順序を決定する必要があります。リテラルを直接渡すと評価サイクルの管理が複雑になるため、必ず参照を経由する設計になっています。

テンプレート構文

第2引数で渡した変数は、通常のTerraformテンプレート式と同じ構文で参照できます。

${変数名}               # 変数の展開
%{ for item in list ~}  # forループ
%{ if 条件 ~}           # 条件分岐
%{ endif ~}

基本的な使用例

S3から取得したテンプレートをレンダリング

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "デプロイ環境"
  type        = string
  default     = "dev"
}

variable "app_name" {
  description = "アプリケーション名"
  type        = string
}

# S3からテンプレートファイルを取得
data "aws_s3_object" "config_template" {
  bucket = "my-templates-bucket"
  key    = "app-config.tmpl"
}

# テンプレートをレンダリングしてSSMパラメータに保存
resource "aws_ssm_parameter" "app_config" {
  name  = "/${var.environment}/${var.app_name}/config"
  type  = "String"
  value = templatestring(data.aws_s3_object.config_template.body, {
    app_name    = var.app_name
    environment = var.environment
    region      = "ap-northeast-1"
  })

  tags = {
    Name        = "${var.app_name}-config"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

output "rendered_config" {
  description = "レンダリングされた設定内容"
  value       = templatestring(data.aws_s3_object.config_template.body, {
    app_name    = var.app_name
    environment = var.environment
    region      = "ap-northeast-1"
  })
}

S3バケット内のapp-config.tmplがこのような内容の場合:

APP_NAME=${app_name}
ENVIRONMENT=${environment}
AWS_REGION=${region}

rendered_configの出力は次のようになります:

APP_NAME=myapp
ENVIRONMENT=dev
AWS_REGION=ap-northeast-1

これは公式ドキュメントのExample use caseパターンに対応しています。

ローカル値を使った動的テンプレート構築

ローカル値でテンプレートを組み立て、それをtemplatestringに渡す応用パターンです。

variable "services" {
  description = "サービス名のリスト"
  type        = list(string)
  default     = ["web", "api", "worker"]
}

variable "environment" {
  description = "デプロイ環境"
  type        = string
  default     = "dev"
}

locals {
  # テンプレートを動的に構築
  nginx_template = <<-EOT
    %{ for service in services ~}
    upstream ${service} {
      server ${service}.${environment}.internal:8080;
    }
    %{ endfor ~}
  EOT
}

output "nginx_config" {
  description = "生成されたNginx設定"
  value = templatestring(local.nginx_template, {
    services    = var.services
    environment = var.environment
  })
}

注意: 公式ドキュメントでは、ローカル値でテンプレートを動的構築する方法は「他に代替手段がない場合のみ」と位置づけられています。理由は2点あります: 1. 結果が複雑になり保守が難しくなる 2. 外部入力に依存する場合、Terraformが実行されるシステム上の任意ファイルを読み込むテンプレートが生成されるリスクがある 可能な限りtemplatefileや通常の文字列補間で代替することを検討してください。

templatefileとの比較

特徴templatestringtemplatefile
テンプレートソースモジュール内オブジェクト参照ローカルファイルパス
リモートテンプレート✅ 対応(データソース経由)❌ 非対応
ローカルファイル❌ 直接不可✅ 対応
動的テンプレート構築✅ locals経由で可能❌ 不可
Terraform最小バージョンv1.5以降v0.12以降

よくある間違いと対処法

❌ 第1引数にリテラル文字列を渡す

# エラー: 第1引数にリテラルは渡せない
output "bad" {
  value = templatestring("Hello, ${name}!", { name = "World" })
}
# エラーメッセージ例:
# Error: Invalid function argument
# The first argument to "templatestring" must be a reference to a named object

リテラル文字列は通常の文字列テンプレート式で処理できます:

# 正しい方法:変数を直接補間
output "good" {
  value = "Hello, ${var.name}!"
}

❌ v1.5未満で使用する

templatestringはTerraform v1.5で追加された関数です。古いバージョンでは使用できません。required_version = ">= 1.5.0"を必ず指定しましょう。

まとめ

templatestringは、リモートから取得したテンプレート文字列をTerraformの設定内で動的にレンダリングするための関数です。

  • 第1引数: モジュール内オブジェクトへの参照(必須制約)
  • 主な用途: S3等から取得したテンプレートのレンダリング
  • 注意: 動的テンプレート構築(locals経由)はリスクがあるため慎重に

templatefileがローカルの静的テンプレートに最適なのに対し、templatestringはリモートの動的テンプレートに最適です。用途に応じて使い分けることで、より柔軟なインフラ設定管理が実現できます。

関連リソース