使用自定义服务帐户在 GCP 中创建 VM 时 KMS 权限出现 400 错误

问题描述

我正在使用 terraform 创建一个虚拟机实例和连接到所述实例的网络、计算磁盘、该磁盘的快照以及用于加密数据的 KMS 密钥环和密钥。

我使用自己创建的服务帐户对 GCP 进行身份验证,使用以下块:

credentials = file("gcp-account.json")

该帐户具有以下权限:

然后,在 google_compute_snapshotgoogle_compute_disk 块中,我提供 kms_key_self_link 和服务帐户以使用新创建的 KMS 密钥和我的自定义服务帐户为请求加密数据:

kms_key_self_link       = var.kms_key_selflink
kms_key_service_account = var.service_account

我在 google_compute_instance 块中做同样的事情,并在 kms_key_self_linkboot_disk 中提供 attached_disk 并指定 VM 应使用自定义服务帐户进行请求:

  service_account {
    email  = var.service_account
    scopes = []
  }

然后,在运行 terraform apply 时,我收到以下错误

错误:创建实例时出错:googleapi:错误 400:Cloud KMS 错误 使用钥匙时 项目/{项目名称}/locations/{位置}/keyRings/{密钥环名称}/cryptoKeys/{密钥名称}:权限“cloudkms.cryptokeyversions.usetoEncrypt”被拒绝 资源 'projects/{project name}/locations/{location}/keyRings/{key ring name}/cryptoKeys/{key name}:'(或者它可能不存在),kmsPermissionDenied

什么在我授予时得到解决

roles/cloudkms.cryptoKeyEncrypterDecrypter

获得 Compute Engine 服务代理的权限,然后脚本运行得很好。

data "google_iam_policy" "kms_key_encrypt_decrypt" {
  binding {
    role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"

    members = ["serviceAccount:service{{PROJECT_NUMBER}}@computesystem.iam.gserviceaccount.com"]
  }
}

resource "google_kms_crypto_key_iam_policy" "crypto_key" {
  crypto_key_id = google_kms_crypto_key.key.id
  policy_data   = data.google_iam_policy.kms_key_encrypt_decrypt.policy_data
}

但是,我更希望我的所有资源仅使用我的自定义服务帐户来处理请求,并且不以任何方式涉及认的 Compute Engine 服务代理。

我已经检查过,Compute Engine 服务代理分配了哪些角色,只有一个

Compute Engine 服务代理

并为我的自定义服务帐户分配了完全相同的角色。 这没有帮助。后来我注意到,问题只发生在 VM 的 boot_disk 中:

  boot_disk {
    kms_key_self_link = var.kms_key_selflink

    initialize_params {
      image = var.vm_image
      type  = var.gce_disk_type
    }
  }

当我注释掉 kms_key_self_link 块中的 boot_disk 时,其他资源(快照、计算磁盘、附加磁盘)也使用 kms_key_self_link自定义服务帐户毫无问题地进行配置。如果我将 kms_key_self_link 参数保留在 boot_disk 中,问题仍然存在,我需要指定认代理才能解决问题。

有没有办法只使用自定义服务帐户来配置我的所有资源,而无需认计算引擎服务代理的任何参与,我只是在我的脚本中遗漏了一些东西,或者认代理是否需要保留对于某些操作?

解决方法

因此,正如通过提供的答案所证明的那样,如果没有 Compute Engine 服务代理的参与,就不可能获得所有资源。它必须具有

roles/cloudkms.cryptoKeyEncrypterDecrypter

授予的角色,与使用的任何其他自定义服务帐户无关。这是我在 Terraform 代码中使用的策略来授予它必要的权限:

data "google_iam_policy" "kms_key_encrypt_decrypt" {
  binding {
    role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"

    members = ["serviceAccount:service{{PROJECT_NUMBER}}@computesystem.iam.gserviceaccount.com"]
  }
}

resource "google_kms_crypto_key_iam_policy" "crypto_key" {
  crypto_key_id = google_kms_crypto_key.key.id
  policy_data   = data.google_iam_policy.kms_key_encrypt_decrypt.policy_data
}

感谢大家的回答。