본문 바로가기

IaC/Terraform

[Terraform]반복문(For)을 사용하여 resource 작성하는 방법

Terraform의 반복문(Loops) 기능은 기본적인 코드 구성을 최소화하면서 다양한 리소스를 생성하거나 관리할 때 유용합니다.

기본 문법

핵심 개념

  1. Input Collection: for 키워드 뒤에 오는 컬렉션은 반복을 수행할 대상이 됩니다.
  2. Output Expression: 콜론(:) 뒤의 표현식은 각 반복마다의 결과를 결정합니다.
  3. Condition: if 키워드를 사용하여 조건을 지정할 수 있습니다. 이 조건에 맞는 항목만 결과로 포함됩니다.

Input Types

  • A for expression's input (given after the in keyword) can be
    • a list
    • a set
    • a tuple
    • a map
    • an object.

Lists & Sets

[for <VARIABLE> in <COLLECTION> : <EXPRESSION> if <CONDITION>]

Example

주어진 숫자 목록에서 각 숫자를 제곱하고, 그 결과 중 10보다 큰 값을 필터링합니다. 결과: [16, 25]

variable "numbers" {
  default = [2, 3, 4, 5]
}

output "squared_numbers_above_ten" {
  value = [for n in var.numbers : n * n if n * n > 10]
}

Maps & Objects

[for <KEY>, <VALUE> in <MAP> : <KEY_EXPRESSION> => <VALUE_EXPRESSION> if <CONDITION>]

Example

주어진 맵에서 값이 "active"인 항목만 추출합니다. 결과: { alice = "active", carol = "active" }

variable "status_map" {
  default = {
    alice = "active"
    bob   = "inactive"
    carol = "active"
    dave  = "pending"
  }
}

output "active_users" {
  value = {for k, v in var.status_map : k => v if v == "active"}
}

Example

  • iam group 만들기
  • iam user 정의
  • terraform.tfvars 작성

terraform.tfvars 작성

users = [
  {
    name = "jeff"
    level = 3
    role = "주니어 개발자"
    is_developer = true
  },
  {
    name = "jmhan"
    level = 3
    role = "마케터"
    is_developer = false
  },
  {
    name = "lucia"
    level = 4
    role = "데브옵스"
    is_developer = true
  },
  {
    name = "rachel"
    level = 9
    role = "매니저"
    is_developer = false
  },
]

iam_group, iam_user 생성하기

provider "aws" {
  region = "ap-northeast-2"
}

# group 만들기
resource "aws_iam_group" "developer" {
  name = "developer"
}

resource "aws_iam_group" "employee" {
  name = "employee"
}

output "groups" {
  value = [
    aws_iam_group.developer,
    aws_iam_group.employee
  ]
}

# user 만들기
## 변수로 주입 - terraform.tfstate
variable "users" {
  type = list(any)
}

## for_each_map을 사용하여 대입
## key: user.name, value: user
resource "aws_iam_user" "for_user" {
  for_each = {
    for user in var.users :
    user.name => user
  }
  name = each.key

  # each.value에는 for_each_map에서의 key,value 값이 들어간다.
  tags = {
    level = each.value.level
    role  = each.value.role
  }
}

## 조건문으로 is_developer을 체크하여 group의 이름을 return한다.
resource "aws_iam_user_group_membership" "iam_membership" {
  for_each = {
    for user in var.users :
    user.name => user
  }

  user   = each.key
  groups = each.value.is_developer ? [aws_iam_group.developer.name, aws_iam_group.employee.name] : [aws_iam_group.employee.name]
}

IAM Group & User 생성: for_each를 사용하여 다양한 사용자에 대한 IAM 사용자를 생성하고, 그들을 적절한 IAM 그룹에 할당했습니다.

결과 - tf apply

