본문 바로가기
Terraform/Terraform 101 Study

2주차 1편 테라폼 기초 - 기본 사용 2/3

by 개발자 영만 2024. 6. 16.

3.5 데이터 소스

  • Terraform에서는 데이터 소스를 사용하여 테라폼 코드 외부에서 정의된 리소스저장된 정보를 참조할 수 있습니다.
  • 이를 통해 기존 리소스를 활용하거나 외부 데이터를 가져와서 테라폼 코드 내에서 사용할 수 있습니다.

데이터 소스 구성

  • 데이터 소스 블록은 data로 시작하며, 리소스 블록과 유사하게 구성됩니다.
  • 데이터 소스 유형은 '프로바이더_리소스유형' 형태로 정의됩니다.
data "local_file" "abc" {
  filename = "${path.module}/abc.txt"
}
  • 데이터 소스를 정의할 때 사용할 수 있는 메타인수는 다음과 같습니다
    • depends_on: 종속성을 선언하여 특정 리소스의 생성 시점을 정의합니다.
    • count: 여러 리소스를 생성합니다.
    • for_each: map 또는 set 타입의 데이터 배열을 기반으로 여러 리소스를 생성합니다.
    • lifecycle: 리소스의 수명주기를 관리합니다.
  • 실습
# 실습을 위한 abc.txt 파일 생성
echo "t101 study - 2week" > abc.txt

# 테라폼 명령어 실행
terraform init && terraform plan && terraform apply -auto-approve
terraform state list

# 테라폼 콘솔에서 데이터 소스 참조 확인
terraform console
> data.local_file.abc
...
> data.local_file.abc.filename
...
> data.local_file.abc.content
...
> data.local_file.abc.id
...
exit

 

데이터 소스 속성 참조

  • 데이터 소스를 테라폼에서 참조하는 방식은 리소스와 구별되게 data가 앞에 붙습니다. 속성 값은 다음과 같이 접근할 수 있습니다.
# Terraform Code
data "<리소스 유형>" "<이름>" {
  <인수> = <값>
}

# 데이터 소스 참조
data.<리소스 유형>.<이름>.<속성>

 

AWS 가용영역 인수 정의 예시

  • AWS 가용영역을 데이터 소스로 가져와 서브넷의 가용영역을 설정하는 예시입니다
# Declare the data source
data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "primary" {
  availability_zone = data.aws_availability_zones.available.names[0]
  # e.g. ap-northeast-2a
}

resource "aws_subnet" "secondary" {
  availability_zone = data.aws_availability_zones.available.names[1]
  # e.g. ap-northeast-2b
}
  • 아래 문서에서 데이터 소스로 가져오기 위한 조건인 인수는 Argument로 표현되어 있고, 가져온 데이터 소스의 내용은 Attributes에 안내되어 있다

데이터 소스 속성 참조 확인

  • main.tf 파일 수정
data "aws_availability_zones" "seoul" {
  state = "available"
}
  • 테라폼 명령어 실행
terraform init -upgrade && terraform plan && terraform apply -auto-approve
terraform state list

  • 데이터 소스 속성 확인
terraform state show data.aws_availability_zones.seoul

  • 테라폼 콘솔에서 데이터 소스 참조 확인
terraform console
> data.aws_availability_zones.seoul
...
> data.aws_availability_zones.seoul.id
...
> data.aws_availability_zones.seoul.names
...
> data.aws_availability_zones.seoul.zone_ids
...
exit

# Tip. terraform console 값 echo로 확인
echo "data.aws_availability_zones.seoul" | terraform console
echo "data.aws_availability_zones.seoul.names" | terraform console
echo "data.aws_availability_zones.seoul.names[0]" | terraform console
echo "data.aws_availability_zones.seoul.names[1]" | terraform console
echo "data.aws_availability_zones.seoul.zone_ids[0]" | terraform console

  • main.tf 파일 코드 수정
resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

data "local_file" "abc" {
  filename = local_file.abc.filename
}

