GitLab 관리 Terraform/OpenTofu 상태
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
팀 전체에 걸쳐 인프라 상태 파일을 관리하려면 보안과 안정성이 모두 필요합니다. GitLab 관리 OpenTofu 상태를 사용하면 다음을 할 수 있습니다. OpenTofu 상태 파일은 디스크와 오브젝트 스토리지에 저장된 상태에서 Lockbox Ruby gem으로 암호화됩니다.
히스토리
- GitLab 15.7에서 마침표가 포함된 상태 이름에 대한 지원이
allow_dots_on_tf_state_names라는 기능 플래그와 함께 도입되었습니다. 기본적으로 비활성화되어 있습니다. - GitLab 16.0에서 마침표가 포함된 상태 이름에 대한 지원이 일반적으로 사용 가능해졌습니다. 기능 플래그
allow_dots_on_tf_state_names가 제거되었습니다. - GitLab 18.3에서 GitLab 관리 OpenTofu 및 Terraform 상태에 대한 지원이 도입되었습니다. GitLab CLI(
glab) 1.66 이상이 필요합니다.
팀 전체에 걸쳐 인프라 상태 파일을 관리하려면 보안과 안정성이 모두 필요합니다. GitLab 관리 OpenTofu 상태는 상태 관리에서 흔히 발생하는 어려움을 없애 줍니다. 최소한의 구성만으로 OpenTofu 상태가 GitLab 프로젝트의 자연스러운 확장이 됩니다. 이 통합은 인프라 정의, 코드, 상태를 모두 하나의 안전한 위치에 보관합니다.
GitLab 관리 OpenTofu 상태를 사용하면 다음을 할 수 있습니다.
- 저장 데이터 자동 암호화로 상태 파일을 안전하게 저장합니다
- 내장 버전 관리로 변경 사항을 추적해 누가 무엇을 언제 변경했는지 파악합니다
- 별도의 인증 시스템을 만들지 않고 GitLab 권한 모델로 액세스를 제어합니다
- 상태 파일 충돌이나 손상 없이 여러 팀에 걸쳐 협업합니다
- 기존 GitLab CI/CD 파이프라인과 매끄럽게 통합합니다
- CI/CD job과 로컬 개발 환경 양쪽에서 상태에 원격으로 액세스합니다
재해 복구 고려 사항#
OpenTofu 상태 파일은 디스크와 오브젝트 스토리지에 저장된 상태에서 Lockbox Ruby gem으로 암호화됩니다.
암호화에는 db_key_base 애플리케이션 설정에서 파생된 키를 사용합니다.
이러한 암호화 방식 때문에 상태 파일을 복호화하려면 인스턴스가 가용한 상태여야 합니다.
인스턴스가 오프라인이 되면 상태 파일에 액세스하거나 복호화할 수 없습니다. GitLab을 실행하는 데 필요한 인프라의 구성이 상태 파일에 들어 있으면 이는 문제가 됩니다.
GitLab이 자신을 부트스트랩하는 데 필요한 OpenTofu 모듈이나 그 외 의존성을 호스팅하고 있으면, 인스턴스가 오프라인일 때 이러한 의존성에 접근할 수 없습니다.
이 문제를 피하려면 다음과 같이 합니다.
- 의존성을 별도로 호스팅하거나 백업합니다.
- 공유 장애 지점이 없는 별도의 GitLab 인스턴스를 사용합니다.
- 중요한 부트스트랩 의존성은 다른 호스팅 방안을 검토합니다.
사전 요구 사항#
GitLab Self-Managed에서 OpenTofu 상태 파일에 GitLab을 사용하려면 먼저 다음 조건이 필요합니다.
- 관리자가 Terraform/OpenTofu 상태 스토리지를 설정해야 합니다.
- 프로젝트에서 Infrastructure 메뉴를 켜야 합니다.
- Settings > General로 이동합니다.
- Visibility, project features, permissions를 확장합니다.
- Infrastructure에서 토글을 켭니다.
계획 데이터 보안#
OpenTofu plan.json 또는 plan.cache 파일은 암호화되지 않으며 비밀번호, 액세스 토큰, 인증서 같은
민감한 데이터가 포함될 수 있습니다. 기본적으로 Guest 권한을 가진 사용자도 계획 파일에 액세스할 수 있습니다.
계획 데이터를 보호하려면 다음과 같이 합니다.
- 아티팩트 구성에서
access: 'developer'를 설정합니다. 이 설정은 액세스를 Developer 권한 이상인 사용자로 제한합니다. - 공개 파이프라인을 비활성화합니다.
- 계획 출력을 암호화합니다.
- 프로젝트 공개 범위를 비공개로 설정합니다.
GitLab CI/CD를 사용하여 OpenTofu 상태를 백엔드로 초기화#
사전 요구 사항:
tofu apply로 상태를 잠그고, 잠금을 해제하고, 상태에 쓰려면 Maintainer 또는 Owner 권한이 있어야 합니다.tofu plan -lock=false로 상태를 읽으려면 Developer, Maintainer 또는 Owner 권한이 있어야 합니다.
GitLab CI/CD를 백엔드로 구성하려면 다음을 수행합니다.
-
OpenTofu 프로젝트의
backend.tf같은.tf파일에 HTTP 백엔드를 정의합니다.terraform { backend "http" { } } -
프로젝트 리포지터리의 루트 디렉터리에
.gitlab-ci.yml파일을 만듭니다. OpenTofu CI/CD 컴포넌트를 사용해.gitlab-ci.yml파일을 구성합니다. -
프로젝트를 GitLab에 푸시합니다. 이 동작은 파이프라인을 트리거하며, 해당 파이프라인은
gitlab-tofu init,gitlab-tofu validate,gitlab-tofu plan명령을 실행합니다. -
앞선 파이프라인에서 수동
deployjob을 트리거합니다. 이 동작은gitlab-tofu apply명령을 실행하며, 정의된 인프라를 프로비저닝합니다.
앞선 명령의 출력은 job 로그에서 확인할 수 있습니다.
gitlab-tofu CLI는 tofu CLI를 감싼 래퍼입니다.
OpenTofu 환경 변수 사용자 정의#
CI/CD job을 정의할 때 OpenTofu HTTP 구성 변수를 사용할 수 있습니다.
init을 사용자 정의하고 OpenTofu 구성을 재정의하려면
init -backend-config=... 방식 대신 환경 변수를 사용합니다.
-backend-config를 사용하면 해당 구성은 다음과 같이 처리됩니다.
plan명령의 출력에 캐시됩니다.- 보통
apply명령으로 그대로 전달됩니다.
이러한 구성은 CI job에서 상태 파일을 잠글 수 없는 문제 같은 문제로 이어질 수 있습니다.
계획 파일 이름 사용자 정의#
기본적으로 gitlab-tofu plan(또는 gitlab-terraform plan) 명령은 항상 계획 출력을 plan.cache라는 파일에 씁니다.
파일 이름을 변경하려면 CI/CD 파이프라인 구성에서 TF_PLAN_CACHE 환경 변수를 설정합니다. 예를 들어
파일 이름을 my-plan.tfplan으로 설정하려면 다음과 같이 지정합니다.
variables:
TF_PLAN_CACHE: "my-plan.tfplan"
-out=<filename> 옵션을 전달해 출력 파일 이름을 설정하지 않습니다. GitLab 명령이 이 옵션을 재정의합니다.
로컬 머신에서 상태 액세스#
로컬 머신에서 GitLab 관리 OpenTofu 상태에 액세스할 수 있습니다.
GitLab을 클러스터로 배포한 환경에서는 로컬 스토리지를 사용하지 않아야 합니다. 노드 간에 상태가 분리되어 이후의 OpenTofu 실행이 일관되지 않을 수 있습니다. 대신 원격 스토리지 리소스를 사용합니다.
-
OpenTofu 상태가 CI/CD용으로 초기화되어 있는지 확인합니다.
-
값이 미리 채워진 OpenTofu
init명령을 복사합니다.- 상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
- Operate > Terraform states를 선택합니다.
- 사용하려는 환경 옆에서 Actions (⋮)를 선택한 다음 Copy Terraform init command를 선택합니다.
-
터미널을 열고 로컬 머신에서 이 명령을 실행합니다.
GitLab 관리 OpenTofu 상태로 마이그레이션#
OpenTofu는 백엔드가 변경되거나 재구성될 때 상태를 복사하는 기능을 지원합니다. 이 기능을 사용해 다른 백엔드에서 GitLab 관리 OpenTofu 상태로 마이그레이션합니다.
GitLab 관리 OpenTofu 상태로 마이그레이션하는 데 필요한 명령은 로컬 터미널에서 실행해야 합니다.
다음 예시는 상태 이름을 변경하는 방법을 보여 줍니다. 다른 상태 스토리지 백엔드에서 GitLab 관리 OpenTofu 상태로 마이그레이션할 때도 같은 워크플로가 필요합니다.
이 명령은 로컬 머신에서 실행해야 합니다.
초기 백엔드 설정#
glab으로 백엔드를 초기화하려면 다음 명령을 실행합니다.
glab opentofu init <old_state_name>
OpenTofu CLI로 백엔드를 초기화하려면 다음 명령을 실행합니다.
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/old-state-name"
tofu init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
백엔드가 성공적으로 초기화되면 다음과 같은 응답이 표시됩니다.
Initializing the backend...
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
re-run this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
백엔드 변경#
tofu init이 기존 상태의 위치를 아는 .terraform/ 디렉터리를 만들었으므로,
이제 새 위치를 알려 줄 수 있습니다.
glab opentofu init <new-state-name> -- -migrate-state
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/<new-state-name>"
tofu init \
-migrate-state \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
백엔드가 성공적으로 초기화되면
다음과 같은 응답이 표시됩니다. yes를 입력하면 기존 위치의 상태가 새 위치로
복사됩니다. 그런 다음 GitLab CI/CD에서 실행하는 방식으로 돌아갈 수 있습니다.
Initializing the backend...
Backend configuration changed!
Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "http" backend to the
newly configured "http" backend. No existing state was found in the newly
configured "http" backend. Do you want to copy this state to the new "http"
backend? Enter "yes" to copy and "no" to start with an empty state.
Enter a value: yes
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
GitLab 백엔드를 원격 데이터 소스로 사용#
GitLab 관리 OpenTofu 상태 백엔드를 OpenTofu 데이터 소스로 사용할 수 있습니다.
-
main.tf또는 그 외 관련 파일에 다음 변수를 선언합니다. 값은 비워 둡니다.variable "example_remote_state_address" { type = string description = "Gitlab remote state file address" } variable "example_username" { type = string description = "Gitlab username to query remote state" } variable "example_access_token" { type = string description = "GitLab access token to query remote state" } -
앞 단계의 값을 재정의하려면
example.auto.tfvars라는 파일을 만듭니다. 이 파일은 프로젝트 리포지터리에서 버전 관리하지 않아야 합니다.example_remote_state_address = "https://gitlab.com/api/v4/projects//terraform/state/" example_username = "" example_access_token = "" -
.tf파일에서 OpenTofu 입력 변수를 사용해 데이터 소스를 정의합니다.data "terraform_remote_state" "example" { backend = "http" config = { address = var.example_remote_state_address username = var.example_username password = var.example_access_token } }- address: 데이터 소스로 사용하려는 원격 상태 백엔드의 URL입니다.
예를 들면
https://gitlab.com/api/v4/projects//terraform/state/입니다. - username: 데이터 소스에 인증할 사용자 이름입니다. 인증에
개인 액세스 토큰을 사용하는 경우
이 값은 GitLab 사용자 이름입니다. GitLab CI/CD를 사용하는 경우 이 값은
'gitlab-ci-token'입니다. - password: 데이터 소스에 인증할 비밀번호입니다. 인증에 개인 액세스 토큰을
사용하는 경우 이 값은 토큰 값입니다(토큰에 API 스코프가 있어야 합니다).
GitLab CI/CD를 사용하는 경우 이 값은
${CI_JOB_TOKEN}CI/CD 변수의 내용입니다.
- address: 데이터 소스로 사용하려는 원격 상태 백엔드의 URL입니다.
예를 들면
이제 데이터 소스의 출력을 Terraform 리소스에서
data.terraform_remote_state.example.outputs.으로 참조할 수 있습니다.
대상 프로젝트의 OpenTofu 상태를 읽으려면 Developer, Maintainer 또는 Owner 권한이 필요합니다.
OpenTofu 상태 파일 관리#
OpenTofu 상태 파일을 보려면 다음을 수행합니다.
- 상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
- 왼쪽 사이드바에서 Operate > Terraform states를 선택합니다.
이 UI의 개선 사항을 추적하는 에픽이 있습니다.
개별 OpenTofu 상태 버전 관리#
GitLab CLI(glab) 또는 API를 사용해
개별 상태 버전을 관리합니다.
사전 요구 사항:
- 시리얼 번호로 상태 버전을 가져오려면 Developer, Maintainer 또는 Owner 권한이 있어야 합니다.
- 시리얼 번호로 상태 버전을 제거하려면 Maintainer 또는 Owner 권한이 있어야 합니다.
시리얼 번호로 상태 버전을 가져오려면 다음을 수행합니다.
glab opentofu state download <your_state_name> <version_serial_number>
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version_serial_number>"
시리얼 번호로 상태 버전을 제거하려면 다음을 수행합니다.
glab opentofu state delete <your_state_name> <version_serial_number>
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version_serial_number>"
상태 파일 제거#
사전 요구 사항:
- 상태 파일을 제거하려면 Maintainer 또는 Owner 권한이 있어야 합니다.
glab opentofu state delete <your_state_name>
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"
CI/CD job 토큰과 기본 인증을 사용할 수도 있습니다.
curl --request DELETE --user "gitlab-ci-token:$CI_JOB_TOKEN" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"
GraphQL API를 사용할 수도 있습니다.
UI로 상태 파일을 제거하려면 다음을 수행합니다.
- 왼쪽 사이드바에서 Operate > Terraform states를 선택합니다.
- Actions 칼럼에서 Actions (⋮) > Remove state file and versions를 선택합니다.
상태 잠금 및 잠금 해제#
사전 요구 사항:
- 상태 파일을 잠그려면 Maintainer 또는 Owner 권한이 있어야 합니다.
# Lock a state file
glab opentofu state lock <your_state_name>
# Unlock a state file
glab opentofu state unlock <your_state_name>
# Lock a state file
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/lock"
# Unlock a state file
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/lock"
UI로 상태 파일을 잠그거나 잠금을 해제하려면 다음을 수행합니다.
- 왼쪽 사이드바에서 Operate > Terraform states를 선택합니다.
- Actions 칼럼에서 잠그려면 Actions (⋮) > Lock을, 잠금을 해제하려면 Actions (⋮) > Unlock을 선택합니다.
상태 파일 다운로드#
사전 요구 사항:
- 상태 파일을 다운로드하려면 Developer, Maintainer 또는 Owner 권한이 있어야 합니다.
# Download the latest state
glab opentofu state download <your_state_name>
# Download a specific version (serial) of a state
glab opentofu state download <your_state_name> <your_serial>
# Download the latest state
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"
# Download a specific version (serial) of a state
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version_serial_number>"
UI로 최신 상태 파일을 다운로드하려면 다음을 수행합니다.
- 왼쪽 사이드바에서 Operate > Terraform states를 선택합니다.
- Actions 칼럼에서 Actions (⋮) > Download JSON을 선택합니다.
UI로는 특정 버전의 상태를 다운로드할 방법이 없습니다.
Terraform 상태 파일의 민감한 데이터 보호#
Terraform 상태 파일에는 비밀번호, 개인 키, API 토큰, 데이터베이스 연결 문자열 같은 민감한 정보가 포함될 수 있습니다. GitLab에서는 Developer 권한 이상을 가진 사용자가 자신이 멤버인 프로젝트의 Terraform 상태 파일을 다운로드하고 볼 수 있습니다.
민감한 데이터의 노출을 줄이려면 다음과 같이 합니다.
-
GitLab Ultimate 고객: Developer 권한을 그대로 따르면서
admin_terraform_state권한만 제외한 커스텀 역할을 만듭니다. 이렇게 하면 팀 멤버가 민감한 데이터가 담긴 Terraform 상태 파일에 액세스하지 않고도 Infrastructure as Code(IaC) 프로젝트에 기여할 수 있습니다.[!note] 커스텀 역할은 GitLab Ultimate에서만 사용할 수 있습니다. Premium 이하 티어의 고객은 이 완화 방안을 사용할 수 없으므로 앞서 설명한 다른 전략에 집중해야 합니다.
-
OpenTofu 사용자: 저장된 민감한 데이터를 보호하기 위해 상태 및 계획 암호화를 켭니다. GitLab은 암호화 구성을 제공하는 OpenTofu CI/CD 컴포넌트를 통해 이를 기본으로 지원합니다. 권한이 없는 사용자가 상태 파일에 액세스하더라도 암호화된 콘텐츠는 보호됩니다.
-
모든 사용자:
- 인프라 상태에 액세스해야 하는 사용자로 프로젝트 멤버십을 제한합니다.
- 상태를 저장할 별도의 프로젝트를 사용하고 필요한 사용자만 멤버로 추가합니다.
- HashiCorp Vault나 AWS Secrets Manager 같은 외부 시크릿 관리 솔루션을 사용해, 시크릿을 Terraform 구성에 저장하는 대신 동적으로 참조합니다.
- 변수 정의에서 Terraform
sensitive매개변수로 민감한 값을 표시합니다. 이렇게 하면 값이 CLI 출력과 계획 파일에 나타나지 않지만, 상태 파일에는 그대로 남습니다. - Developer 권한을 가진 프로젝트 멤버를 정기적으로 감사하고, 실수로 노출된 시크릿이 있는지 상태 파일 내용을 검토합니다.