LabHub
배우기 러닝패스 코스

Infrastructure as Code

The security rule was copy-pasted to three places and prod was missed

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

이미 운영 중인 복붙 환경 둘을 moved 로 교체 없이 모듈 호출로 바꾸고, 모듈을 git 태그로 고정해 dev 만 새 버전을 쓰게 한 뒤, 변수 값이 들어오는 경로의 우선순위와 모듈 경계의 입력 검증을 확인합니다.

왜 중요한가

복붙한 환경은 한 곳을 고칠 때마다 나머지를 빼먹을 기회를 만듭니다. 그렇다고 이미 적용된 코드를 모듈로 옮기면서 리소스 주소가 바뀌면 도구는 그것을 지우고 다시 만들려 하므로, 리팩터링은 상태에 이동을 알리는 일과 함께 해야 합니다. 모듈에 버전이 없으면 모듈을 고친 순간 모든 환경이 같이 바뀌어 '관계없는 환경이 깨짐' 이 생기고, 값이 여러 경로로 들어오는 규칙을 모르면 실험하다 남긴 파일 하나가 운영 값을 조용히 바꿉니다.

단계

  1. /root/iac-mod/dev/main.tf/root/iac-mod/prod/main.tf 에 같은 모양의 리소스 둘을 두세요. local_file.configout/app.confname=api, env=<환경>, replicas=<수> 세 줄(dev 1, prod 3), local_file.bannerout/banner.txtapi (<환경>) 한 줄입니다. 두 디렉터리 모두 init·apply 하세요.
  2. /root/iac-mod/modules/web/main.tf 에 입력 env(문자열)·replicas(수), 같은 두 리소스, 출력 config_path 를 둔 모듈을 만드세요. dev 의 main.tf 는 replicas 변수(기본 1)를 두고 module "web"source = "../modules/web" 로 부르며, moved 블록 두 개로 옛 주소를 module.web.local_file.config·module.web.local_file.banner 로 옮기세요. init 한 뒤 계획에 생성·삭제·교체가 없어야 하고, 그대로 apply 합니다.
  3. /root/iac-mod/prod/main.tf 도 같은 모듈을 부르게 바꾸세요(replicas 기본 3, env prod, moved 두 개). 계획에 생성·삭제·교체가 없어야 하고 apply 합니다. 이제 규칙을 고칠 곳은 모듈 한 곳입니다.
  4. /root/iac-mod/modules/web 을 git 저장소로 만들어 지금 내용을 커밋하고 태그 v1.0.0 을 붙이세요. dev·prod 의 source 를 git::file:///root/iac-mod/modules/web?ref=v1.0.0 로 바꾸고 tofu init -upgrade 한 뒤 두 계획이 모두 깨끗해야 합니다.
  5. 모듈에 두 가지를 더해 커밋하고 태그 v2.0.0 을 붙이세요: config 내용 끝에 owner=platform 한 줄, 그리고 replicas 가 1 이상 10 이하인지 검사하는 validation. dev 만 ref=v2.0.0 으로 올려 init·apply 하고, prod 는 v1.0.0 에 남겨 계획이 깨끗해야 합니다.
  6. dev 에서 replicas 값을 여러 경로로 넣어 보며 echo var.replicas | tofu console 로 실제 값을 확인하고 /root/iac-mod/precedence.txt 에 적으세요. 모든 경우에 환경 변수 TF_VAR_replicas=9 가 있습니다. env_only(파일 없음), with_tfvars(terraform.tfvars 에 2), with_auto(여기에 a.auto.tfvars 3·b.auto.tfvars 4 추가), with_var_file(여기에 -var-file=ops.tfvars, 값 6), with_var(-var-file=ops.tfvars -var replicas=5 순서), var_then_file(-var replicas=5 -var-file=ops.tfvars 순서) 여섯 줄을 이름=값 으로 씁니다. 끝나면 a·b.auto.tfvars 와 ops.tfvars 를 지우고 terraform.tfvars(2)만 남겨 apply 하세요.
  7. dev 에서 tofu plan -var replicas=0 을 실행해 출력(오류 포함)을 /root/iac-mod/invalid.txt 에 저장하세요. 채점기는 dev 의 사본에서 0 과 11 이 거부되고, prod(v1.0.0, 검사 없음)에서는 0 이 통과하는지 확인합니다. dev 와 prod 의 계획은 깨끗하게 남겨 둡니다.

참고

복붙한 두 환경을 먼저 적용해 둔다

/root/iac-mod/dev/main.tf/root/iac-mod/prod/main.tf 에 같은 모양의 리소스 둘을 두세요. local_file.configout/app.confname=api, env=<환경>, replicas=<수> 세 줄(dev 1, prod 3), local_file.bannerout/banner.txtapi (<환경>) 한 줄입니다. 두 디렉터리 모두 init·apply 하세요.

이 단계는 '복붙한 코드가 이미 운영 중' 인 출발점을 만드는 것입니다. 두 파일의 차이가 환경 이름과 레플리카 수뿐이라는 점을 확인해 두세요 — 그것이 모듈의 입력이 됩니다.