resource "local_file" "def" {
  content  = data.local_file.abc.content
  filename = "${path.module}/def.txt"
}
  • 테라폼 명령어 실행 및 결과 확인
terraform apply -auto-approve
terraform state list

  • 파일 확인

  • 그래프 확인

  • 테라폼 콘솔에서 데이터 소스 참조 확인

 

 

3.6 입력 변수 Variable

  • 입력 변수는 인프라를 구성하는 데 필요한 속성 값을 정의하여 코드의 변경 없이 여러 인프라를 생성하는 데 목적이 있습니다. 테라폼에서는 이를 입력 변수(Input Variables)로 정의합니다.

변수 선언 방식

  • 변수는 variable로 시작하는 블록으로 구성되며, 이 블록 뒤의 이름 값은 동일 모듈 내에서 고유해야 합니다. 변수를 선언한 후, 코드 내에서 해당 변수를 참조할 수 있습니다.
variable "<이름>" {
  <인수> = <값>
}

variable "image_id" {
  type = string
}
  • 다음 예약 변수 이름은 변수로 사용할 수 없습니다.
    • source, version, providers, count, for_each, lifecycle, depends_on, locals
  • 변수 정의 시 사용 가능한 메타인수
    • default: 기본값을 설정합니다. 여러 방법으로 값을 전달하지 않으면 기본값이 사용됩니다. 기본값이 없으면 대화식으로 사용자에게 값을 물어봅니다.
    • type: 변수에 허용되는 값 유형을 정의합니다. 지원되는 유형은 string, number, bool, list, map, set, object, tuple 등이 있습니다. 유형을 지정하지 않으면 any 유형으로 간주됩니다.
    • description: 입력 변수의 설명을 작성합니다.
    • validation: 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의합니다.
    • sensitive: 민감한 변수 값임을 알리며 테라폼 출력문에서 값 노출을 제한합니다. 주로 암호와 같은 민감 데이터를 다룰 때 사용합니다.
    • nullable: 변수에 값이 없어도 됨을 지정합니다.

변수 유형

  • 기본 유형
    • string: 문자열
    • number: 숫자
    • bool: true 또는 false
    • any: 모든 유형
  • 집합 유형
    • list (<유형>): 인덱스 기반 집합
    • map (<유형>): 값 = 속성 기반 집합, 키값 기준 정렬
    • set (<유형>): 값 기반 집합, 정렬 키값 기준 정렬
    • object ({<인수 이름>=<유형>, …}): 복잡한 구조체
    • tuple ([<유형>, …]): 순서가 있는 복합 데이터 타입
  • list와 set은 선언하는 형태가 비슷하지만 참조 방식이 인덱스(list)와 키(set)로 차이가 있습니다. map와 set은 선언된 값이 정렬되는 특징을 가집니다.

입력 변수 사용 예시

  • number 유형의 변수 선언 예시
variable "number_example" {
  description = "An example of a number variable in Terraform"
  type        = number
  default     = 42
}
  • list 유형의 변수 선언 예시
variable "list_example" {
  description = "An example of a list in Terraform"
  type        = list
  default     = ["a", "b", "c"]
}
  • 리스트의 모든 항목이 numberlist 예시
variable "list_numeric_example" {
  description = "An example of a numeric list in Terraform"
  type        = list(number)
  default     = [1, 2, 3]
}
  • 모든 값이 stringmap 예시
variable "map_example" {
  description = "An example of a map in Terraform"
  type        = map(string)
  default = {
    key1 = "value1"
    key2 = "value2"
    key3 = "value3"
  }
}
  • object 또는 tuple을 사용한 복잡한 구조적 유형 예시
variable "object_example" {
  description = "An example of a structural type in Terraform"
  type        = object({
    name    = string
    age     = number
    tags    = list(string)
    enabled = bool
  })
  default = {
    name    = "value1"
    age     = 42
    tags    = ["a", "b", "c"]
    enabled = true
  }
}
  • main.tf 파일 코드 수정
variable "string" {
  type        = string
  description = "var String"
  default     = "myString"
}

