11. データソース集
AWS Provider のうち、「読むだけ」 のデータソース。実物を作らずに既存リソースの情報を取得する仕組み。これらを覚えると、コードがハードコードから解放されて環境を移しやすくなります。
この章の目次
アカウント・リージョン情報
# data ソース 3 種(引数なし/空 {} で済む)
# - aws_caller_identity = 今 Terraform を実行している主体の情報
# - aws_region = 現在の region 情報
# - aws_partition = "aws"/"aws-cn"/"aws-us-gov" のどれか
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
data "aws_partition" "current" {}
# よく使うパターン: 上の data から取った値で ARN を組み立てる
# ハードコードしない → 別環境にコピペしても動く
locals {
account_id = data.aws_caller_identity.current.account_id
region = data.aws_region.current.name
partition = data.aws_partition.current.partition # 通常 "aws"
# 例: arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/hello
log_group_arn = "arn:${local.partition}:logs:${local.region}:${local.account_id}:log-group:/aws/lambda/hello"
}
aws_partition を使うと、中国リージョン(aws-cn)や GovCloud(aws-us-gov)を含むコードが書けます。普通は aws 固定で OK ですが、ARN を組む時は癖にしておくと安全。
アベイラビリティゾーン
# 現在のリージョンで利用可能な AZ 名の list を取得
# state = "available" → 一時的にダウンしている AZ を除外
data "aws_availability_zones" "available" {
state = "available"
# ローカルゾーンや Wavelength(特殊な opt-in 必要 AZ)を除外
filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}
# 使い方: 取得した AZ list を使って subnet を 2 個(AZ ごとに 1 つ)作成
# count.index = 0, 1 → AZ 0, 1 にそれぞれ subnet を配置
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 1}.0/24" # 10.0.1.0/24, 10.0.2.0/24
availability_zone = data.aws_availability_zones.available.names[count.index]
}
AMI(最新・特定)
# Amazon Linux 2023 の最新 AMI を毎回検索
# most_recent + owners + filter で「Amazon 公式 + 名前パターン」を絞る
data "aws_ami" "al2023" {
most_recent = true # 候補から最新作成日のものを選ぶ
owners = ["amazon"] # 所有者を Amazon に限定
filter {
name = "name"
values = ["al2023-ami-*-x86_64"] # 名前のワイルドカードマッチ
}
}
# Ubuntu 24.04 の最新(owners に Canonical 社のアカウント ID を指定)
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # ← Canonical(Ubuntu 配布元)の公式 AWS アカウント
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"]
}
}
# 自社で焼いた AMI を引く(owners に "self" を指定すると自アカウントの AMI のみ)
data "aws_ami" "internal" {
most_recent = true
owners = ["self"]
filter {
name = "name"
values = ["myapp-*"] # 自社命名規則のプレフィックス
}
}
IAM ポリシー組み立て
# IAM ポリシー JSON を HCL で組み立てる(jsonencode より読みやすい)
# .json 属性で IAM-policy 形式の JSON 文字列が取れる
data "aws_iam_policy_document" "lambda_assume" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}
# 複数のポリシー文書を 1 つに合成(merge する)
# source_policy_documents に並べると、statements がすべて結合された JSON が返る
data "aws_iam_policy_document" "merged" {
source_policy_documents = [
data.aws_iam_policy_document.s3_read.json,
data.aws_iam_policy_document.dynamodb_rw.json,
]
}
ネットワーク既存参照
「会社共通の VPC があるので、それを使う」「既存の subnet を見つける」といった使い方。
# タグで既存 VPC を検索(Name タグが "shared-main" の VPC を引く)
data "aws_vpc" "main" {
tags = { Name = "shared-main" }
}
# 上の VPC 内の subnet を、タグで絞り込んで一覧取得
# 返るのは ids 属性に subnet ID の list
data "aws_subnets" "private" {
filter {
name = "vpc-id"
values = [data.aws_vpc.main.id]
}
tags = { Tier = "private" }
}
# 使い方: 取得した list の 1 番目を subnet_id に渡す
resource "aws_instance" "worker" {
subnet_id = data.aws_subnets.private.ids[0]
# ...
}
Route 53 ホストゾーン
# 既存の Route 53 ホストゾーンをドメイン名で検索
# Terraform でゾーン自体を作らず、外で作られたゾーンに「レコードだけ追加」する用途
data "aws_route53_zone" "this" {
name = "hcl-guide.com"
# private_zone = false # public/private 両方ある場合に明示
}
# 取得したゾーンに新しい A レコードを追加
resource "aws_route53_record" "blog" {
zone_id = data.aws_route53_zone.this.zone_id # data から zone_id を取得
name = "blog.hcl-guide.com"
type = "A"
# ...
}
Secrets Manager / SSM Parameter Store
API キー・パスワードを .tfvars に書かず、Secrets Manager / SSM から取得します。
# Secrets Manager から最新版のシークレットを取得
# secret_string プロパティに「文字列としての中身」が入っている
data "aws_secretsmanager_secret_version" "db" {
secret_id = "myapp/db/master"
}
# 慣例: シークレットの中身を JSON で入れておき、jsondecode で構造化
# 例: {"username":"admin","password":"..."} → { username=..., password=... }
locals {
db = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)
}
# 取り出した値は local.db.username / local.db.password で使える
# SSM Parameter Store から値を取得(名前で指定)
# value プロパティに中身が入る。SecureString でも復号済みの値が取れる
data "aws_ssm_parameter" "api_key" {
name = "/myapp/external-api-key"
}
# Lambda の環境変数として渡す例
resource "aws_lambda_function" "x" {
environment {
variables = {
API_KEY = data.aws_ssm_parameter.api_key.value
}
}
}
秘密が state に入る
data ソースで取得した秘密は、Terraform の state ファイルに平文で保存 されます。state を S3 に置く時は 必ず暗号化(バケットの SSE-KMS)と アクセス制限(IAM、bucket policy)をかける。
KMS キー
# AWS が用意した「EBS 用デフォルト KMS キー」のエイリアスを引く
# target_key_arn に実際の KMS キーの ARN が入る
data "aws_kms_alias" "ebs" {
name = "alias/aws/ebs"
}
# 使い方: 取得した KMS キーの ARN を EBS ボリュームの暗号化に使う
resource "aws_ebs_volume" "data" {
availability_zone = "ap-northeast-1a"
size = 100
encrypted = true
kms_key_id = data.aws_kms_alias.ebs.target_key_arn
}
ハードコード排除のコツ
Terraform 学習者がやりがちな「ハードコード」と、置き換える data:
| ハードコード | 置き換え先 |
|---|---|
"123456789012" | data.aws_caller_identity.current.account_id |
"ap-northeast-1" | data.aws_region.current.name |
["ap-northeast-1a","1c"] | data.aws_availability_zones.available.names |
"ami-0c4..." | data.aws_ami.al2023.id |
"db_password = ..." | data.aws_secretsmanager_secret_version |
vpc_id = "vpc-xxx" | data.aws_vpc.main.id |
これだけで、コードは「環境を変えても動く」状態に近づきます。
AWS 編はここまで
お疲れ様でした。HCL × AWS × GitHub の 3 領域で、Terraform の実務に必要な土台が揃いました。次は実際に ホーム から興味のあるトピックを行ったり来たりして、自分のプロジェクトで手を動かしてみてください。