1. 概要
flattenの基本的な動作- ネストされたリストの展開パターン
- for式との組み合わせ
- 実際のユースケース(複数VPCのサブネット管理など)
flatten(list_of_lists)はネストされたリストを1次元のリストに変換します。複数のリソースから生成したIDのリストをまとめたり、for式で生成したネストリストを展開したりする場面で頻繁に使います。
2. 基本的な動作
# terraform consoleで確認
> flatten([[1, 2], [3, 4], [5]])
[1, 2, 3, 4, 5]
> flatten(["a", ["b", "c"], ["d", ["e", "f"]]])
["a", "b", "c", "d", "e", "f"]
# 空リストも展開される
> flatten([[1, 2], [], [3]])
[1, 2, 3]
3. for式との組み合わせ(最重要パターン)
flattenとfor式の組み合わせは、Terraformで最も重要なパターンの1つです。複数の親リソースに紐づく子リソースのリストを1次元化します。
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 "vpcs" {
description = "VPCと各VPCのサブネット設定"
type = list(object({
name = string
subnets = list(string)
}))
default = [
{
name = "web"
subnets = ["10.0.1.0/24", "10.0.2.0/24"]
},
{
name = "db"
subnets = ["10.1.1.0/24", "10.1.2.0/24"]
}
]
}
locals {
# VPC × サブネットの組み合わせを1次元のリストに展開
subnet_list = flatten([
for vpc in var.vpcs : [
for subnet_cidr in vpc.subnets : {
vpc_name = vpc.name
cidr = subnet_cidr
}
]
])
# 結果:
# [
# { vpc_name = "web", cidr = "10.0.1.0/24" },
# { vpc_name = "web", cidr = "10.0.2.0/24" },
# { vpc_name = "db", cidr = "10.1.1.0/24" },
# { vpc_name = "db", cidr = "10.1.2.0/24" },
# ]
}
4. 実践例: 複数環境のセキュリティグループルール
variable "ingress_rules" {
description = "サービスごとのインバウンドルール"
type = list(object({
service = string
ports = list(number)
}))
default = [
{ service = "web", ports = [80, 443] },
{ service = "api", ports = [8080, 8443] },
{ service = "admin", ports = [9090] }
]
}
locals {
# サービス × ポートの組み合わせを展開
all_rules = flatten([
for rule in var.ingress_rules : [
for port in rule.ports : {
service = rule.service
port = port
}
]
])
}
# tomap → for_each で各ルールを独立したリソースとして管理
resource "aws_security_group_rule" "ingress" {
for_each = {
for rule in local.all_rules :
"${rule.service}-${rule.port}" => rule
}
type = "ingress"
from_port = each.value.port
to_port = each.value.port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.main.id
description = "${each.value.service} port ${each.value.port}"
}
resource "aws_security_group" "main" {
name = "${var.environment}-main"
description = "${var.environment} main security group"
tags = {
Name = "${var.environment}-main"
Environment = var.environment
ManagedBy = "terraform"
}
}
5. サブネットIDのマージ
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet("10.0.0.0/16", 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.environment}-public-${count.index + 1}"
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet("10.0.0.0/16", 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.environment}-private-${count.index + 1}"
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
ManagedBy = "terraform"
}
}
locals {
# publicとprivateサブネットのIDを1つのリストにまとめる
all_subnet_ids = flatten([
aws_subnet.public[*].id,
aws_subnet.private[*].id
])
}
6. 関連記事
- for式の使い方 — ネストリストの生成
- zipmap / transpose — mapの生成・転置 — リストからmapを生成
- chunklist / coalescelist / one — リストの分割・結合
7. まとめ
flatten(list_of_lists)— ネストされたリストを1次元のリストに展開する- 最重要パターン:
flatten([for x in list : [for y in x.items : {...}]])でクロス積を展開 for_eachに渡すmapを生成する前のリスト展開として定番aws_subnet.public[*].idなどのスプラット式と組み合わせてIDリストをマージできる
動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/functions/flatten