variable "number" {
  type    = number
  default = 123
}

variable "boolean" {
  default = true
}

variable "list" {
  default = [
    "google",
    "vmware",
    "amazon",
    "microsoft"
  ]
}

output "list_index_0" {
  value = var.list[0]
}

output "list_all" {
  value = [
    for name in var.list : upper(name)
  ]
}

variable "map" { # Sorting
  default = {
    aws   = "amazon",
    azure = "microsoft",
    gcp   = "google"
  }
}

variable "set" { # Sorting
  type = set(string)
  default = [
    "google",
    "vmware",
    "amazon",
    "microsoft"
  ]
}

variable "object" {
  type = object({ name = string, age = number })
  default = {
    name = "abc"
    age  = 12
  }
}

variable "tuple" {
  type    = tuple([string, number, bool])
  default = ["abc", 123, true]
}

variable "ingress_rules" { # optional (>= Terraform 1.3.0)
  type = list(object({
    port        = number,
    description = optional(string),
    protocol    = optional(string, "tcp"),
  }))
  default = [
    { port = 80, description = "web" },
    { port = 53, protocol = "udp" }
  ]
}
  • 확인
terraform init && terraform plan && terraform apply -auto-approve
terraform state list
terraform output

 

유효성 검사

  • 변수 블록 내 validation 블록에서 정의되며, 사용자가 지정한 유효성 검사를 수행합니다.
  • condition: validation 블록 내에 위치하며, true 또는 false를 반환하는 조건을 지정합니다. 이 조건은 유효성 검사를 통과할지 여부를 결정합니다.
  • error_message: condition이 false를 반환할 경우 출력되는 메시지를 정의합니다. 즉, 유효성 검사에 실패했을 때 사용자에게 보여줄 오류 메시지입니다.
  • regex 함수: 문자열에 대해 정규식을 적용하여 일치하는 부분을 반환합니다. 이 함수는 유효성 검사에서 정규식 불일치를 검출하는 데 사용될 수 있습니다.
  • can 함수: regex 함수와 함께 사용하여, 정규식에 일치하지 않는 경우 오류를 검출할 수 있습니다. 즉, 문자열이 정해진 패턴에 맞지 않을 때 오류를 발생시킬 수 있습니다.
  • 변수 블록 내에서 여러 개의 validation 블록을 중복하여 선언할 수 있습니다. 이는 여러 개의 유효성 검사를 순서대로 적용할 수 있음을 의미합니다.
  • main.tf 파일 코드 수정
variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    condition     = length(var.image_id) > 4
    error_message = "The image_id value must exceed 4."
  }

  validation {
    # regex(...) fails if it cannot find a match
    condition     = can(regex("^ami-", var.image_id))
    error_message = "The image_id value must starting with \"ami-\"."
  }
}
  • 확인 - 4자 미만 & ami- 접두사가 없는 image_id를 입력한 경우
# 4자 미만 & "ami-" 접두사가 없는 image_id를 입력한 경우
terraform apply -auto-approve
var.image_id
  The id of the machine image (AMI) to use for the server.

  Enter a value: ami
...

  • 확인 - 4자 미만의 image_id를 입력한 경우
# 4자 미만의 image_id를 입력한 경우#
terraform apply -auto-approve
var.image_id
  The id of the machine image (AMI) to use for the server.

  Enter a value: ami-
...

  • 확인 - 유효한 image_id를 입력한 경우
# 유효성 검사 만족
terraform apply -auto-approve
var.image_id
  The id of the machine image (AMI) to use for the server.

  Enter a value: ami-12345678
...

 

변수 참조

  • Terraform에서 변수는 var.<이름> 형식으로 코드 내에서 참조됩니다.
  • main.tf 파일 코드 수정
variable "my_password" {}

resource "local_file" "abc" {
  content  = var.my_password
  filename = "${path.module}/abc.txt"
}
  • 실행
# 초기화 및 적용
terraform init -upgrade && terraform apply -auto-approve
...
var.my_password
  Enter a value: qwe123
...

