Skip to content

Commit

Permalink
adding KMS key encryption to disks (GoogleCloudPlatform#569)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisst authored and modular-magician committed Oct 20, 2018
1 parent 7bf1036 commit 51f2020
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 15 deletions.
2 changes: 1 addition & 1 deletion build/terraform
2 changes: 1 addition & 1 deletion build/terraform-beta
30 changes: 30 additions & 0 deletions products/compute/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,12 @@ objects:
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
output: true
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
input: true
- !ruby/object:Api::Type::String
name: 'sourceImageId'
Expand Down Expand Up @@ -1702,6 +1708,12 @@ objects:
The RFC 4648 base64 encoded SHA-256 hash of the
customer-supplied encryption key that protects this resource.
output: true
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
# TODO(alexstephen): Change to ResourceRef with array support
- !ruby/object:Api::Type::Array
name: 'licenses'
Expand Down Expand Up @@ -1768,6 +1780,12 @@ objects:
The RFC 4648 base64 encoded SHA-256 hash of the
customer-supplied encryption key that protects this resource.
output: true
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
- !ruby/object:Api::Type::String
name: 'sourceDiskId'
description: |
Expand Down Expand Up @@ -2995,6 +3013,12 @@ objects:
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
output: true
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
input: true
- !ruby/object:Api::Type::NestedObject
name: 'sourceDiskEncryptionKey'
Expand All @@ -3014,6 +3038,12 @@ objects:
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
output: true
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
input: true
properties:
- !ruby/object:Api::Type::Time
Expand Down
12 changes: 12 additions & 0 deletions products/compute/disk_parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
output: true
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
input: true
- !ruby/object:Api::Type::ResourceRef
name: 'sourceSnapshot'
Expand All @@ -62,6 +68,12 @@
description: |
Specifies a 256-bit customer-supplied encryption key, encoded in
RFC 4648 base64 to either encrypt or decrypt this resource.
- !ruby/object:Api::Type::String
# TODO(chrisst) Change to ResourceRef once KMS is in Magic Modules
name: 'kmsKeyName'
min_version: beta
description: |
The name of the encryption key that is stored in Google Cloud KMS.
- !ruby/object:Api::Type::String
name: 'sha256'
description: |
Expand Down
24 changes: 24 additions & 0 deletions products/compute/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,30 @@ overrides: !ruby/object:Provider::ResourceOverrides
override_order: -1
name: image
diff_suppress_func: 'diskImageDiffSuppress'
diskEncryptionKey.kmsKeyName: !ruby/object:Provider::Terraform::PropertyOverride
diff_suppress_func: 'compareSelfLinkRelativePaths'
name: "kmsKeySelfLink"
description: |
The self link of the encryption key used to encrypt the disk. Also called KmsKeyName
in the cloud console. In order to use this additional
IAM permissions need to be set on the Compute Engine Service Agent. See
https://cloud.google.com/compute/docs/disks/customer-managed-encryption#encrypt_a_new_persistent_disk_with_your_own_keys
sourceSnapshotEncryptionKey.kmsKeyName: !ruby/object:Provider::Terraform::PropertyOverride
diff_suppress_func: 'compareSelfLinkRelativePaths'
name: "kmsKeySelfLink"
description: |
The self link of the encryption key used to encrypt the disk. Also called KmsKeyName
in the cloud console. In order to use this additional
IAM permissions need to be set on the Compute Engine Service Agent. See
https://cloud.google.com/compute/docs/disks/customer-managed-encryption#encrypt_a_new_persistent_disk_with_your_own_keys
sourceImageEncryptionKey.kmsKeyName: !ruby/object:Provider::Terraform::PropertyOverride
diff_suppress_func: 'compareSelfLinkRelativePaths'
name: "kmsKeySelfLink"
description: |
The self link of the encryption key used to encrypt the disk. Also called KmsKeyName
in the cloud console. In order to use this additional
IAM permissions need to be set on the Compute Engine Service Agent. See
https://cloud.google.com/compute/docs/disks/customer-managed-encryption#encrypt_a_new_persistent_disk_with_your_own_keys
image: !ruby/object:Provider::Terraform::PropertyOverride
override_order: 5
description: |
Expand Down
140 changes: 127 additions & 13 deletions provider/terraform/tests/resource_compute_disk_test.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func TestAccComputeDisk_basic(t *testing.T) {
Config: testAccComputeDisk_basic(diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foobar", &disk),
"google_compute_disk.foobar", getTestProjectFromEnv(), &disk),
testAccCheckComputeDiskHasLabel(&disk, "my-label", "my-label-value"),
testAccCheckComputeDiskHasLabelFingerprint(&disk, "google_compute_disk.foobar"),
),
Expand Down Expand Up @@ -265,7 +265,7 @@ func TestAccComputeDisk_update(t *testing.T) {
Config: testAccComputeDisk_basic(diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foobar", &disk),
"google_compute_disk.foobar", getTestProjectFromEnv(), &disk),
resource.TestCheckResourceAttr("google_compute_disk.foobar", "size", "50"),
testAccCheckComputeDiskHasLabel(&disk, "my-label", "my-label-value"),
testAccCheckComputeDiskHasLabelFingerprint(&disk, "google_compute_disk.foobar"),
Expand All @@ -275,7 +275,7 @@ func TestAccComputeDisk_update(t *testing.T) {
Config: testAccComputeDisk_updated(diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foobar", &disk),
"google_compute_disk.foobar", getTestProjectFromEnv(), &disk),
resource.TestCheckResourceAttr("google_compute_disk.foobar", "size", "100"),
testAccCheckComputeDiskHasLabel(&disk, "my-label", "my-updated-label-value"),
testAccCheckComputeDiskHasLabel(&disk, "a-new-label", "a-new-label-value"),
Expand Down Expand Up @@ -305,14 +305,14 @@ func TestAccComputeDisk_fromSnapshot(t *testing.T) {
Config: testAccComputeDisk_fromSnapshot(projectName, firstDiskName, snapshotName, diskName, "self_link"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.seconddisk", &disk),
"google_compute_disk.seconddisk", getTestProjectFromEnv(), &disk),
),
},
resource.TestStep{
Config: testAccComputeDisk_fromSnapshot(projectName, firstDiskName, snapshotName, diskName, "name"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.seconddisk", &disk),
"google_compute_disk.seconddisk", getTestProjectFromEnv(), &disk),
),
},
},
Expand All @@ -334,14 +334,52 @@ func TestAccComputeDisk_encryption(t *testing.T) {
Config: testAccComputeDisk_encryption(diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foobar", getTestProjectFromEnv(), &disk),
testAccCheckEncryptionKey(
"google_compute_disk.foobar", &disk),
),
},
},
})
}

