✅ 이 블로깅은 테라폼으로 시작하는 IaC 책을 기반으로 작성한다.


입력 변수는 코드 변경 없이 여러 인프라를 생성하는 데 목적이 있다. 다만 테라폼에서 Plan 수행 시에 값을 입력(Input)하는 변수이다.

변수 선언 방식

variable로 시작되는 블록이며, 동일 모듈 내에서 고유한 이름을 가져야 한다.

# variable 블록 선언의 예
variable "<이름>" {
 <인수> = <값>
}

variable "image_id" {
 type = string
}

미리 예약되어 있는 변수 이름이 있어 사용 불가능한 이름이 있고

⇒ source, version, providers, count, for_each, lifecycle, depends_on, locals

변수 정의 시 사용 가능한 메타인수도 있다.

⇒ default, type, descriptio, validation, sensitive, nullable

변수 유형

지원되는 변수 유형은 일반 프로그래밍과 유사하다

  • 기본 유형 : string, number, bool, any
  • 집합 유형 : list, map, set, object, tuple

유효성 검사

validation 블록을 지정해서 유효성 검사를 할 수 있다.

regex 함수는 대상의 문자열에 정규식을 적용하고 일치하는 문자열을 반환하는데, 여기에 can 함수를 함께 사용하면 정규식에 일치하지 않는 경우의 오류를 검출한다.

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-\"."
  }
}

Untitled

image_id는 4글자를 초과하거나 ami- 형식을 따라야 한다. 그렇지 않으면 validation에 실패하게 되어 있다

Untitled 1

조건에 맞는 값을 넣어주면 validation을 통과할 수 있다

이는 기존에 생성해 둔 이미지를 사용할 때 유용하다!

변수 참조

variable은 코드 내에서 var.<이름>으로 참조된다.

variable "my_password" {}

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

패스워드를 입력 변수로 받아서 abc.txt 파일에 저장하는 내용이다.

입력한 변수가 local_file 리소스의 content에 참조되는 값으로 쓰인다.

  1. 패스워드 파일로 저장

     $ terraform apply -auto-approve
     	var.my_password
     	  Enter a value: abc123
        
     	...생략...
    

    apply를 실행하여 패스워드를 입력한다.

     $ terraform state list 
     	local_file.abc
     $ terraform state show local_file.abc
     	# local_file.abc:
     	resource "local_file" "abc" {
     	    content              = "abc123"
     	    content_base64sha256 = "bKE9UspwyIPg8LsQHkJaiehiTeUdstI5JZOvaoQRgJA="
     	    content_base64sha512 = "xwtd2ev7b1HQnUEytxcMnSB1CnhS8AaA9lZY8DEOgQBW5nY8NMmgCw6UAHb1RJXBafwjAszrMSA5JxxDRpUH3A=="
     	    content_md5          = "e99a18c428cb38d5f260853678922e03"
     	    content_sha1         = "6367c48dd193d56ea7b0baad25b19455e529f5ee"
     	    content_sha256       = "6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090"
     	    content_sha512       = "c70b5dd9ebfb6f51d09d4132b7170c9d20750a7852f00680f65658f0310e810056e6763c34c9a00b0e940076f54495c169fc2302cceb312039271c43469507dc"
     	    directory_permission = "0777"
     	    file_permission      = "0777"
     	    filename             = "./abc.txt"
     	    id                   = "6367c48dd193d56ea7b0baad25b19455e529f5ee"
     	}
     $ cat abc.txt 
     	abc123
    

    terraform state로 만들어진 리소스를 확인하거나 직접 파일을 열어봐도 결과를 확인할 수 있다

  2. 패스워드를 변경해 보자!

     $ terraform apply -auto-approve
     	var.my_password
     	  Enter a value: t1013
        	
     	local_file.abc: Refreshing state... [id=6367c48dd193d56ea7b0baad25b19455e529f5ee]
        	
     	Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
     	-/+ destroy and then create replacement
        	
     	Terraform will perform the following actions:
        	
     	  # local_file.abc must be replaced
        
     	...생략...
    

    그럼 기존 파일은 destroy되고 다시 create되었다

     $ terraform state list 
     	local_file.abc
     $ terraform state show local_file.abc
     	# local_file.abc:
     	resource "local_file" "abc" {
     	    content              = "t1013"
     	    content_base64sha256 = "PFB8tC2DAaG2dU90AbURyMH0TlQKyOMAl11pD8iMEGo="
     	    content_base64sha512 = "Fg7M34d/JafyjLxxoxtZJ4leZizYgLb302cw1CD/9go59x9h1TQJQThFsCxiKHwN79pSZGhLdHSkJqVXasMDFA=="
     	    content_md5          = "519a6f29465c675e6f2b8820f5142bfe"
     	    content_sha1         = "519cacb9a0e2c53ab605a560dfa3590aa3abb3fc"
     	    content_sha256       = "3c507cb42d8301a1b6754f7401b511c8c1f44e540ac8e300975d690fc88c106a"
     	    content_sha512       = "160eccdf877f25a7f28cbc71a31b5927895e662cd880b6f7d36730d420fff60a39f71f61d53409413845b02c62287c0defda5264684b7474a426a5576ac30314"
     	    directory_permission = "0777"
     	    file_permission      = "0777"
     	    filename             = "./abc.txt"
     	    id                   = "519cacb9a0e2c53ab605a560dfa3590aa3abb3fc"
     	}
     $ cat abc.txt 
     	t1013
    

    변경한 패스워드가 바로 반영되어 replace되었다.

  3. terraform destroy에도 필요한 패스워드(!)

     $ terraform destroy -auto-approve
     	var.my_password
     	  Enter a value: t1013
        	
     	local_file.abc: Refreshing state... [id=519cacb9a0e2c53ab605a560dfa3590aa3abb3fc]
        	
     	Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
     	  - destroy
        	
     	Terraform will perform the following actions:
        	
     	  # local_file.abc will be destroyed
        	
     	...생략...
    