# 중략
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_iam_user.for_user["jeff"]: Creating...
aws_iam_user.for_user["rachel"]: Creating...
aws_iam_user.for_user["lucia"]: Creating...
aws_iam_group.developer: Creating...
aws_iam_group.employee: Creating...
aws_iam_user.for_user["jmhan"]: Creating...
aws_iam_group.developer: Creation complete after 1s [id=developer]
aws_iam_user.for_user["lucia"]: Creation complete after 1s [id=lucia]
aws_iam_group.employee: Creation complete after 1s [id=employee]
aws_iam_user.for_user["jmhan"]: Creation complete after 1s [id=jmhan]
aws_iam_user_group_membership.iam_membership["rachel"]: Creating...
aws_iam_user_group_membership.iam_membership["jmhan"]: Creating...
aws_iam_user_group_membership.iam_membership["jeff"]: Creating...
aws_iam_user_group_membership.iam_membership["lucia"]: Creating...
aws_iam_user.for_user["jeff"]: Creation complete after 1s [id=jeff]
aws_iam_user.for_user["rachel"]: Creation complete after 1s [id=rachel]
aws_iam_user_group_membership.iam_membership["jmhan"]: Creation complete after 1s [id=terraform-20230115125449700200000001]
aws_iam_user_group_membership.iam_membership["rachel"]: Creation complete after 1s [id=terraform-20230115125449701800000002]
aws_iam_user_group_membership.iam_membership["lucia"]: Creation complete after 1s [id=terraform-20230115125449921000000003]
aws_iam_user_group_membership.iam_membership["jeff"]: Creation complete after 1s [id=terraform-20230115125449925800000004]

Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

Outputs:

groups = [
  {
    "arn" = "arn:aws:iam:::group/developer"
    "id" = "developer"
    "name" = "developer"
    "path" = "/"
    "unique_id" = "AGPAZYURONAV3HZHAUJRQ"
  },
  {
    "arn" = "arn:aws:iam:::group/employee"
    "id" = "employee"
    "name" = "employee"
    "path" = "/"
    "unique_id" = "AGPAZYURONAV47DC2TLYH"
  },

조건을 확인하여 IAM 권한 부여하기

depends_on

  • 의존성 관계를 정의해 준다.
# locals
locals {
  ## locals 안에 지역변수(type list) developers를 이용하여 var.user에서 is_developer 여부가 true인 경우만 return  
  developers = [
    for user in var.users :
    user
    if user.is_developer
  ]
}

resource "aws_iam_user_policy_attachment" "developer" {
    for_each = {
      for user in local.developers :
      user.name => user
    }

    user = each.key
    policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"

    depends_on = [
      aws_iam_user.for_user
    ]
}

# output으로 developer 목록 출력
output "developers" {
    value = local.developers
}

# output으로 high level user 출력
output "high_level_users" {
    value = [
        for user in var.users :
        user
        if user.level > 5
    ]
}

조건부 권한 할당: localsfor를 조합하여 개발자만을 필터링하고, 이들에게만 특정 IAM 정책을 할당했습니다.

결과 - tf apply

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_iam_user_policy_attachment.developer["jeff"]: Creating...
aws_iam_user_policy_attachment.developer["lucia"]: Creating...
aws_iam_user_policy_attachment.developer["jeff"]: Creation complete after 1s [id=jeff-20230115134459401300000001]
aws_iam_user_policy_attachment.developer["lucia"]: Creation complete after 1s [id=lucia-20230115134459412800000002]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

developers = [
  {
    "is_developer" = true
    "level" = 3
    "name" = "jeff"
    "role" = "주니어 개발자"
  },
  {
    "is_developer" = true
    "level" = 4
    "name" = "lucia"
    "role" = "데브옵스"
  },
]
groups = [
  {
    "arn" = "arn:aws:iam:::group/developer"
    "id" = "developer"
    "name" = "developer"
    "path" = "/"
    "unique_id" = "AGPAZYURONAV3HZHAUJRQ"
  },
  {
    "arn" = "arn:aws:iam:::group/employee"
    "id" = "employee"
    "name" = "employee"
    "path" = "/"
    "unique_id" = "AGPAZYURONAV47DC2TLYH"
  },
]
high_level_users = [
  {
    "is_developer" = false
    "level" = 9
    "name" = "rachel"
    "role" = "매니저"
  },