dev 를 모듈 호출로 바꾸되 아무것도 다시 만들지 않는다

/root/iac-mod/modules/web/main.tf 에 입력 env(문자열)·replicas(수), 같은 두 리소스, 출력 config_path 를 둔 모듈을 만드세요. dev 의 main.tf 는 replicas 변수(기본 1)를 두고 module "web"source = "../modules/web" 로 부르며, moved 블록 두 개로 옛 주소를 module.web.local_file.config·module.web.local_file.banner 로 옮기세요. init 한 뒤 계획에 생성·삭제·교체가 없어야 하고, 그대로 apply 합니다.

모듈 안의 path.module 은 모듈 디렉터리입니다. 파일이 호출한 환경 디렉터리 아래에 있어야 하므로 path.root 를 씁니다 — 이 경로가 옛 값과 한 글자라도 다르면 이동 뒤 교체가 따라옵니다. 모듈을 추가·변경하면 init 을 다시 해야 합니다.

prod 도 같은 모듈로 옮긴다

/root/iac-mod/prod/main.tf 도 같은 모듈을 부르게 바꾸세요(replicas 기본 3, env prod, moved 두 개). 계획에 생성·삭제·교체가 없어야 하고 apply 합니다. 이제 규칙을 고칠 곳은 모듈 한 곳입니다.

dev 와 같은 절차입니다. 차이는 입력값뿐이어야 합니다 — 모듈 안에 env == "prod" 같은 분기를 넣고 싶어지면 그 값은 인자로 받아야 한다는 신호입니다.

모듈에 버전을 붙이고 두 환경을 그 버전에 고정한다

/root/iac-mod/modules/web 을 git 저장소로 만들어 지금 내용을 커밋하고 태그 v1.0.0 을 붙이세요. dev·prod 의 source 를 git::file:///root/iac-mod/modules/web?ref=v1.0.0 로 바꾸고 tofu init -upgrade 한 뒤 두 계획이 모두 깨끗해야 합니다.

로컬 경로 source 는 버전이 없어서, 모듈을 고치는 순간 부르는 모든 환경이 함께 바뀝니다. git 주소의 ref 로 태그를 고정하면 init 이 그 시점의 사본을 .terraform/modules 에 받아 둡니다. 이 파드의 git 에는 사용자 정보가 없으니 git -c user.name=... -c user.email=... 로 커밋하세요.

새 버전은 dev 에서 먼저, prod 는 그대로

모듈에 두 가지를 더해 커밋하고 태그 v2.0.0 을 붙이세요: config 내용 끝에 owner=platform 한 줄, 그리고 replicas 가 1 이상 10 이하인지 검사하는 validation. dev 만 ref=v2.0.0 으로 올려 init·apply 하고, prod 는 v1.0.0 에 남겨 계획이 깨끗해야 합니다.

태그를 고정했기 때문에 모듈 저장소의 main 이 바뀌어도 prod 는 영향을 받지 않습니다. dev 의 계획에서 config 가 어떻게 바뀌는지(내용 변경이라 교체) 확인하고 적용하세요.

같은 변수에 값이 여러 곳에서 들어오면 누가 이기나

dev 에서 replicas 값을 여러 경로로 넣어 보며 echo var.replicas | tofu console 로 실제 값을 확인하고 /root/iac-mod/precedence.txt 에 적으세요. 모든 경우에 환경 변수 TF_VAR_replicas=9 가 있습니다. env_only(파일 없음), with_tfvars(terraform.tfvars 에 2), with_auto(여기에 a.auto.tfvars 3·b.auto.tfvars 4 추가), with_var_file(여기에 -var-file=ops.tfvars, 값 6), with_var(-var-file=ops.tfvars -var replicas=5 순서), var_then_file(-var replicas=5 -var-file=ops.tfvars 순서) 여섯 줄을 이름=값 으로 씁니다. 끝나면 a·b.auto.tfvars 와 ops.tfvars 를 지우고 terraform.tfvars(2)만 남겨 apply 하세요.

우선순위는 '나중에 읽은 것이 이긴다' 로 외우면 됩니다. 환경 변수가 가장 먼저, 그다음 terraform.tfvars, auto.tfvars 는 파일 이름 순서, 명령줄의 -var 와 -var-file 은 적은 순서대로 읽힙니다. 실험한 파일을 남겨 두면 다음 사람의 적용 값이 조용히 바뀝니다.

모듈 경계에서 잘못된 값을 막는다

dev 에서 tofu plan -var replicas=0 을 실행해 출력(오류 포함)을 /root/iac-mod/invalid.txt 에 저장하세요. 채점기는 dev 의 사본에서 0 과 11 이 거부되고, prod(v1.0.0, 검사 없음)에서는 0 이 통과하는지 확인합니다. dev 와 prod 의 계획은 깨끗하게 남겨 둡니다.

validation 은 모듈의 입력 변수에 붙어 있어서, 루트에서 어떤 경로로 값을 넣든 모듈 경계에서 막힙니다. 같은 입력이 prod 에서는 통과한다는 것은 v1 에 검사가 없기 때문이고, 그것이 버전 고정의 양면입니다.