# 상태 확인
terraform state list
terraform state show local_file.abc

# 파일 내용 확인
cat abc.txt ; echo

# 변경 및 재적용
terraform apply -auto-approve
var.my_password
  Enter a value: t101mypss
...

# 변경된 파일 내용 확인
cat abc.txt ; echo

 

민감한 변수 취급

  • Terraform에서는 변수를 민감한 값으로 표시할 수 있습니다. 이는 보안상의 이유로 변수 값을 출력할 때 가려진(sensitive) 형태로 나타나도록 만드는 기능입니다.
  • 아 예시에서 sensitive = true는 my_password 변수가 민감한 정보를 포함하고 있음을 선언합니다.
variable "my_password" {
  default   = "password"
  sensitive = true
}

resource "local_file" "abc" {
  content  = var.my_password
  filename = "${path.module}/abc.txt"
}
  • Terraform에서 terraform apply나 terraform state show 명령어를 사용할 때, 민감한 변수의 값은 출력에서 가려집니다. (sensitive value)로 표시됩니다.
  • terraform.tfstate 파일에는 민감한 변수 값이 평문으로 기록되므로 State 파일의 보안에 유의해야 합니다.
# 민감한 값 처리 확인
terraform apply -auto-approve
...
      ~ content              = (sensitive value) # forces replacement
...

terraform state show local_file.abc
...
    content              = (sensitive value)
...

echo "local_file.abc.content" | terraform console
(sensitive value)

# 결과물 확인
cat abc.txt ; echo

# terraform.tfstate 파일 확인
cat terraform.tfstate | grep '"content":'
            "content": "password",

 

terraform.tfstate 파일을 보안적으로 안전하게 관리하기 위한 주요 방안

  • 파일 암호화: terraform.tfstate 파일을 암호화하여 저장하거나 관리합니다. 이를 위해 클라우드 제공자의 키 매니지먼트 서비스나 Terraform Vault와 같은 시크릿 관리 도구를 활용할 수 있습니다.
  • 접근 제어 및 권한 관리: 파일에 접근할 수 있는 권한을 최소한의 필요성에 맞춰 제한하고, 접근 로그를 검토하여 보안 사고를 사전에 탐지할 수 있도록 합니다.
  • 정기적인 보안 검토: terraform.tfstate 파일을 정기적으로 검토하여 민감한 정보가 노출되지 않도록 유지합니다.

변수 입력 방식과 우선순위

  • 변수는 코드 수정 없이 재사용 가능한 값으로, 특히 테라폼의 모듈적 특성을 활용하여 다양한 환경에서 동일한 모듈을 사용할 수 있도록 합니다.
  • 사용자는 프로비저닝 실행 시 원하는 값을 변수에 정의할 수 있습니다. 이는 테라폼에서 프로비저닝하고자 하는 리소스나 환경에 필요한 설정 값을 제공하는 데 사용됩니다.
  • 변수는 여러 방식으로 선언될 수 있으며, 이에 따라 우선순위가 결정됩니다. 일반적인 우선순위는 다음과 같습니다
    • 환경 변수(Environment Variables): 로컬 시스템이나 빌드 서버의 환경 변수를 통해 변수 값이 설정될 수 있습니다. 이는 보통 우선순위가 가장 높습니다.
    • tfvars 파일: 테라폼 변수 파일(tfvars 파일)을 사용하여 변수 값을 정의할 수 있습니다. 이 파일은 특정 환경에 맞게 설정할 수 있습니다.
    • 모듈 입력 변수: 모듈 호출 시 인라인으로 변수 값을 전달할 수 있습니다. 이는 모듈을 호출하는 부분에서 변수를 설정할 때 사용됩니다.
    • 기본값(Default Value): 변수가 선언될 때 기본값을 지정할 수 있습니다. 기본값은 다른 방식으로 값이 설정되지 않았을 때 사용됩니다.
  • main.tf 파일 코드 수정
variable "my_var" {}

resource "local_file" "abc" {
  content  = var.my_var
  filename = "${path.module}/abc.txt"
}