diff --git a/google/data_source_google_compute_instance.go b/google/data_source_google_compute_instance.go index 0caf5bcf5a6..f2f72811575 100644 --- a/google/data_source_google_compute_instance.go +++ b/google/data_source_google_compute_instance.go @@ -101,6 +101,7 @@ func dataSourceGoogleComputeInstanceRead(d *schema.ResourceData, meta interface{ } if key := disk.DiskEncryptionKey; key != nil { di["disk_encryption_key_sha256"] = key.Sha256 + di["kms_key_self_link"] = key.KmsKeyName } attachedDisks = append(attachedDisks, di) } diff --git a/google/resource_compute_instance.go b/google/resource_compute_instance.go index ff3fb62af45..edf7d7cf0ab 100644 --- a/google/resource_compute_instance.go +++ b/google/resource_compute_instance.go @@ -75,6 +75,12 @@ func resourceComputeInstance() *schema.Resource { Computed: true, }, + "kms_key_self_link": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "initialize_params": { Type: schema.TypeList, Optional: true, @@ -270,6 +276,11 @@ func resourceComputeInstance() *schema.Resource { Sensitive: true, }, + "kms_key_self_link": { + Type: schema.TypeString, + Optional: true, + }, + "disk_encryption_key_sha256": { Type: schema.TypeString, Computed: true, @@ -355,6 +366,12 @@ func resourceComputeInstance() *schema.Resource { Sensitive: true, }, + "kms_key_self_link": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "disk_encryption_key_sha256": { Type: schema.TypeString, Computed: true, @@ -860,6 +877,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error if inConfig { di["disk_encryption_key_raw"] = d.Get(fmt.Sprintf("attached_disk.%d.disk_encryption_key_raw", adIndex)) } + di["kms_key_self_link"] = key.KmsKeyName di["disk_encryption_key_sha256"] = key.Sha256 } // We want the disks to remain in the order we set in the config, so if a disk @@ -1371,6 +1389,12 @@ func expandAttachedDisk(diskConfig map[string]interface{}, d *schema.ResourceDat RawKey: v.(string), } } + + if v, ok := diskConfig["kms_key_self_link"]; ok { + disk.DiskEncryptionKey = &computeBeta.CustomerEncryptionKey{ + KmsKeyName: v.(string), + } + } return disk, nil } @@ -1506,6 +1530,12 @@ func expandBootDisk(d *schema.ResourceData, config *Config, zone *compute.Zone, } } + if v, ok := d.GetOk("boot_disk.0.kms_key_self_link"); ok { + disk.DiskEncryptionKey = &computeBeta.CustomerEncryptionKey{ + KmsKeyName: v.(string), + } + } + if v, ok := d.GetOk("boot_disk.0.source"); ok { source, err := ParseDiskFieldValue(v.(string), d, config) if err != nil { @@ -1576,6 +1606,7 @@ func flattenBootDisk(d *schema.ResourceData, disk *computeBeta.AttachedDisk, con if disk.DiskEncryptionKey != nil { result["disk_encryption_key_sha256"] = disk.DiskEncryptionKey.Sha256 + result["kms_key_self_link"] = disk.DiskEncryptionKey.KmsKeyName } return []map[string]interface{}{result} diff --git a/google/resource_compute_instance_test.go b/google/resource_compute_instance_test.go index 827ebd24f4f..c76706d3644 100644 --- a/google/resource_compute_instance_test.go +++ b/google/resource_compute_instance_test.go @@ -282,6 +282,40 @@ func TestAccComputeInstance_diskEncryption(t *testing.T) { }) } +func TestAccComputeInstance_kmsDiskEncryption(t *testing.T) { + t.Parallel() + + var instance compute.Instance + var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10)) + bootKmsKeyName := "projects/project/locations/us-central1/keyRings/testing-cloud-kms/cryptoKeys/key-0/cryptoKeyVersions/1" + diskNameToEncryptionKey := map[string]*compute.CustomerEncryptionKey{ + fmt.Sprintf("instance-testd-%s", acctest.RandString(10)): { + KmsKeyName: "projects/project/locations/us-central1/keyRings/testing-cloud-kms/cryptoKeys/key-1/cryptoKeyVersions/1", + }, + fmt.Sprintf("instance-testd-%s", acctest.RandString(10)): { + KmsKeyName: "projects/project/locations/us-central1/keyRings/testing-cloud-kms/cryptoKeys/key-2/cryptoKeyVersions/1", + }, + fmt.Sprintf("instance-testd-%s", acctest.RandString(10)): { + KmsKeyName: "projects/project/locations/us-central1/keyRings/testing-cloud-kms/cryptoKeys/key-3/cryptoKeyVersions/1", + }, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_disks_encryption(bootKmsKeyName, diskNameToEncryptionKey, instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists("google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceDiskKmsEncryptionKey("google_compute_instance.foobar", &instance, bootKmsKeyName, diskNameToEncryptionKey), + ), + }, + }, + }) +} + func TestAccComputeInstance_attachedDisk(t *testing.T) { t.Parallel() @@ -1363,6 +1397,50 @@ func testAccCheckComputeInstanceDiskEncryptionKey(n string, instance *compute.In } } +func testAccCheckComputeInstanceDiskKmsEncryptionKey(n string, instance *compute.Instance, bootDiskEncryptionKey string, diskNameToEncryptionKey map[string]*compute.CustomerEncryptionKey) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + for i, disk := range instance.Disks { + if disk.Boot { + attr := rs.Primary.Attributes["boot_disk.0.kms_key_self_link"] + if attr != bootDiskEncryptionKey { + return fmt.Errorf("Boot disk has wrong encryption key in state.\nExpected: %s\nActual: %s", bootDiskEncryptionKey, attr) + } + if disk.DiskEncryptionKey == nil && attr != "" { + return fmt.Errorf("Disk %d has mismatched encryption key.\nTF State: %+v\nGCP State: ", i, attr) + } + } else { + if disk.DiskEncryptionKey != nil { + expectedKey := diskNameToEncryptionKey[GetResourceNameFromSelfLink(disk.Source)].KmsKeyName + if disk.DiskEncryptionKey.KmsKeyName != expectedKey { + return fmt.Errorf("Disk %d has unexpected encryption key in GCP.\nExpected: %s\nActual: %s", i, expectedKey, disk.DiskEncryptionKey.Sha256) + } + } + } + } + + numAttachedDisks, err := strconv.Atoi(rs.Primary.Attributes["attached_disk.#"]) + if err != nil { + return fmt.Errorf("Error converting value of attached_disk.#") + } + for i := 0; i < numAttachedDisks; i++ { + diskName := GetResourceNameFromSelfLink(rs.Primary.Attributes[fmt.Sprintf("attached_disk.%d.source", i)]) + kmsKeyName := rs.Primary.Attributes[fmt.Sprintf("attached_disk.%d.kms_key_self_link", i)] + if key, ok := diskNameToEncryptionKey[diskName]; ok { + expectedEncryptionKey := key.KmsKeyName + if kmsKeyName != expectedEncryptionKey { + return fmt.Errorf("Attached disk %d has unexpected encryption key in state.\nExpected: %s\nActual: %s", i, expectedEncryptionKey, kmsKeyName) + } + } + } + return nil + } +} + func testAccCheckComputeInstanceTag(instance *compute.Instance, n string) resource.TestCheckFunc { return func(s *terraform.State) error { if instance.Tags == nil {