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` -