1. 概要
- Heredoc構文(
<<-EOT)とは何か - インデント対応のHeredoc(
<<-) - テンプレート文字列(
${...}・%{...}) templatefile関数との使い分け- 実際のユースケース(IAMポリシー・ユーザーデータなど)
Terraformでは複数行の文字列を書くためにHeredoc構文とテンプレート文字列が使えます。IAMポリシーのJSON、EC2のユーザーデータ、設定ファイルの内容など、長い文字列を扱うときに重宝します。
2. Heredoc基本構文
# 基本形(インデントは除去されない)
variable = <<EOT
1行目
2行目
3行目
EOT
# インデント対応(<<- を使うとインデントが自動除去される)
variable = <<-EOT
1行目
2行目
3行目
EOT
<<-EOT(ハイフン付き)を使うと、全行の中で最も少ない先頭スペース数を検出し、その分だけ全行から除去します。行ごとの相対的なインデント差は保持されます。コードのインデントを揃えたい場合はこちらを使います。
3. IAMポリシーの記述
terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
variable "environment" {
description = "環境名"
type = string
default = "dev"
}
variable "bucket_name" {
description = "S3バケット名"
type = string
}
# Heredocで複数行のJSONを記述
resource "aws_iam_policy" "s3_read" {
name = "${var.environment}-s3-read-policy"
description = "S3読み取り専用ポリシー"
policy = <<-EOT
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::${var.bucket_name}",
"arn:aws:s3:::${var.bucket_name}/*"
]
}
]
}
EOT
tags = {
Name = "${var.environment}-s3-read-policy"
Environment = var.environment
ManagedBy = "terraform"
}
}
推奨: IAMポリシーのJSONには
jsonencode()関数を使う方がより安全です。Heredocの場合、文字列のエスケープミスがあってもTerraformは検知できませんが、jsonencode()なら構文エラーを検出できます。
4. EC2ユーザーデータ
EC2起動時に実行するスクリプトのユーザーデータもHeredocで書くと読みやすくなります。
data "aws_ami" "amazon_linux_2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = "t3.micro"
# Heredocでユーザーデータを記述
user_data = <<-EOT
#!/bin/bash
set -e
# システム更新
dnf update -y
# Nginxインストール
dnf install -y nginx
# 環境変数を設定
echo "ENVIRONMENT=${var.environment}" >> /etc/environment
# Nginx起動
systemctl enable nginx
systemctl start nginx
EOT
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.environment}-web"
Environment = var.environment
ManagedBy = "terraform"
}
}
5. テンプレート文字列(%{if}・%{for})
%{if}と%{for}を使うと、文字列の中に条件分岐やループを埋め込めます。
locals {
servers = ["web-01", "web-02", "web-03"]
# %{for} — ループを文字列内に展開
hosts_file = <<-EOT
# Managed by Terraform
%{ for server in local.servers ~}
10.0.0.${index(local.servers, server) + 1} ${server}.internal
%{ endfor ~}
EOT
# %{if} — 条件分岐を文字列内に展開
nginx_config = <<-EOT
server {
listen 80;
%{ if var.environment == "prd" ~}
server_name www.example.com;
%{ else ~}
server_name ${var.environment}.example.com;
%{ endif ~}
}
EOT
}
6. templatefile関数との使い分け
| 比較 | Heredoc | templatefile |
|---|---|---|
| テンプレートの場所 | .tfファイル内 | 外部ファイル(.tftpl) |
| 再利用 | しにくい | しやすい |
| 向いている用途 | 短い・シンプルな内容 | 長い・複雑な内容 |
| バージョン管理 | .tfと一体 | 別ファイルで管理 |
7. 関連記事
- jsonencode / jsondecode の使い方 — IAMポリシーをより安全に記述する
- for式の使い方 — テンプレート内の%{for}との違い
- variable(入力変数)の使い方 — Heredoc内での変数参照
- join / split / format / replace — 文字列操作
- upper / lower / title / substr / strrev
- startswith / endswith / regex / regexall
8. まとめ
<<-EOT ... EOTはインデント対応のHeredoc構文(全行中の最小インデント数分を除去、相対差は保持)- Heredoc内では
${var.名前}で変数を参照できる %{for}・%{if}でループや条件分岐を文字列内に埋め込める- IAMポリシーには
jsonencode()を使う方がより安全 - 長い・再利用するテンプレートは
templatefile関数で外部ファイル化が推奨
動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/expressions/strings