diff --git a/.changelog/6919.txt b/.changelog/6919.txt
new file mode 100644
index 00000000000..89a4685cfe7
--- /dev/null
+++ b/.changelog/6919.txt
@@ -0,0 +1,6 @@
+```release-note:enhancement
+compute: added support for `image_encryption_key` to `google_compute_image`
+```
+```release-note:enhancement
+compute: added support for `source_snapshot`, `source_snapshot_encyption_key`, and `source_image_encryption_key` to `google_compute_instance_template`
+```
diff --git a/google/resource_compute_image.go b/google/resource_compute_image.go
index a48de727bcb..00ee76941bb 100644
--- a/google/resource_compute_image.go
+++ b/google/resource_compute_image.go
@@ -18,6 +18,7 @@ import (
"fmt"
"log"
"reflect"
+ "strings"
"time"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -87,6 +88,37 @@ Applicable only for bootable images.`,
Elem: computeImageGuestOsFeaturesSchema(),
// Default schema.HashSchema is used.
},
+ "image_encryption_key": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: `Encrypts the image using a customer-supplied encryption key.
+
+After you encrypt an image with a customer-supplied key, you must
+provide the same key if you use the image later (e.g. to create a
+disk from the image)`,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "kms_key_self_link": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ DiffSuppressFunc: compareSelfLinkRelativePaths,
+ Description: `The self link of the encryption key that is stored in Google Cloud
+KMS.`,
+ },
+ "kms_key_service_account": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: `The service account being used for the encryption request for the
+given KMS key. If absent, the Compute Engine default service
+account is used.`,
+ },
+ },
+ },
+ },
"labels": {
Type: schema.TypeMap,
Optional: true,
@@ -256,6 +288,12 @@ func resourceComputeImageCreate(d *schema.ResourceData, meta interface{}) error
} else if v, ok := d.GetOkExists("guest_os_features"); !isEmptyValue(reflect.ValueOf(guestOsFeaturesProp)) && (ok || !reflect.DeepEqual(v, guestOsFeaturesProp)) {
obj["guestOsFeatures"] = guestOsFeaturesProp
}
+ imageEncryptionKeyProp, err := expandComputeImageImageEncryptionKey(d.Get("image_encryption_key"), d, config)
+ if err != nil {
+ return err
+ } else if v, ok := d.GetOkExists("image_encryption_key"); !isEmptyValue(reflect.ValueOf(imageEncryptionKeyProp)) && (ok || !reflect.DeepEqual(v, imageEncryptionKeyProp)) {
+ obj["imageEncryptionKey"] = imageEncryptionKeyProp
+ }
labelsProp, err := expandComputeImageLabels(d.Get("labels"), d, config)
if err != nil {
return err
@@ -403,6 +441,9 @@ func resourceComputeImageRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("guest_os_features", flattenComputeImageGuestOsFeatures(res["guestOsFeatures"], d, config)); err != nil {
return fmt.Errorf("Error reading Image: %s", err)
}
+ if err := d.Set("image_encryption_key", flattenComputeImageImageEncryptionKey(res["imageEncryptionKey"], d, config)); err != nil {
+ return fmt.Errorf("Error reading Image: %s", err)
+ }
if err := d.Set("labels", flattenComputeImageLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading Image: %s", err)
}
@@ -627,6 +668,33 @@ func flattenComputeImageGuestOsFeaturesType(v interface{}, d *schema.ResourceDat
return v
}
+func flattenComputeImageImageEncryptionKey(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ if v == nil {
+ return nil
+ }
+ original := v.(map[string]interface{})
+ if len(original) == 0 {
+ return nil
+ }
+ transformed := make(map[string]interface{})
+ transformed["kms_key_self_link"] =
+ flattenComputeImageImageEncryptionKeyKmsKeySelfLink(original["kmsKeyName"], d, config)
+ transformed["kms_key_service_account"] =
+ flattenComputeImageImageEncryptionKeyKmsKeyServiceAccount(original["kmsKeyServiceAccount"], d, config)
+ return []interface{}{transformed}
+}
+func flattenComputeImageImageEncryptionKeyKmsKeySelfLink(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ if v == nil {
+ return v
+ }
+ vStr := v.(string)
+ return strings.Split(vStr, "/cryptoKeyVersions/")[0]
+}
+
+func flattenComputeImageImageEncryptionKeyKmsKeyServiceAccount(v interface{}, d *schema.ResourceData, config *Config) interface{} {
+ return v
+}
+
func flattenComputeImageLabels(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}
@@ -706,6 +774,40 @@ func expandComputeImageGuestOsFeaturesType(v interface{}, d TerraformResourceDat
return v, nil
}
+func expandComputeImageImageEncryptionKey(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ l := v.([]interface{})
+ if len(l) == 0 || l[0] == nil {
+ return nil, nil
+ }
+ raw := l[0]
+ original := raw.(map[string]interface{})
+ transformed := make(map[string]interface{})
+
+ transformedKmsKeySelfLink, err := expandComputeImageImageEncryptionKeyKmsKeySelfLink(original["kms_key_self_link"], d, config)
+ if err != nil {
+ return nil, err
+ } else if val := reflect.ValueOf(transformedKmsKeySelfLink); val.IsValid() && !isEmptyValue(val) {
+ transformed["kmsKeyName"] = transformedKmsKeySelfLink
+ }
+
+ transformedKmsKeyServiceAccount, err := expandComputeImageImageEncryptionKeyKmsKeyServiceAccount(original["kms_key_service_account"], d, config)
+ if err != nil {
+ return nil, err
+ } else if val := reflect.ValueOf(transformedKmsKeyServiceAccount); val.IsValid() && !isEmptyValue(val) {
+ transformed["kmsKeyServiceAccount"] = transformedKmsKeyServiceAccount
+ }
+
+ return transformed, nil
+}
+
+func expandComputeImageImageEncryptionKeyKmsKeySelfLink(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ return v, nil
+}
+
+func expandComputeImageImageEncryptionKeyKmsKeyServiceAccount(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ return v, nil
+}
+
func expandComputeImageLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
diff --git a/google/resource_compute_image_test.go b/google/resource_compute_image_test.go
index 94844bf91bc..4fd39532a4f 100644
--- a/google/resource_compute_image_test.go
+++ b/google/resource_compute_image_test.go
@@ -211,6 +211,30 @@ func TestAccComputeImage_resolveImage(t *testing.T) {
})
}
+func TestAccComputeImage_imageEncryptionKey(t *testing.T) {
+ t.Parallel()
+
+ kmsKey := BootstrapKMSKeyInLocation(t, "us-central1")
+ kmsKeyName := GetResourceNameFromSelfLink(kmsKey.CryptoKey.Name)
+ kmsRingName := GetResourceNameFromSelfLink(kmsKey.KeyRing.Name)
+
+ vcrTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccComputeImage_imageEncryptionKey(kmsRingName, kmsKeyName, randString(t, 10)),
+ },
+ {
+ ResourceName: "google_compute_image.image",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
func testAccCheckComputeImageResolution(t *testing.T, n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
config := googleProviderConfig(t)
@@ -450,3 +474,42 @@ resource "google_compute_image" "foobar" {
}
`, diskName, snapshotName, imageName)
}
+
+func testAccComputeImage_imageEncryptionKey(kmsRingName, kmsKeyName, suffix string) string {
+ return fmt.Sprintf(`
+data "google_kms_key_ring" "ring" {
+ name = "%s"
+ location = "us-central1"
+}
+
+data "google_kms_crypto_key" "key" {
+ name = "%s"
+ key_ring = data.google_kms_key_ring.ring.id
+}
+
+resource "google_service_account" "test" {
+ account_id = "tf-test-sa-%s"
+ display_name = "KMS Ops Account"
+}
+
+resource "google_kms_crypto_key_iam_member" "crypto_key" {
+ crypto_key_id = data.google_kms_crypto_key.key.id
+ role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
+ member = "serviceAccount:${google_service_account.test.email}"
+}
+
+data "google_compute_image" "debian" {
+ family = "debian-11"
+ project = "debian-cloud"
+}
+
+resource "google_compute_image" "image" {
+ name = "tf-test-image-%s"
+ source_image = data.google_compute_image.debian.self_link
+ image_encryption_key {
+ kms_key_self_link = data.google_kms_crypto_key.key.id
+ kms_key_service_account = google_service_account.test.email
+ }
+}
+`, kmsRingName, kmsKeyName, suffix, suffix)
+}
diff --git a/google/resource_compute_instance_template.go b/google/resource_compute_instance_template.go
index 1f591b075ab..d3c86734d54 100644
--- a/google/resource_compute_instance_template.go
+++ b/google/resource_compute_instance_template.go
@@ -160,6 +160,74 @@ func resourceComputeInstanceTemplate() *schema.Resource {
ForceNew: true,
Description: `The image from which to initialize this disk. This can be one of: the image's self_link, projects/{project}/global/images/{image}, projects/{project}/global/images/family/{family}, global/images/{image}, global/images/family/{family}, family/{family}, {project}/{family}, {project}/{image}, {family}, or {image}. ~> Note: Either source or source_image is required when creating a new instance except for when creating a local SSD.`,
},
+ "source_image_encryption_key": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: `The customer-supplied encryption key of the source
+image. Required if the source image is protected by a
+customer-supplied encryption key.
+
+Instance templates do not store customer-supplied
+encryption keys, so you cannot create disks for
+instances in a managed instance group if the source
+images are encrypted with your own keys.`,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "kms_key_service_account": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: `The service account being used for the encryption
+request for the given KMS key. If absent, the Compute
+Engine default service account is used.`,
+ },
+ "kms_key_self_link": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: `The self link of the encryption key that is stored in
+Google Cloud KMS.`,
+ },
+ },
+ },
+ },
+ "source_snapshot": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: `The source snapshot to create this disk. When creating
+a new instance, one of initializeParams.sourceSnapshot,
+initializeParams.sourceImage, or disks.source is
+required except for local SSD.`,
+ },
+ "source_snapshot_encryption_key": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: `The customer-supplied encryption key of the source snapshot.`,
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "kms_key_service_account": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: `The service account being used for the encryption
+request for the given KMS key. If absent, the Compute
+Engine default service account is used.`,
+ },
+ "kms_key_self_link": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: `The self link of the encryption key that is stored in
+Google Cloud KMS.`,
+ },
+ },
+ },
+ },
"interface": {
Type: schema.TypeString,
@@ -886,7 +954,7 @@ func buildDisks(d *schema.ResourceData, config *Config) ([]*compute.AttachedDisk
if v, ok := d.GetOk(prefix + ".source"); ok {
disk.Source = v.(string)
- conflicts := []string{"disk_size_gb", "disk_name", "disk_type", "source_image", "labels"}
+ conflicts := []string{"disk_size_gb", "disk_name", "disk_type", "source_image", "source_snapshot", "labels"}
for _, conflict := range conflicts {
if _, ok := d.GetOk(prefix + "." + conflict); ok {
return nil, fmt.Errorf("Cannot use `source` with any of the fields in %s", conflicts)
@@ -906,6 +974,8 @@ func buildDisks(d *schema.ResourceData, config *Config) ([]*compute.AttachedDisk
disk.InitializeParams.DiskType = v.(string)
}
+ disk.InitializeParams.Labels = expandStringMap(d, prefix+".labels")
+
if v, ok := d.GetOk(prefix + ".source_image"); ok {
imageName := v.(string)
imageUrl, err := resolveImage(config, project, imageName, userAgent)
@@ -917,7 +987,29 @@ func buildDisks(d *schema.ResourceData, config *Config) ([]*compute.AttachedDisk
disk.InitializeParams.SourceImage = imageUrl
}
- disk.InitializeParams.Labels = expandStringMap(d, prefix+".labels")
+ if _, ok := d.GetOk(prefix + ".source_image_encryption_key"); ok {
+ disk.InitializeParams.SourceImageEncryptionKey = &compute.CustomerEncryptionKey{}
+ if v, ok := d.GetOk(prefix + ".source_image_encryption_key.0.kms_key_self_link"); ok {
+ disk.InitializeParams.SourceImageEncryptionKey.KmsKeyName = v.(string)
+ }
+ if v, ok := d.GetOk(prefix + ".source_image_encryption_key.0.kms_key_service_account"); ok {
+ disk.InitializeParams.SourceImageEncryptionKey.KmsKeyServiceAccount = v.(string)
+ }
+ }
+
+ if v, ok := d.GetOk(prefix + ".source_snapshot"); ok {
+ disk.InitializeParams.SourceSnapshot = v.(string)
+ }
+
+ if _, ok := d.GetOk(prefix + ".source_snapshot_encryption_key"); ok {
+ disk.InitializeParams.SourceSnapshotEncryptionKey = &compute.CustomerEncryptionKey{}
+ if v, ok := d.GetOk(prefix + ".source_snapshot_encryption_key.0.kms_key_self_link"); ok {
+ disk.InitializeParams.SourceSnapshotEncryptionKey.KmsKeyName = v.(string)
+ }
+ if v, ok := d.GetOk(prefix + ".source_snapshot_encryption_key.0.kms_key_service_account"); ok {
+ disk.InitializeParams.SourceSnapshotEncryptionKey.KmsKeyServiceAccount = v.(string)
+ }
+ }
if _, ok := d.GetOk(prefix + ".resource_policies"); ok {
// instance template only supports a resource name here (not uri)
@@ -1100,8 +1192,14 @@ func diskCharacteristicsFromMap(m map[string]interface{}) diskCharacteristics {
return dc
}
-func flattenDisk(disk *compute.AttachedDisk, defaultProject string) (map[string]interface{}, error) {
+func flattenDisk(disk *compute.AttachedDisk, configDisk map[string]any, defaultProject string) (map[string]interface{}, error) {
diskMap := make(map[string]interface{})
+
+ // These values are not returned by the API, so we copy them from the config.
+ diskMap["source_image_encryption_key"] = configDisk["source_image_encryption_key"]
+ diskMap["source_snapshot"] = configDisk["source_snapshot"]
+ diskMap["source_snapshot_encryption_key"] = configDisk["source_snapshot_encryption_key"]
+
if disk.InitializeParams != nil {
if disk.InitializeParams.SourceImage != "" {
path, err := resolveImageRefToRelativeURI(defaultProject, disk.InitializeParams.SourceImage)
@@ -1266,11 +1364,12 @@ func flattenDisks(disks []*compute.AttachedDisk, d *schema.ResourceData, default
apiDisks := make([]map[string]interface{}, len(disks))
for i, disk := range disks {
- d, err := flattenDisk(disk, defaultProject)
+ configDisk := d.Get(fmt.Sprintf("disk.%d", i)).(map[string]any)
+ apiDisk, err := flattenDisk(disk, configDisk, defaultProject)
if err != nil {
return nil, err
}
- apiDisks[i] = d
+ apiDisks[i] = apiDisk
}
return reorderDisks(d.Get("disk").([]interface{}), apiDisks), nil
diff --git a/google/resource_compute_instance_template_test.go b/google/resource_compute_instance_template_test.go
index e8ad7261d66..21fbdf9ef35 100644
--- a/google/resource_compute_instance_template_test.go
+++ b/google/resource_compute_instance_template_test.go
@@ -1108,6 +1108,66 @@ func TestAccComputeInstanceTemplate_spot(t *testing.T) {
})
}
+func TestAccComputeInstanceTemplate_sourceSnapshotEncryptionKey(t *testing.T) {
+ t.Parallel()
+
+ var instanceTemplate compute.InstanceTemplate
+ kmsKey := BootstrapKMSKeyInLocation(t, "us-central1")
+ kmsKeyName := GetResourceNameFromSelfLink(kmsKey.CryptoKey.Name)
+ kmsRingName := GetResourceNameFromSelfLink(kmsKey.KeyRing.Name)
+
+ vcrTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccComputeInstanceTemplate_sourceSnapshotEncryptionKey(kmsRingName, kmsKeyName, randString(t, 10)),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckComputeInstanceTemplateExists(
+ t, "google_compute_instance_template.template", &instanceTemplate),
+ ),
+ },
+ {
+ ResourceName: "google_compute_instance_template.template",
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"disk.0.source_snapshot", "disk.0.source_snapshot_encryption_key"},
+ },
+ },
+ })
+}
+
+func TestAccComputeInstanceTemplate_sourceImageEncryptionKey(t *testing.T) {
+ t.Parallel()
+
+ var instanceTemplate compute.InstanceTemplate
+ kmsKey := BootstrapKMSKeyInLocation(t, "us-central1")
+ kmsKeyName := GetResourceNameFromSelfLink(kmsKey.CryptoKey.Name)
+ kmsRingName := GetResourceNameFromSelfLink(kmsKey.KeyRing.Name)
+
+ vcrTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccComputeInstanceTemplate_sourceImageEncryptionKey(kmsRingName, kmsKeyName, randString(t, 10)),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckComputeInstanceTemplateExists(
+ t, "google_compute_instance_template.template", &instanceTemplate),
+ ),
+ },
+ {
+ ResourceName: "google_compute_instance_template.template",
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"disk.0.source_image_encryption_key"},
+ },
+ },
+ })
+}
+
func testAccCheckComputeInstanceTemplateDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
config := googleProviderConfig(t)
@@ -2829,3 +2889,129 @@ resource "google_compute_instance_template" "foobar" {
}
`, suffix)
}
+
+func testAccComputeInstanceTemplate_sourceSnapshotEncryptionKey(kmsRingName, kmsKeyName, suffix string) string {
+ return fmt.Sprintf(`
+data "google_kms_key_ring" "ring" {
+ name = "%s"
+ location = "us-central1"
+}
+
+data "google_kms_crypto_key" "key" {
+ name = "%s"
+ key_ring = data.google_kms_key_ring.ring.id
+}
+
+resource "google_service_account" "test" {
+ account_id = "test-sa-%s"
+ display_name = "KMS Ops Account"
+}
+
+resource "google_kms_crypto_key_iam_member" "crypto_key" {
+ crypto_key_id = data.google_kms_crypto_key.key.id
+ role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
+ member = "serviceAccount:${google_service_account.test.email}"
+}
+
+data "google_compute_image" "debian" {
+ family = "debian-11"
+ project = "debian-cloud"
+}
+
+resource "google_compute_disk" "persistent" {
+ name = "debian-disk"
+ image = data.google_compute_image.debian.self_link
+ size = 10
+ type = "pd-ssd"
+ zone = "us-central1-a"
+}
+
+resource "google_compute_snapshot" "snapshot" {
+ name = "my-snapshot"
+ source_disk = google_compute_disk.persistent.id
+ zone = "us-central1-a"
+ snapshot_encryption_key {
+ kms_key_self_link = data.google_kms_crypto_key.key.id
+ kms_key_service_account = google_service_account.test.email
+ }
+}
+
+resource "google_compute_instance_template" "template" {
+ name = "tf-test-instance-template-%s"
+ machine_type = "e2-medium"
+
+ disk {
+ source_snapshot = google_compute_snapshot.snapshot.self_link
+ source_snapshot_encryption_key {
+ kms_key_self_link = data.google_kms_crypto_key.key.id
+ kms_key_service_account = google_service_account.test.email
+ }
+ auto_delete = true
+ boot = true
+ }
+
+ network_interface {
+ network = "default"
+ }
+}
+`, kmsRingName, kmsKeyName, suffix, suffix)
+}
+
+func testAccComputeInstanceTemplate_sourceImageEncryptionKey(kmsRingName, kmsKeyName, suffix string) string {
+ return fmt.Sprintf(`
+data "google_kms_key_ring" "ring" {
+ name = "%s"
+ location = "us-central1"
+}
+
+data "google_kms_crypto_key" "key" {
+ name = "%s"
+ key_ring = data.google_kms_key_ring.ring.id
+}
+
+resource "google_service_account" "test" {
+ account_id = "tf-test-sa-%s"
+ display_name = "KMS Ops Account"
+}
+
+resource "google_kms_crypto_key_iam_member" "crypto_key" {
+ crypto_key_id = data.google_kms_crypto_key.key.id
+ role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
+ member = "serviceAccount:${google_service_account.test.email}"
+}
+
+data "google_compute_image" "debian" {
+ family = "debian-11"
+ project = "debian-cloud"
+}
+
+resource "google_compute_image" "image" {
+ name = "debian-image"
+ source_image = data.google_compute_image.debian.self_link
+ image_encryption_key {
+ kms_key_self_link = data.google_kms_crypto_key.key.id
+ kms_key_service_account = google_service_account.test.email
+ }
+}
+
+
+resource "google_compute_instance_template" "template" {
+ name = "tf-test-instance-template-%s"
+ machine_type = "e2-medium"
+
+ disk {
+ source_image = google_compute_image.image.self_link
+ source_image_encryption_key {
+ kms_key_self_link = data.google_kms_crypto_key.key.id
+ kms_key_service_account = google_service_account.test.email
+ }
+ auto_delete = true
+ boot = true
+ }
+
+ network_interface {
+ network = "default"
+ }
+}
+`, kmsRingName, kmsKeyName, suffix, suffix)
+}
diff --git a/google/resource_compute_snapshot.go b/google/resource_compute_snapshot.go
index 5e95d1a6940..fd525c6b045 100644
--- a/google/resource_compute_snapshot.go
+++ b/google/resource_compute_snapshot.go
@@ -89,8 +89,19 @@ resource, this field is visible only if it has a non-empty value.`,
Type: schema.TypeList,
Optional: true,
ForceNew: true,
- Description: `The customer-supplied encryption key of the snapshot. Required if the
-source snapshot is protected by a customer-supplied encryption key.`,
+ Description: `Encrypts the snapshot using a customer-supplied encryption key.
+
+After you encrypt a snapshot using a customer-supplied key, you must
+provide the same key if you use the snapshot later. For example, you
+must provide the encryption key when you create a disk from the
+encrypted snapshot in a future request.
+
+Customer-supplied encryption keys do not protect access to metadata of
+the snapshot.
+
+If you do not provide an encryption key when creating the snapshot,
+then the snapshot will be encrypted using an automatically generated
+key and you do not need to provide a key to use the snapshot later.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
diff --git a/website/docs/r/compute_image.html.markdown b/website/docs/r/compute_image.html.markdown
index 9da4174bb43..aa4cb70d884 100644
--- a/website/docs/r/compute_image.html.markdown
+++ b/website/docs/r/compute_image.html.markdown
@@ -129,6 +129,14 @@ The following arguments are supported:
Applicable only for bootable images.
Structure is [documented below](#nested_guest_os_features).
+* `image_encryption_key` -
+ (Optional)
+ Encrypts the image using a customer-supplied encryption key.
+ After you encrypt an image with a customer-supplied key, you must
+ provide the same key if you use the image later (e.g. to create a
+ disk from the image)
+ Structure is [documented below](#nested_image_encryption_key).
+
* `labels` -
(Optional)
Labels to apply to this Image.
@@ -178,6 +186,19 @@ The following arguments are supported:
The type of supported feature. Read [Enabling guest operating system features](https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#guest-os-features) to see a list of available options.
Possible values are `MULTI_IP_SUBNET`, `SECURE_BOOT`, `SEV_CAPABLE`, `UEFI_COMPATIBLE`, `VIRTIO_SCSI_MULTIQUEUE`, `WINDOWS`, and `GVNIC`.
+The `image_encryption_key` block supports:
+
+* `kms_key_self_link` -
+ (Optional)
+ The self link of the encryption key that is stored in Google Cloud
+ KMS.
+
+* `kms_key_service_account` -
+ (Optional)
+ The service account being used for the encryption request for the
+ given KMS key. If absent, the Compute Engine default service
+ account is used.
+
The `raw_disk` block supports:
* `container_type` -
diff --git a/website/docs/r/compute_instance_template.html.markdown b/website/docs/r/compute_instance_template.html.markdown
index ee1228c9cee..06e943dad0a 100644
--- a/website/docs/r/compute_instance_template.html.markdown
+++ b/website/docs/r/compute_instance_template.html.markdown
@@ -382,7 +382,23 @@ The following arguments are supported:
`projects/{project}/global/images/family/{family}`, `global/images/{image}`,
`global/images/family/{family}`, `family/{family}`, `{project}/{family}`,
`{project}/{image}`, `{family}`, or `{image}`.
-~> **Note:** Either `source` or `source_image` is **required** in a disk block unless the disk type is `local-ssd`. Check the API [docs](https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates/insert) for details.
+~> **Note:** Either `source`, `source_image`, or `source_snapshot` is **required** in a disk block unless the disk type is `local-ssd`. Check the API [docs](https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates/insert) for details.
+
+* `source_image_encryption_key` - (Optional) The customer-supplied encryption
+ key of the source image. Required if the source image is protected by a
+ customer-supplied encryption key.
+
+ Instance templates do not store customer-supplied encryption keys, so you
+ cannot create disks for instances in a managed instance group if the source
+ images are encrypted with your own keys. Structure
+ [documented below](#nested_source_image_encryption_key).
+
+* `source_snapshot` - (Optional) The source snapshot to create this disk.
+~> **Note:** Either `source`, `source_image`, or `source_snapshot` is **required** in a disk block unless the disk type is `local-ssd`. Check the API [docs](https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates/insert) for details.
+
+* `source_snapshot_encryption_key` - (Optional) The customer-supplied encryption
+ key of the source snapshot. Structure
+ [documented below](#nested_source_snapshot_encryption_key).
* `interface` - (Optional) Specifies the disk interface to use for attaching this disk,
which is either SCSI or NVME. The default is SCSI. Persistent disks must always use SCSI
@@ -395,7 +411,7 @@ The following arguments are supported:
* `source` - (Optional) The name (**not self_link**)
of the disk (such as those managed by `google_compute_disk`) to attach.
-~> **Note:** Either `source` or `source_image` is **required** in a disk block unless the disk type is `local-ssd`. Check the API [docs](https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates/insert) for details.
+~> **Note:** Either `source`, `source_image`, or `source_snapshot` is **required** in a disk block unless the disk type is `local-ssd`. Check the API [docs](https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates/insert) for details.
* `disk_type` - (Optional) The GCE disk type. Such as `"pd-ssd"`, `"local-ssd"`,
`"pd-balanced"` or `"pd-standard"`.
@@ -418,11 +434,29 @@ The following arguments are supported:
If you do not provide an encryption key, then the disk will be encrypted using an automatically generated key and you do not need to provide a key to use the disk later.
- Instance templates do not store customer-supplied encryption keys, so you cannot use your own keys to encrypt disks in a managed instance group.
+ Instance templates do not store customer-supplied encryption keys, so you cannot use your own keys to encrypt disks in a managed instance group. Structure [documented below](#nested_access_config).
* `resource_policies` (Optional) -- A list (short name or id) of resource policies to attach to this disk for automatic snapshot creations. Currently a max of 1 resource policy is supported.
-The `disk_encryption_key` block supports:
+The `source_image_encryption_key` block supports:
+
+* `kms_key_service_account` - (Optional) The service account being used for the
+ encryption request for the given KMS key. If absent, the Compute Engine
+ default service account is used.
+
+* `kms_key_self_link` - (Required) The self link of the encryption key that is
+ stored in Google Cloud KMS.
+
+The `source_snapshot_encryption_key` block supports:
+
+* `kms_key_service_account` - (Optional) The service account being used for the
+ encryption request for the given KMS key. If absent, the Compute Engine
+ default service account is used.
+
+* `kms_key_self_link` - (Required) The self link of the encryption key that is
+ stored in Google Cloud KMS.
+
+The `disk_encryption_key` block supports:
* `kms_key_self_link` - (Required) The self link of the encryption key that is stored in Google Cloud KMS
diff --git a/website/docs/r/compute_snapshot.html.markdown b/website/docs/r/compute_snapshot.html.markdown
index 38c526a6587..42c2f9c0f90 100644
--- a/website/docs/r/compute_snapshot.html.markdown
+++ b/website/docs/r/compute_snapshot.html.markdown
@@ -159,8 +159,16 @@ The following arguments are supported:
* `snapshot_encryption_key` -
(Optional)
- The customer-supplied encryption key of the snapshot. Required if the
- source snapshot is protected by a customer-supplied encryption key.
+ Encrypts the snapshot using a customer-supplied encryption key.
+ After you encrypt a snapshot using a customer-supplied key, you must
+ provide the same key if you use the snapshot later. For example, you
+ must provide the encryption key when you create a disk from the
+ encrypted snapshot in a future request.
+ Customer-supplied encryption keys do not protect access to metadata of
+ the snapshot.
+ If you do not provide an encryption key when creating the snapshot,
+ then the snapshot will be encrypted using an automatically generated
+ key and you do not need to provide a key to use the snapshot later.
Structure is [documented below](#nested_snapshot_encryption_key).
* `source_disk_encryption_key` -