민감한 변수 취급

패스워드와 같은 민감한 입력 변수를 위해 테라폼 0.14.0 버전부터 입력 변수의 민감 여부를 sensitive를 통해 선언할 수 있다.

variable "my_password" {
  default   = "password"
  sensitive = true
}

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

Untitled 2

Untitled 3

apply를 실행할 때와 리소스를 terraform console로 확인해 보면 출력은 sensitive로 가려져 있다!

$ cat abc.txt 
	password
$ cat terraform.tfstate | grep '"content":'
	            "content": "password",

출력에서 sensitive로 가려져 있어도 저장된 abc.txt 파일과 tfstate 파일에는 결과물이 평문으로 기록되므로 State 파일의 보안에 유의해야 한다!!!

변수 입력 방식과 우선순위

variable의 목적은 코드 내용을 수정하지 않고 테라폼의 모듈적 특성을 통해 입력되는 변수로 재사용성을 높이는 데 있다.

선언 방식에 따라 변수의 우선순위가 있는데, 배포 환경에 따라 다른 변수 값을 주거나 프로비저닝 파이프라인 구성 시에 외부 값을 지정하는 데에 사용할 수도 있다고 한다!

Untitled 4

그림 출처 : https://spacelift.io/blog/terraform-tfvars

[우선순위 수준 1] 실행 후 입력

variable "my_var" {}

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

우선 main.tf를 하나 만들어서 variable에 아무 값도 넣어주지 않는 상태로 입력받는다.

$ terraform apply -auto-approve
	var.my_var
	  Enter a value: var1
$ echo "local_file.abc.content" | terraform console 
	"var1"

그럼 처음 생성된 파일에는 당연히 var1이 저장되어 있다

[우선순위 수준 2] variable 블록의 default 값

variable "my_var" {
  default = "var2"
}

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

이번엔 variable 블록에 default 값을 지정해 준다

