この記事で解決する課題
Terraformでaws_lakeformation_permissions
を扱う際、制御するケースに応じて適切なオブジェクト(database
、data_location
、lf_tag_policy
等)を書き分ける必要があります。(参考:Resource: aws_lakeformation_permissions Argument Reference)
したがって、単純にfor_each
で種類の異なる複数のリソースを作成するには工夫が必要です。
本記事では、必要なオブジェクトだけをdynamic
とtry
で生成することで、for_each
だけでは難しい可変スキーマをシンプルに管理する方法を紹介します。
結論(完成コード)
database
、data_location
、lf_tag_policy
のいずれか1つだけを受け取り、渡されたものだけ dynamic で生成するモジュール。
モジュール本体
# modules/lakeformation_permissions/main.tf
resource "aws_lakeformation_permissions" "main" {
principal = var.principal_arn
permissions = var.permissions
# ---- database ----
dynamic "database" {
for_each = try([var.policy.database], [])
content {
name = database.value.name
}
}
# ---- data_location ----
dynamic "data_location" {
for_each = try([var.policy.data_location], [])
content {
arn = data_location.value.arn
}
}
# ---- lf_tag_policy ----
dynamic "lf_tag_policy" {
for_each = try([var.policy.lf_tag_policy], [])
content {
resource_type = lf_tag_policy.value.resource_type
dynamic "expression" {
for_each = lf_tag_policy.value.expression
content {
key = expression.value.key
values = expression.value.values
}
}
}
}
}
変数定義
variable "principal_arn" {
type = string
}
variable "permissions" {
type = list(string)
}
variable "policy" {
# database / data_location / lf_tag_policy のいずれか1つを受け取るため any を指定
type = any
}
使い方(呼び出し例)
# localsでパラメータ定義(3パターンをまとめて管理するサンプル)
locals {
lf_permission_parameters = {
# S3 データロケーション用
location_for_role = {
principal_arn = "arn:aws:iam::123456789012:role/lake-formation-role"
permissions = ["DATA_LOCATION_ACCESS"]
policy = {
data_location = {
arn = "arn:aws:s3:::my-data-bucket"
}
}
}
# Database 用
database_for_role = {
principal_arn = "arn:aws:iam::123456789012:role/lake-formation-role"
permissions = ["SELECT", "ALTER"]
policy = {
database = {
name = "my_db"
}
}
}
# LF-Tag Policy 用
lf_tag_policy_for_role = {
principal_arn = "arn:aws:iam::123456789012:role/lake-formation-role"
permissions = ["SELECT"]
policy = {
lf_tag_policy = {
resource_type = "TABLE"
expression = [
{
key = "my_tag",
values = ["high","low"]
}
]
}
}
}
}
}
# モジュール本体の呼び出し
module "lf_permission" {
source = "./modules/lakeformation_permissions"
for_each = local.lf_permission_parameters
principal_arn = each.value.principal_arn
permissions = each.value.permissions
policy = each.value.policy
}
設計のポイント
-
for_eachでは足りない理由
for_each
そのものは「同じ形の繰り返し」が前提です。
今回はオブジェクトの種類が制御したいケースによって変わる = 可変スキーマ なのでモジュール設計に工夫が必要になります。 -
dynamic × try([...], [])
dynamic
に渡すfor_each
は「空なら生成しない、1要素なら生成する」の意味です。
try([var.policy.database], [])
によって、未指定時に空配列渡すことによりこれを実現しています。
まとめ
-
可変スキーマが前提のリソースは、
for_each
だけだとつらい。 -
dynamic
とtry
を組み合わせることで、必要なブロックだけを生成。
「あ、これ自分の案件でも使えるかも」と思ったら、ぜひ試してみてください!