본문 바로가기
IaC/Terraform

Terraform에서 Dynamic Block 사용하기

by 홍띠 2024. 12. 22.

Dynamic Block이란?

테라폼에서 리소스와 같은 최상위 블록 내부에서 반복적인 nested block의 타입을 사용해야하는 경우가 있다. 반복되는 블록을 모두 작성해서 사용 할 수도 있지만, dynamic block을 사용해서 동적으로 생성하도록 구성 할 수 있다.


기본 반복문과의 비교

기본반복문

for_each를 사용한 기본 반복문에서는 resource 블록 자체가 반복문의 대상이 된다.

따라서 생성하려는 리소스가 반복문에 사용되는 변수의 리스트 원소 개수만큼 생성된다.

resource "aws_subnet" "private_subnets" {
  for_each = var.private_subnets

  vpc_id = aws_vpc.vpc.id
  availability_zone = each.value.az
  cidr_block = each.value.cidr_block

  map_public_ip_on_launch = false

  tags = merge(
    var.tags,
    lookup(each.value, "tags", {}),
    { Name = each.key },
  )
}

위 예시에서는 프라이빗 서브넷이 var.private_subnets 에 선언된 리스트의 subnet 개수만큼 생성된다.

Dynamic Block

리소스 자체를 다수로 만드는 기본 반복문과 달리, 리소스 1개를 만들면서 해당 리소스의 구성요소를 여러개 필요로 하는 경우가 있다.

예시를 들어서 설명하면, 아래와 같이 모듈 내 main.tf에서 iam role에 연결되는 inline policy들을 dynamic block을 통해 생성하려고 한다.

  • main.tf
resource "aws_iam_role" "role" {
    name = var.role_name
    assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
    managed_policy_arns = var.managed_policy_arns

    dynamic "inline_policy" {
        for_each = var.inline_policy
        iterator = policy
        content {
            name = policy.value["name"]
            policy = policy.value["policy"]
        }
    }

    tags = var.tags
}

 

다이내믹 블록 내부에 inline_policy에 대한 variable을 생성한다.

  • variables.tf
variable "inline_policy" {
    description = "List of configuration block for a policy statement"
    type = list(object({
        name = string
        policy = any
    }))
    default = []
}

variable "role_name" {
    description = "Name of the role"
    type = string
}

variable "managed_policy_arns" {
    description = "Set of exclusive IAM managed policy ARNs to attach to the IAM role."
    type = list(string)
    default = []
}

variable "tags" {
    description = "A map of tags to add to all resources."
    type = map(string)
    default = {}
}

 

위 모듈을 사용해서 새로운 iam role을 만든다.

  • iam_roles.tf
module "test_role" {
    source = "./modules/role"

    role_name = "test-role"

		inline_policy = [{
	    name = "my_inline_policy_1st"
	    policy = jsonencode({
	      Version = "2012-10-17"
	      Statement = [
	        {
	          Action   = ["ec2:Describe*"]
	          Effect   = "Allow"
	          Resource = "*"
	        },
	      ]
	    })},{
	    name = "my_inline_policy_2nd"
	    policy = jsonencode({
	      Version = "2012-10-17"
	      Statement = [
	        {
	          Action   = ["secretsmanager:ListSecrets"]
	          Effect   = "Allow"
	          Resource = "*"
	        },
	      ]
	    })}
    ]
    tags = local.tags
}

 

이렇게 되면 결과적으로 코드로 풀어보면 아래의 코드와 동일한 결과의 리소스가 생성된다.

resource "aws_iam_role" "example" {
  name               = "test-role"
  
  inline_policy {
    name = "my_inline_policy_1st"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Action   = ["ec2:Describe*"]
          Effect   = "Allow"
          Resource = "*"
        }]
    })
  }

  inline_policy {
    name = "my_inline_policy_2nd"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Action   = ["secretsmanager:ListSecrets"]
          Effect   = "Allow"
          Resource = "*"
        }]
    })
  }
}