Files
project-gitops/docs/architecture/terraform.md
T
2026-08-28 17:24:26 +09:00

4.9 KiB

Terraform boundary

Terraform은 VM만 정의하는 도구가 아니라 provider가 노출하는 API 객체의 desired state를 선언하고 plan/apply하는 framework입니다. 이 저장소에는 machine/cloud provider가 없으므로 서버, 네트워크, k3s 설치를 Terraform이 소유하지 않습니다. 현재 적용 범위는 Vault API 객체뿐입니다.

도구별 소유권

대상 소유 도구 이유
Kubernetes manifest와 rollout Argo CD Git revision을 지속적으로 reconcile
Vault mount, auth, policy, role, Transit key, DB connection Terraform Vault provider API 객체의 plan과 state ownership 필요
Vault init/unseal, initial secret seed 승인된 operator runbook 일회성 ceremony와 secret material을 state에서 제외
KV secret payload 외부 secret authority/operator Git과 Terraform state에 값이 남지 않아야 함
VM, network, k3s 현재 소유자 없음 실제 provider와 lifecycle이 정해지지 않음

Kubernetes와 Helm을 Terraform에 다시 넣지 않습니다. 같은 object를 Argo CD와 Terraform이 동시에 소유하면 두 reconciler가 충돌합니다. 반대로 Terraform을 Argo hook에서 실행하면 cluster reconciliation이 Vault state lock과 privileged credential lifecycle까지 떠안게 됩니다.

State 경계

vault-foundation
  creates delegation
       |                  |
       v                  v
vault-workloads      vault-database
runtime access       PostgreSQL integration
  • vault-foundation은 mount, Kubernetes auth와 위임 policy/login role을 소유합니다. Routine CI apply 대상이 아닙니다.
  • vault-workloads는 runtime ACL/Kubernetes role과 애플리케이션 Transit key만 소유합니다.
  • vault-database는 실제 PostgreSQL이 준비된 뒤 connection과 migration dynamic role만 소유합니다.

위임받은 state는 자기 runner policy나 login role을 만들지 않습니다. State 간 이름은 checked-in contract로 공유하며 terraform_remote_state로 다른 state snapshot을 읽지 않습니다.

Policy HCL이 정확한 API path를 허용하므로 kv, database, transit, kubernetes, project-auth-jwt, auth-system-postgres-dev 같은 보안 경계 이름은 각 root의 local contract로 고정합니다. 변수로 한쪽만 override해 plan은 성공하지만 권한이 어긋나는 상태를 허용하지 않습니다. 이 이름을 바꿀 때는 foundation policy, delegated root와 runtime consumer를 하나의 migration 설계에서 함께 변경합니다.

Mount, Kubernetes auth와 선택적 CI JWT auth에는 prevent_destroy를 적용합니다. 입력 누락이 기존 auth mount 삭제로 이어지지 않으며, 실제 제거는 consumer/token inventory를 거친 별도 decommission revision에서만 보호를 명시적으로 해제합니다.

실행 계약

  1. Remote backend는 encryption, versioning, locking과 root별 access control을 제공해야 합니다.
  2. terraform-plan이 만든 saved plan을 검토하고, 같은 PLAN_FILEterraform-apply가 사용합니다.
  3. Plan은 sensitive artifact로 취급하며 apply 성공 후 제거합니다.
  4. Provider token과 PostgreSQL password는 Terraform 1.11 이상의 ephemeral variable/write-only argument로 실행 시점에 다시 주입합니다.
  5. Delegated runner token은 짧은 TTL, no-default-policy와 정확한 object path만 사용합니다. Capability 확인, self lookup과 명시적 self revoke에 필요한 세 self-service API만 별도로 허용합니다.
  6. Foundation, workloads, database apply는 서로 다른 승인 단계입니다.

두 번째 클러스터 또는 machine IaC

두 번째 클러스터가 생겨도 state를 합치지 않습니다. Cluster별 backend와 Vault instance ownership이 독립이면 같은 세 root contract를 reusable module로 승격합니다. 실제 VM/network provider, account, failure domain과 destroy/backup 책임이 정해졌을 때만 다음처럼 별도 machine root를 추가합니다.

infrastructure/live/<cluster>/machine
infrastructure/live/<cluster>/vault-foundation
infrastructure/live/<cluster>/vault-workloads
infrastructure/live/<cluster>/vault-database

Machine root output을 읽기 위해 Vault state 전체를 공유하지 않습니다. 필요한 endpoint는 명시적 configuration contract나 최소 권한의 별도 configuration store로 전달합니다.

Further reading