使用Terraform创建带Google KMS密钥的GCE实例遇权限错误
问题核心
你遇到的错误如下:
Error: Error creating instance: googleapi: Error 400: Cloud KMS error when using key projects/formal-wonder-394711/locations/europe-west2/keyRings/my-key-ridha/cryptoKeys/my-crypto-key: Permission 'cloudkms.cryptoKeyVersions.useToEncrypt' denied on resource 'projects/formal-wonder-394711/locations/europe-west2/keyRings/my-key-ridha/cryptoKeys/my-crypto-key' (or it may not exist)., kmsPermissionDenied
中文翻译:
错误:创建实例失败:googleapi: 错误400:使用密钥 projects/formal-wonder-394711/locations/europe-west2/keyRings/my-key-ridha/cryptoKeys/my-crypto-key 时触发Cloud KMS错误:资源 'projects/formal-wonder-394711/locations/europe-west2/keyRings/my-key-ridha/cryptoKeys/my-crypto-key' 上的权限 'cloudkms.cryptoKeyVersions.useToEncrypt' 被拒绝(或资源不存在)。, kmsPermissionDenied
问题根源是:调用KMS加密磁盘的主体不是Terraform服务账号,而是Google Compute Engine的默认服务账号。创建带加密磁盘的VM时,是Compute Engine服务代表VM关联的服务账号发起KMS加密请求,而非Terraform执行账号。
修复方案
1. 修正KMS IAM绑定资源
将现有的IAM绑定替换为针对Compute Engine默认服务账号的权限配置,使用最小权限角色roles/cloudkms.cryptoKeyEncrypter:
resource "google_kms_crypto_key_iam_binding" "compute-kms-binding" { crypto_key_id = google_kms_crypto_key.my-crypto-key.id role = "roles/cloudkms.cryptoKeyEncrypter" members = [ # 替换为你的项目编号,格式:serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com "serviceAccount:123456789012-compute@developer.gserviceaccount.com" ] depends_on = [google_kms_crypto_key.my-crypto-key] }
项目编号可通过命令获取:
gcloud projects describe formal-wonder-394711 --format="value(projectNumber)"
2. 调整VM实例的依赖顺序
确保VM实例在KMS权限绑定完成后再创建,避免时序问题:
resource "google_compute_instance" "myvm" { name = "my-test-vm" machine_type = "e2-small" zone = "europe-west2-a" boot_disk { initialize_params { image = "debian-cloud/debian-11" } kms_key_self_link = google_kms_crypto_key.my-crypto-key.id } network_interface { network = google_compute_network.vpc2.id subnetwork = google_compute_subnetwork.network-subnet2.id } depends_on = [ google_compute_network.vpc2, google_compute_subnetwork.network-subnet2, google_kms_crypto_key_iam_binding.compute-kms-binding # 添加此依赖 ] }
3. 可选:优化Terraform服务账号权限
如果Terraform需要管理KMS密钥,保留原绑定但使用更贴合的角色(避免过度授权):
resource "google_kms_crypto_key_iam_binding" "terraform-kms-binding" { crypto_key_id = google_kms_crypto_key.my-crypto-key.id role = "roles/cloudkms.editor" members = [ "serviceAccount:terraform-service@formal-wonder-394711.iam.gserviceaccount.com" ] depends_on = [google_kms_crypto_key.my-crypto-key] }
关键注意事项
- 权限主体区分:Terraform服务账号负责资源创建,磁盘加密操作由Compute Engine服务发起,使用的是项目默认Compute服务账号。
- 最小权限原则:优先使用
roles/cloudkms.cryptoKeyEncrypter这类细粒度角色,避免roles/cloudkms.admin等高权限角色带来的安全风险。
内容的提问来源于stack exchange,提问作者Rizwan Khan A