$ terraform apply -auto-approve
	  # local_file.abc must be replaced
	-/+ resource "local_file" "abc" {
	      ~ content              = "var1" -> "var2" # forces replacement

$ echo "local_file.abc.content" | terraform console 
	"var2"

forces replacement 메세지와 함께 var2로 덮어쓰기되었다!

[우선순위 수준 3] 환경 변수 (TF_VAR 변수 이름)

시스템 환경 변수의 접두사에 TF_VAR_ 가 포함되면 그 뒤의 문자열을 변수 이름으로 인식한다.

$ export TF_VAR_my_var=var3
$ echo ${TF_VAR_my_var}
	var3

main.tf 파일은 그대로 둔 채로 TF_VAR_을 포함한 시스템 환경 변수만 추가해 준다

$ terraform apply -auto-approve
	  # local_file.abc must be replaced
	-/+ resource "local_file" "abc" {
	      ~ content              = "var2" -> "var3" # forces replacement

$ echo "local_file.abc.content" | terraform console 
	"var3"

이번에도 var3으로 변경되었다!

[우선순위 수준 4] terraform.tfvars에 정의된 변수 선언

$ echo 'my_var="var4"' > terraform.tfvars
$ cat terraform.tfvars 
	my_var="var4"

루트 모듈의 main.tf 파일과 같은 위치에 terraform.tfvars 파일을 생성해 변수에 대한 값을 추가한다

$ terraform apply -auto-approve
	  # local_file.abc must be replaced
	-/+ resource "local_file" "abc" {
	      ~ content              = "var3" -> "var4" # forces replacement

$ echo "local_file.abc.content" | terraform console 
	"var4"

마찬가지로 var4으로 변경되었다

[우선순위 수준 5] *.auto.tfvars에 정의된 변수 선언

파일명의 정렬에 따라 우선순위가 적용된다.

$ echo 'my_var="var5_a"' > a.auto.tfvars
$ ls *.tfvars
	a.auto.tfvars  terraform.tfvars

먼저 a로 시작하는 .auto.tfvars 파일을 생성한다.

$ terraform apply -auto-approve
	  # local_file.abc must be replaced
	-/+ resource "local_file" "abc" {
	      ~ content              = "var4" -> "var5_a" # forces replacement

$ echo "local_file.abc.content" | terraform console 
	"var5_a"

해당 값이 var5_a로 변경되어 있다

동일하게 b 파일을 만들어 봤는데 또 var5_b로 변경되어 있길래 생성 순서에 영향을 받나 의심이 들어서 마구잡이로 만들어 보았다

$ echo 'my_var="var5_e"' > e.auto.tfvars
$ echo 'my_var="var5_c"' > c.auto.tfvars
$ echo 'my_var="var5_z"' > z.auto.tfvars
$ ls *.tfvars
	a.auto.tfvars  b.auto.tfvars  c.auto.tfvars  e.auto.tfvars  terraform.tfvars  z.auto.tfvars

결과는 var5_z로 변경되어 있었고 마지막 테스트를 진행했다

$ echo 'my_var="var5_d"' > d.auto.tfvars
$ ls *.tfvars
	a.auto.tfvars  b.auto.tfvars  c.auto.tfvars  d.auto.tfvars  e.auto.tfvars  terraform.tfvars  z.auto.tfvars
$ terraform apply -auto-approve
	local_file.abc: Refreshing state... [id=cfd7961959faa23162d57368a3480511e3a7cc03]
	
	No changes. Your infrastructure matches the configuration.
	
	Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
	
	Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

abcez중에서 가운데에 낄 수밖에 없는 d를 만들었고 결과는 변경 사항이 없었다!

*.auto.tfvars 파일 중에서는 파일명 정렬이 맨 나중일수록 우선순위가 높더라!

[우선순위 수준 6] *.auto.tfvars.json에 정의된 변수 선언

*.auto.tfvars와 같이 파일명의 정렬에 따라 우선순위가 적용된다

나는 무조건 json 파일이 더 우선순위가 높을 줄 알았는데 *.auto.tfvars와 유사했다

$ cat <<EOF > a.auto.tfvars.json
	> {
	>   "my_var" : "var6_a"
	> }
	> EOF
$ ls *.tfvars ; ls *.json
	a.auto.tfvars  b.auto.tfvars  c.auto.tfvars  d.auto.tfvars  e.auto.tfvars  terraform.tfvars  z.auto.tfvars
	a.auto.tfvars.json
$ terraform apply -auto-approve
	local_file.abc: Refreshing state... [id=cfd7961959faa23162d57368a3480511e3a7cc03]
	
	No changes. Your infrastructure matches the configuration.
	
	Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
	
	Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
$ echo "local_file.abc.content" | terraform console 
	"var5_z"

z.auto.tfvars이 정렬이 제일 나중이었기에 값에 변경사항은 없었다

$ cat <<EOF > z1.auto.tfvars.json
	{
	  "my_var" : "var6_z1"
	}
	EOF
$ ls *.tfvars *.json
	a.auto.tfvars  a.auto.tfvars.json  b.auto.tfvars  c.auto.tfvars  d.auto.tfvars  e.auto.tfvars  terraform.tfvars  z.auto.tfvars  z1.auto.tfvars.json
$ terraform apply -auto-approve
	  # local_file.abc must be replaced
	-/+ resource "local_file" "abc" {
	      ~ content              = "var5_z" -> "var6_z1" # forces replacement
	
$ echo "local_file.abc.content" | terraform console 
	"var6_z1"

그래서 이번엔 z1으로 우선순위를 제일 높였더니 예상대로 var6_z1으로 값이 변경되었다

[우선순위 수준 7] CLI 실행 시 -var 인수에 지정 또는 -var-file로 파일 지정

  • 여러 인수가 선언되는 경우 나중에 선언된 변수의 우선순위가 높다

      $ terraform apply -auto-approve -var=my_var=var7
      	  # local_file.abc must be replaced
      	-/+ resource "local_file" "abc" {
      	      ~ content              = "var6_z1" -> "var7" # forces replacement
              
      $ echo "local_file.abc.content" | terraform console 
      	"var7"
    

    값을 var7로 만든 상태에서

      $ terraform apply -auto-approve -var=my_var=var8 -var=my_var=var7
      	local_file.abc: Refreshing state... [id=e809b87931786a59488444d74f62b55428b0a44a]
        	
      	No changes. Your infrastructure matches the configuration.
        
      	Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
        	
      	Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
    

    일부러 var7을 나중에 선언해 보았는데 역시 변경 사항이 없었고

      $ terraform apply -auto-approve -var=my_var=var7 -var=my_var=var8
      	  # local_file.abc must be replaced
      	-/+ resource "local_file" "abc" {
      	      ~ content              = "var7" -> "var8" # forces replacemen
      $ echo "local_file.abc.content" | terraform console 
      	"var8"
    

    var8을 나중에 선언해 보니 var8로 변경된 것을 확인할 수 있었다

  • *.tfvars와 같은 형식의 내용의 파일이라면 -var-file로 지정할 수 있다.

      $ echo 'my_var="var9"' > var9.txt
      $ cat var9.txt 
      	my_var="var9"
    
      $ terraform apply -auto-approve -var=my_var=var7 -var-file="var9.txt"
      	  # local_file.abc must be replaced
      	-/+ resource "local_file" "abc" {
      	      ~ content              = "var8" -> "var9" # forces replacement
        	
      $ echo "local_file.abc.content" | terraform console 
      	"var9"
    

    var7을 인수로 주었음에도 불구하고 -var-file을 나중에 선언했기 때문에 var9로 변경된 점을 확인할 수 있었다.

결론

  • .tfvars 확장자로 생성된 파일에 변수를 미리 기입하면 실행 시 입력해야 하는 변수 값을 하나의 파일에서 관리할 수 있다는 장점이 있다.
  • variable은 코드 수정없이 입력 변수로 테라폼의 재사용성을 높일 수 있다
  • 변수 입력에는 우선순위가 있으므로 이를 잘 활용하여 파일로 관리하거나 빌드 환경에 따라 분리해 주는 데에 용이할 듯하다

Categories:

Updated:

Leave a comment