Terraform/OpenTofu 기초 · 변수와 출력 · 이론
변수 우선순위, 출력, 그리고 민감값의 착각
한 줄 요약
같은 코드가 dev·stage·prod 를 감당하려면 값이 코드 밖으로 나가야 한다. 문제는 값을 넣을 수 있는 자리가 여럿이고, 그 사이에 정해진 강약이 있다는 것이다.
왜 이게 필요했나
환경이 셋인데 다른 것은 인스턴스 크기와 복제 수뿐이라고 하자. 가장 쉬운 해법은 디렉터리를 세 벌 복사하는 것이다. 그리고 반년 뒤, 세 디렉터리는 서로 다른 생물이 되어 있다. prod 에만 들어간 보안 설정이 stage 에는 없고, dev 에서 고친 버그가 prod 에는 반영되지 않았다. 사고는 언제나 그 틈에서 난다.
변수는 이 복사를 막는 장치다. 코드는 하나로 두고 값만 갈아 끼우면, 환경 간 차이가 "파일 세 벌의 diff" 에서 "값 몇 개"로 줄어든다. 그러면 사람이 차이를 눈으로 확인할 수 있게 된다.
어떻게 동작하나
값을 넣는 자리는 여럿이고, 나중에 오는 것이 이긴다.
| 강도 | 자리 | 성격 |
| --- | --- | --- |
| 가장 약함 | 변수 선언의 default | "아무도 안 주면 이 값" |
| 약함 | TF_VAR_이름 환경변수 | CI 러너나 셸에서 주입 |
| 중간 | terraform.tfvars | 이 디렉터리의 표준 값 |
| 조금 셈 | *.auto.tfvars (파일명 사전순) | 자동으로 함께 읽히는 값 |
| 셈 | -var-file=파일 | 이번 실행에 고른 값 묶음 |
| 가장 셈 | -var 이름=값 | 이번 한 번의 예외 |
변수 선언에는 값 말고도 붙일 것이 세 가지 있다. type 은 잘못된 형태를 초기에 막고, description 은 이 값이 무엇인지 알려 주며, validation 은 허용 범위를 코드로 못 박는다. validation 의 진짜 값어치는 실패 시점을 앞당기는 것이다. 검증이 없으면 잘못된 값이 적용 중반에 프로바이더 오류로 터지고, 그때는 이미 절반이 만들어진 상태다.
locals 는 변수처럼 보이지만 성격이 다르다. 밖에서 주입할 수 없는 이름 붙인 식이다. 여러 변수를 조합한 이름 접두어처럼, 한 번 정의해 여러 곳에서 쓰고 싶은 값에 쓴다.
output 은 이 설정의 공개 인터페이스다. 모듈로 쓰일 때는 다른 코드가 참조하는 유일한 창구이므로, 모든 출력에 description 을 다는 것이 좋다. 그리고 -json 옵션을 주면 기계가 읽는 형식으로 나와 파이프라인에서 쓰기 좋다.
마지막으로 sensitive = true 다. 이것은 출력을 화면에서 가릴 뿐이다. 상태 파일에는 값이 평문으로 남고, output -json 에도 값이 그대로 들어 있다. 이 사실을 모르면 "민감 표시를 했으니 안전하다"는 착각으로 상태 파일을 아무 데나 두게 된다.
현장에서 만나는 모습
첫째, -var 로 끄고 잊은 불. 장애 대응 중 -var replicas=10 으로 서비스를 살렸다면 그 값은 반드시 저장소에 커밋돼야 한다. 그러지 않으면 다음 정상 배포가 조용히 예전 값으로 되돌린다. 명령줄 값이 가장 세다는 성질은 응급 상황에서 유용한 만큼, 기록이 남지 않는다는 대가를 함께 지불한다.
둘째, 기본값의 함정. "일단 돌아가게" 하려고 모든 변수에 기본값을 넣으면, 값을 주지 않았을 때 조용히 개발용 설정으로 프로덕션이 만들어진다. 환경마다 반드시 달라야 하는 값에는 기본값을 주지 않는 편이 안전하다. 도구는 값이 없으면 물어보거나 실패하는데, 그 실패가 사고보다 훨씬 싸다.
셋째, 계획 로그에 남는 비밀. plan 출력에는 리소스 속성이 그대로 찍힌다. CI 로그를 사내 누구나 볼 수 있는 곳에 쌓아 두면 그것이 곧 유출 경로다. 민감 표시와 별개로 로그 보관 정책을 함께 봐야 하는 이유다.
다음 실습에서 할 것
/root/tf/vars 에서 같은 변수에 기본값·tfvars·명령줄·환경변수 네 가지 방법으로 값을 넣어 무엇이 이기는지 파일로 확인한다. validation 으로 잘못된 값을 거부시키고 그 메시지를 저장한다. locals 로 이름 접두어를 조합하고, 설명이 붙은 출력을 네 개 이상 만든다. 마지막에는 민감 변수를 선언해 사람이 보는 출력에서는 가려지지만 JSON 에는 값이 남는다는 사실을 눈으로 확인한다.