Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for creating instances with CMEK #3481

Merged
merged 8 commits into from
May 13, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions google/data_source_google_compute_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
31 changes: 31 additions & 0 deletions google/resource_compute_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -355,6 +366,12 @@ func resourceComputeInstance() *schema.Resource {
Sensitive: true,
},

"kms_key_self_link": {
zachberger marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},

"disk_encryption_key_sha256": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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),
zachberger marked this conversation as resolved.
Show resolved Hide resolved
}
}
return disk, nil
}

Expand Down Expand Up @@ -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 {
zachberger marked this conversation as resolved.
Show resolved Hide resolved
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 {
Expand Down Expand Up @@ -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}
Expand Down
78 changes: 78 additions & 0 deletions google/resource_compute_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
zachberger marked this conversation as resolved.
Show resolved Hide resolved
fmt.Sprintf("instance-testd-%s", acctest.RandString(10)): {
KmsKeyName: "projects/project/locations/us-central1/keyRings/testing-cloud-kms/cryptoKeys/key-1/cryptoKeyVersions/1",
zachberger marked this conversation as resolved.
Show resolved Hide resolved
},
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),
),
},
},
zachberger marked this conversation as resolved.
Show resolved Hide resolved
})
}

func TestAccComputeInstance_attachedDisk(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -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: <empty>", 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 {
Expand Down
6 changes: 6 additions & 0 deletions website/docs/r/compute_instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ The `boot_disk` block supports:
encoded in [RFC 4648 base64](https://tools.ietf.org/html/rfc4648#section-4)
to encrypt this disk.

* `kms_key_self_link` - (Optional) The self_link of the encryption key that is
stored in Google Cloud KMS to encrypt this disk.

* `initialize_params` - (Optional) Parameters for a new disk that will be created
alongside the new instance. Either `initialize_params` or `source` must be set.
Structure is documented below.
Expand Down Expand Up @@ -195,6 +198,9 @@ The `attached_disk` block supports:
encoded in [RFC 4648 base64](https://tools.ietf.org/html/rfc4648#section-4)
to encrypt this disk.

* `kms_key_self_link` - (Optional) The self_link of the encryption key that is
stored in Google Cloud KMS to encrypt this disk.

The `network_interface` block supports:

* `network` - (Optional) The name or self_link of the network to attach this interface to.
Expand Down