<% unless version.nil? || version == 'beta' -%>
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,
},
},
})
}
<% end -%>

func TestAccComputeDisk_deleteDetach(t *testing.T) {
t.Parallel()
Expand All @@ -359,7 +397,7 @@ func TestAccComputeDisk_deleteDetach(t *testing.T) {
Config: testAccComputeDisk_deleteDetach(instanceName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foo", &disk),
"google_compute_disk.foo", getTestProjectFromEnv(), &disk),
),
},
// this needs to be a second step so we refresh and see the instance
Expand All @@ -370,7 +408,7 @@ func TestAccComputeDisk_deleteDetach(t *testing.T) {
Config: testAccComputeDisk_deleteDetach(instanceName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foo", &disk),
"google_compute_disk.foo", getTestProjectFromEnv(), &disk),
testAccCheckComputeDiskInstances(
"google_compute_disk.foo", &disk),
),
Expand All @@ -396,7 +434,7 @@ func TestAccComputeDisk_deleteDetachIGM(t *testing.T) {
Config: testAccComputeDisk_deleteDetachIGM(diskName, mgrName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foo", &disk),
"google_compute_disk.foo", getTestProjectFromEnv(), &disk),
),
},
// this needs to be a second step so we refresh and see the instance
Expand All @@ -407,7 +445,7 @@ func TestAccComputeDisk_deleteDetachIGM(t *testing.T) {
Config: testAccComputeDisk_deleteDetachIGM(diskName, mgrName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foo", &disk),
"google_compute_disk.foo", getTestProjectFromEnv(), &disk),
testAccCheckComputeDiskInstances(
"google_compute_disk.foo", &disk),
),
Expand All @@ -417,15 +455,15 @@ func TestAccComputeDisk_deleteDetachIGM(t *testing.T) {
Config: testAccComputeDisk_deleteDetachIGM(diskName2, mgrName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foo", &disk),
"google_compute_disk.foo", getTestProjectFromEnv(), &disk),
),
},
// Add the extra step like before
resource.TestStep{
Config: testAccComputeDisk_deleteDetachIGM(diskName2, mgrName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeDiskExists(
"google_compute_disk.foo", &disk),
"google_compute_disk.foo", getTestProjectFromEnv(), &disk),
testAccCheckComputeDiskInstances(
"google_compute_disk.foo", &disk),
),
Expand Down Expand Up @@ -484,9 +522,8 @@ func testAccCheckComputeDiskDestroy(s *terraform.State) error {
return nil
}

func testAccCheckComputeDiskExists(n string, disk *compute.Disk) resource.TestCheckFunc {
func testAccCheckComputeDiskExists(n, p string, disk *compute.Disk) resource.TestCheckFunc {
return func(s *terraform.State) error {
p := getTestProjectFromEnv()
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
Expand Down Expand Up @@ -694,6 +731,83 @@ resource "google_compute_disk" "foobar" {
}`, diskName)
}

func testAccComputeDisk_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_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
project = "${google_project.project.project_id}"

disk_encryption_key {
kms_key_self_link = "${google_kms_crypto_key.my_crypto_key.self_link}"
}

depends_on = [
"google_kms_crypto_key_iam_binding.kms-key-binding",
"google_project_iam_member.kms-project-binding",
]
}
`, pid, pname, org, billing, keyRingName, keyName, diskName)
}

func testAccComputeDisk_deleteDetach(instanceName, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
Expand Down
Loading

0 comments on commit 51f2020

Please sign in to comment.