diff --git a/google/resource_compute_disk_test.go b/google/resource_compute_disk_test.go index 43a98721..cd65ab38 100644 --- a/google/resource_compute_disk_test.go +++ b/google/resource_compute_disk_test.go @@ -342,42 +342,6 @@ func TestAccComputeDisk_encryption(t *testing.T) { }) } -func TestAccComputeDisk_encryptionKMS(t *testing.T) { - t.Parallel() - - org := getTestOrgFromEnv(t) - pid := "tf-test-" + acctest.RandString(10) - billingAccount := getTestBillingAccountFromEnv(t) - diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - keyRingName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - keyName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - importID := fmt.Sprintf("%s/%s/%s", pid, "us-central1-a", diskName) - var disk compute.Disk - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckComputeDiskDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccComputeDisk_encryptionKMS(pid, pname, org, billingAccount, diskName, keyRingName, keyName), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeDiskExists( - "google_compute_disk.foobar", pid, &disk), - testAccCheckEncryptionKey( - "google_compute_disk.foobar", &disk), - ), - }, - resource.TestStep{ - ResourceName: "google_compute_disk.foobar", - ImportStateId: importID, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func TestAccComputeDisk_deleteDetach(t *testing.T) { t.Parallel() diff --git a/google/resource_compute_instance_template.go b/google/resource_compute_instance_template.go index 854616fd..b2687486 100644 --- a/google/resource_compute_instance_template.go +++ b/google/resource_compute_instance_template.go @@ -131,6 +131,23 @@ func resourceComputeInstanceTemplate() *schema.Resource { ForceNew: true, Computed: true, }, + + "disk_encryption_key": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_key_self_link": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkRelativePaths, + }, + }, + }, + }, }, }, }, @@ -500,6 +517,13 @@ func buildDisks(d *schema.ResourceData, config *Config) ([]*computeBeta.Attached disk.DeviceName = v.(string) } + if _, ok := d.GetOk(prefix + ".disk_encryption_key"); ok { + disk.DiskEncryptionKey = &computeBeta.CustomerEncryptionKey{} + if v, ok := d.GetOk(prefix + ".disk_encryption_key.0.kms_key_self_link"); ok { + disk.DiskEncryptionKey.KmsKeyName = v.(string) + } + } + if v, ok := d.GetOk(prefix + ".source"); ok { disk.Source = v.(string) } else { @@ -706,6 +730,14 @@ func flattenDisks(disks []*computeBeta.AttachedDisk, d *schema.ResourceData, def diskMap["disk_name"] = disk.InitializeParams.DiskName diskMap["disk_size_gb"] = disk.InitializeParams.DiskSizeGb } + + if disk.DiskEncryptionKey != nil { + encryption := make([]map[string]interface{}, 1) + encryption[0] = make(map[string]interface{}) + encryption[0]["kms_key_self_link"] = disk.DiskEncryptionKey.KmsKeyName + diskMap["disk_encryption_key"] = encryption + } + diskMap["auto_delete"] = disk.AutoDelete diskMap["boot"] = disk.Boot diskMap["device_name"] = disk.DeviceName diff --git a/google/resource_compute_instance_template_test.go b/google/resource_compute_instance_template_test.go index f15c36fb..6c1f177e 100644 --- a/google/resource_compute_instance_template_test.go +++ b/google/resource_compute_instance_template_test.go @@ -472,6 +472,38 @@ func TestAccComputeInstanceTemplate_minCpuPlatform(t *testing.T) { }) } +func TestAccComputeInstanceTemplate_EncryptKMS(t *testing.T) { + t.Parallel() + + var instanceTemplate compute.InstanceTemplate + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + billingAccount := getTestBillingAccountFromEnv(t) + diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + keyRingName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + keyName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceTemplate_encryptionKMS(pid, pname, org, billingAccount, diskName, keyRingName, keyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceTemplateExists("google_compute_instance_template.foobar", &instanceTemplate), + ), + }, + resource.TestStep{ + ResourceName: "google_compute_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckComputeInstanceTemplateDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -1390,3 +1422,87 @@ resource "google_compute_instance_template" "foobar" { min_cpu_platform = "%s" }`, i, DEFAULT_MIN_CPU_TEST_VALUE) } + +func testAccComputeInstanceTemplate_encryptionKMS(pid, pname, org, billing, diskName, keyRingName, keyName string) string { + return fmt.Sprintf(` +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" + billing_account = "%s" +} + +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_project_services" "apis" { + project = "${google_project.project.project_id}" + + services = [ + "oslogin.googleapis.com", + "compute.googleapis.com", + "cloudkms.googleapis.com", + "appengine.googleapis.com", + ] +} + +resource "google_project_iam_member" "kms-project-binding" { + project = "${google_project.project.project_id}" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + member = "serviceAccount:service-${google_project.project.number}@compute-system.iam.gserviceaccount.com" + + depends_on = ["google_project_services.apis"] +} + +resource "google_kms_crypto_key_iam_binding" "kms-key-binding" { + crypto_key_id = "${google_kms_crypto_key.my_crypto_key.self_link}" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:service-${google_project.project.number}@compute-system.iam.gserviceaccount.com", + ] + + depends_on = ["google_project_services.apis"] +} + +resource "google_kms_key_ring" "my_key_ring" { + name = "%s" + project = "${google_project.project.project_id}" + location = "us-central1" + + depends_on = ["google_project_services.apis"] +} + +resource "google_kms_crypto_key" "my_crypto_key" { + name = "%s" + key_ring = "${google_kms_key_ring.my_key_ring.self_link}" +} + + +resource "google_compute_instance_template" "foobar" { + name = "instancet-test-%s" + machine_type = "n1-standard-1" + can_ip_forward = false + + disk { + source_image = "${data.google_compute_image.my_image.self_link}" + disk_encryption_key { + kms_key_self_link = "${google_kms_crypto_key.my_crypto_key.self_link}" + } + } + + network_interface { + network = "default" + } + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } + + labels { + my_label = "foobar" + } +}`, pid, pname, org, billing, keyRingName, keyName, acctest.RandString(10)) +} diff --git a/website/docs/r/compute_instance_template.html.markdown b/website/docs/r/compute_instance_template.html.markdown index d5e7ab3a..e82dae7d 100644 --- a/website/docs/r/compute_instance_template.html.markdown +++ b/website/docs/r/compute_instance_template.html.markdown @@ -286,6 +286,20 @@ The `disk` block supports: * `type` - (Optional) The type of GCE disk, can be either `"SCRATCH"` or `"PERSISTENT"`. +* `disk_encryption_key` - (Optional) Encrypts or decrypts a disk using a customer-supplied encryption key. + + If you are creating a new disk, this field encrypts the new disk using an encryption key that you provide. If you are attaching an existing disk that is already encrypted, this field decrypts the disk using the customer-supplied encryption key. + + If you encrypt a disk using a customer-supplied key, you must provide the same key again when you attempt to use this resource at a later time. For example, you must provide the key when you create a snapshot or an image from the disk or when you attach the disk to a virtual machine instance. + + 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. + +The `disk_encryption_key` block supports: + +* `kms_key_self_link` - (Optional) The self link of the encryption key that is stored in Google Cloud KMS + The `network_interface` block supports: * `network` - (Optional) The name or self_link of the network to attach this interface to.