Files
project-gitops/docs/decisions/0002-terraform-ownership.md
2026-08-28 17:24:26 +09:00

56 lines
3.1 KiB
Markdown

# ADR 0002: Terraform state ownership
Status: accepted
Updated: 2026-07-26
Terraform의 현재 범위는 Vault API 객체입니다. Kubernetes 리소스는 Argo
CD가 소유하며, machine/network provisioning은 provider와 운영 경계가
확정될 때 별도 root로 추가합니다.
`dev-k3s`는 정확히 세 state를 사용합니다.
| State | 소유 객체 |
|---|---|
| `vault-foundation` | KV/database/Transit mounts, Kubernetes auth backend/config, delegated automation policy와 선택적 분리 CI JWT auth role |
| `vault-workloads` | workload ACL policy, Kubernetes auth role, `project-auth-jwt` Transit key |
| `vault-database` | `database/config/auth-system-postgres-dev` connection과 `auth-db-migration-dev` dynamic role |
Resource 또는 Vault API path 하나는 한 state에만 속합니다. State 사이는
이름 contract와 실행 순서만 공유하며 `terraform_remote_state`로 서로의
snapshot을 읽지 않습니다. Backend는 encryption, versioning, access
control, locking을 제공해야 합니다.
Privilege delegation의 경계는 다음과 같습니다.
- `vault-foundation`은 bootstrap 또는 보안 관리자 승인 때만 실행합니다.
Routine CI identity를 두지 않습니다.
- `vault-foundation`이 workload/database 전용 automation policy와,
OIDC/JWT trust가 검증된 경우 서로 분리된 CI JWT login role을 생성합니다.
두 role의 exact claim map은 최소 한 공통 discriminator key에서 서로 다른
값을 가져야 하므로 동일 scalar-claim JWT가 둘 다 선택할 수 없습니다.
- `vault-workloads``vault-database`는 각각의 short-lived identity를
소비할 뿐 자신에게 권한을 부여하는 객체를 소유하지 않습니다.
- Delegated identity는 자신이 맡은 정확한 policy, auth role, database
path만 CRUD할 수 있습니다.
- Broad `platform-admin` 또는 상시 cluster-internal Vault administrator를
routine automation에 연결하지 않습니다.
실제 CI issuer가 repository, protected ref와 job discriminator claim을
어떤 형식으로 발행하는지 먼저 검증합니다. 그 계약을 확인할 수 없으면 JWT
auth를 활성화하지 않고 bootstrap용 short-lived token만 사용합니다.
Foundation의 future change는 routine identity가 아니라 encrypted unseal
custody를 사용한 승인된 generated-root ceremony가 필요합니다.
Secret payload는 Terraform resource/data source로 관리하지 않습니다.
Provider token과 PostgreSQL credential은 ephemeral variable과 write-only
argument를 통해 실행 시점에만 전달합니다. Vault init material, token,
password, plan과 state를 Git에 저장하지 않습니다.
기존 `vault-core`에서 세 state로 바꾸는 작업은 선언 이동과 state ownership
이관을 분리해 수행합니다. Source에서는 `removed { destroy = false }`,
destination에서는 import를 사용하고, 양쪽 plan의 destroy가 0인지 확인하기
전에는 apply하지 않습니다. Broad `platform-admin`/`vault-operator`
미사용 Keycloak/PostgreSQL operator policy/role은 새 state로 옮기지
않으며 consumer가 없음을 확인한 별도 decommission에서 제거합니다.