GitLab 관리 Terraform/OpenTofu 상태
Offering: 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 작업과 로컬 개발 환경 모두에서 원격으로 상태에 액세스합니다.
재해 복구 고려 사항#
OpenTofu 상태 파일은 디스크와 객체 스토리지에서 휴지 상태일 때 Lockbox Ruby gem으로 암호화됩니다.
암호화는 db_key_base 애플리케이션 설정에서 파생된 키를 사용합니다.
이 암호화 방식으로 인해 상태 파일을 복호화하려면 인스턴스가 사용 가능해야 합니다.
인스턴스가 오프라인이 되면 상태 파일에 액세스하거나 복호화할 수 없습니다. 상태 파일에 GitLab이 실행하는 데 필요한 인프라 구성이 포함되어 있으면 문제가 됩니다.
GitLab이 자체 부트스트랩에 필요한 OpenTofu 모듈 또는 기타 종속성을 호스팅하는 경우 인스턴스가 오프라인이 되면 이러한 종속성에 액세스할 수 없게 됩니다.
이 문제를 방지하려면:
- 종속성을 별도로 호스팅하거나 백업합니다.
- 공유 장애 지점이 없는 별도의 GitLab 인스턴스를 사용합니다.
- 중요한 부트스트랩 종속성에 대해 대체 호스팅을 고려합니다.
사전 조건#
GitLab Self-Managed에서 OpenTofu 상태 파일에 GitLab을 사용하기 전에:
- 관리자가 Terraform/OpenTofu 상태 스토리지를 설정해야 합니다.
- 프로젝트의 인프라 메뉴를 켜야 합니다:
- 설정 > 일반으로 이동합니다.
- 가시성, 프로젝트 기능, 권한을 확장합니다.
- 인프라 아래에서 토글을 켭니다.
계획 데이터 보안#
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명령을 실행합니다. -
이전 파이프라인에서 수동
deploy작업을 트리거합니다. 이 작업은 정의된 인프라를 프로비저닝하는gitlab-tofu apply명령을 실행합니다.
이전 명령의 출력은 작업 로그에서 볼 수 있어야 합니다.
gitlab-tofu CLI는 tofu CLI의 래퍼입니다.
OpenTofu 환경 변수 사용자 정의#
CI/CD 작업을 정의할 때 OpenTofu HTTP 구성 변수를 사용할 수 있습니다.
init을 사용자 정의하고 OpenTofu 구성을 재정의하려면 init -backend-config=... 방식 대신 환경 변수를 사용하세요.
-backend-config를 사용하면 구성이:
plan명령의 출력에 캐시됩니다.- 일반적으로
apply명령으로 전달됩니다.
이 구성은 이전 작업의 계획으로 terraform apply에 대한 CI 작업에서 Terraform 상태 파일을 잠글 수 없음과 같은 문제를 일으킬 수 있습니다.
계획 파일 이름 사용자 정의#
기본적으로 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명령을 복사합니다:- 상단 표시줄에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
- 운영 > Terraform 상태를 선택합니다.
- 사용하려는 환경 옆에서 작업(⋮)을 선택하고 Terraform init 명령 복사를 선택합니다.
-
터미널을 열고 로컬 머신에서 이 명령을 실행합니다.
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.
예를 들어
이제 데이터 소스의 출력을 data.terraform_remote_state.example.outputs.을 사용하여 Terraform 리소스에서 참조할 수 있습니다.
대상 프로젝트에서 OpenTofu 상태를 읽으려면 Developer, Maintainer 또는 Owner 역할이 필요합니다.
OpenTofu 상태 파일 관리#
OpenTofu 상태 파일을 보려면:
- 왼쪽 사이드바에서 운영 > Terraform 상태를 선택합니다.
이 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 작업 토큰 및 기본 인증을 사용할 수도 있습니다:
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를 사용하여 상태 파일을 제거하려면:
- 왼쪽 사이드바에서 운영 > Terraform 상태를 선택합니다.
- 작업 열에서 작업(⋮) > 상태 파일 및 버전 제거를 선택합니다.
상태 잠금 및 잠금 해제#
사전 조건:
- 상태 파일을 잠그려면 Maintainer 또는 Owner 역할이 있어야 합니다.
# 상태 파일 잠금
glab opentofu state lock <your_state_name>
# 상태 파일 잠금 해제
glab opentofu state unlock <your_state_name>
# 상태 파일 잠금
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"
# 상태 파일 잠금 해제
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를 사용하여 상태 파일을 잠그거나 잠금 해제하려면:
- 왼쪽 사이드바에서 운영 > Terraform 상태를 선택합니다.
- 작업 열에서 잠그려면 작업(⋮) > 잠금, 잠금 해제하려면 작업(⋮) > 잠금 해제를 선택합니다.
상태 파일 다운로드#
사전 조건:
- 상태 파일을 다운로드하려면 Developer, Maintainer 또는 Owner 역할이 있어야 합니다.
# 최신 상태 다운로드
glab opentofu state download <your_state_name>
# 특정 버전(시리얼)의 상태 다운로드
glab opentofu state download <your_state_name> <your_serial>
# 최신 상태 다운로드
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"
# 특정 버전(시리얼)의 상태 다운로드
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를 사용하여 최신 상태 파일을 다운로드하려면:
- 왼쪽 사이드바에서 운영 > Terraform 상태를 선택합니다.
- 작업 열에서 작업(⋮) > 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 역할을 가진 프로젝트 멤버를 정기적으로 감사하고 실수로 노출된 시크릿에 대한 상태 파일 내용을 검토합니다.
