Skip to content

Commit eda843c

Browse files
Add source_machine_image_encryption_key to google_compute_instance_from_machine_image resource (#12943) (#9632)
[upstream:0d24752a661a63a3a13c5fa8aee5d09d448fcb84] Signed-off-by: Modular Magician <[email protected]>
1 parent 6e82e08 commit eda843c

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

Diff for: .changelog/12943.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
compute: added `source_machine_image_encryption_key` field to `google_compute_instance_from_machine_image` resource
3+
```

Diff for: google-beta/services/compute/resource_compute_instance_from_machine_image.go

+104
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,43 @@ func computeInstanceFromMachineImageSchema() map[string]*schema.Schema {
6262
Description: `Name or self link of a machine image to create the instance from on.`,
6363
}
6464

65+
s["source_machine_image_encryption_key"] = &schema.Schema{
66+
Type: schema.TypeList,
67+
Optional: true,
68+
MaxItems: 1,
69+
Description: `Encryption key for the source machine image.`,
70+
ForceNew: true,
71+
Elem: &schema.Resource{
72+
Schema: map[string]*schema.Schema{
73+
"raw_key": {
74+
Type: schema.TypeString,
75+
Optional: true,
76+
Sensitive: true,
77+
},
78+
"rsa_encrypted_key": {
79+
Type: schema.TypeString,
80+
Optional: true,
81+
Sensitive: true,
82+
ForceNew: true,
83+
},
84+
"kms_key_name": {
85+
Type: schema.TypeString,
86+
Optional: true,
87+
ForceNew: true,
88+
},
89+
"kms_key_service_account": {
90+
Type: schema.TypeString,
91+
Optional: true,
92+
ForceNew: true,
93+
},
94+
"sha256": {
95+
Type: schema.TypeString,
96+
Computed: true,
97+
},
98+
},
99+
},
100+
}
101+
65102
// Modifying the schema to disable disk overrides, due to an API bug (b/170964971)
66103
// TODO: (camthornton) Remove this when disk override functionality in the API is restored
67104
for _, field := range []string{"boot_disk", "attached_disk", "scratch_disk"} {
@@ -126,6 +163,11 @@ func resourceComputeInstanceFromMachineImageCreate(d *schema.ResourceData, meta
126163
src := d.Get("source_machine_image").(string)
127164
instance.SourceMachineImage = src
128165

166+
// Add source machine image encryption key if specified
167+
if encryptionKey := expandSourceMachineImageEncryptionKey(d); encryptionKey != nil {
168+
instance.SourceMachineImageEncryptionKey = encryptionKey
169+
}
170+
129171
tpl, err := tpgresource.ParseMachineImageFieldValue(src, d, config)
130172
if err != nil {
131173
return err
@@ -264,3 +306,65 @@ func adjustInstanceFromMachineImageDisks(d *schema.ResourceData, config *transpo
264306

265307
return disks, nil
266308
}
309+
310+
func expandSourceMachineImageEncryptionKey(d tpgresource.TerraformResourceData) *compute.CustomerEncryptionKey {
311+
if v, ok := d.GetOk("source_machine_image_encryption_key"); !ok || v == nil {
312+
return nil
313+
}
314+
315+
encryptionKeyList := d.Get("source_machine_image_encryption_key").([]interface{})
316+
if len(encryptionKeyList) == 0 || encryptionKeyList[0] == nil {
317+
return nil
318+
}
319+
320+
encryptionKeyMap := encryptionKeyList[0].(map[string]interface{})
321+
encryptionKey := &compute.CustomerEncryptionKey{}
322+
323+
if rawKey, ok := encryptionKeyMap["raw_key"]; ok && rawKey != "" {
324+
encryptionKey.RawKey = rawKey.(string)
325+
}
326+
327+
if rsaKey, ok := encryptionKeyMap["rsa_encrypted_key"]; ok && rsaKey != "" {
328+
encryptionKey.RsaEncryptedKey = rsaKey.(string)
329+
}
330+
331+
if kmsKey, ok := encryptionKeyMap["kms_key_name"]; ok && kmsKey != "" {
332+
encryptionKey.KmsKeyName = kmsKey.(string)
333+
}
334+
335+
if kmsKeyServiceAccount, ok := encryptionKeyMap["kms_key_service_account"]; ok && kmsKeyServiceAccount != "" {
336+
encryptionKey.KmsKeyServiceAccount = kmsKeyServiceAccount.(string)
337+
}
338+
339+
return encryptionKey
340+
}
341+
342+
func flattenSourceMachineImageEncryptionKey(key *compute.CustomerEncryptionKey) []map[string]interface{} {
343+
if key == nil {
344+
return nil
345+
}
346+
347+
m := map[string]interface{}{}
348+
349+
if key.RawKey != "" {
350+
m["raw_key"] = key.RawKey
351+
}
352+
353+
if key.RsaEncryptedKey != "" {
354+
m["rsa_encrypted_key"] = key.RsaEncryptedKey
355+
}
356+
357+
if key.KmsKeyName != "" {
358+
m["kms_key_name"] = key.KmsKeyName
359+
}
360+
361+
if key.KmsKeyServiceAccount != "" {
362+
m["kms_key_service_account"] = key.KmsKeyServiceAccount
363+
}
364+
365+
if key.Sha256 != "" {
366+
m["sha256"] = key.Sha256
367+
}
368+
369+
return []map[string]interface{}{m}
370+
}

Diff for: google-beta/services/compute/resource_compute_instance_from_machine_image_test.go

+115
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,36 @@ func TestAccComputeInstanceFromMachineImage_confidentialInstanceConfigMain(t *te
305305
})
306306
}
307307

308+
func TestAccComputeInstanceFromMachineImage_withSourceMachineImageEncryptionKey(t *testing.T) {
309+
t.Parallel()
310+
311+
var instance compute.Instance
312+
var instanceName = fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
313+
var resourceName = "google_compute_instance_from_machine_image.foobar"
314+
var machineImageName = fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
315+
bootDiskID := "tf-instance-from-mi-test-disk"
316+
serviceAccountEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", "tf-test-sa", envvar.GetTestProjectFromEnv())
317+
keyRingSuffix := acctest.RandString(t, 10)
318+
keyNameSuffix := acctest.RandString(t, 10)
319+
320+
acctest.VcrTest(t, resource.TestCase{
321+
PreCheck: func() { acctest.AccTestPreCheck(t) },
322+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
323+
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
324+
Steps: []resource.TestStep{
325+
{
326+
Config: testAccComputeInstanceFromMachineImage_withSourceMachineImageEncryptionKey(instanceName, machineImageName, bootDiskID, serviceAccountEmail, keyRingSuffix, keyNameSuffix),
327+
Check: resource.ComposeTestCheckFunc(
328+
testAccCheckComputeInstanceExists(t, resourceName, &instance),
329+
resource.TestCheckResourceAttr(resourceName,
330+
"source_machine_image_encryption_key.0.kms_key_name",
331+
fmt.Sprintf("projects/%s/locations/global/keyRings/tf-test-keyring-%s/cryptoKeys/tf-test-key-%s", envvar.GetTestProjectFromEnv(), keyRingSuffix, keyNameSuffix)),
332+
),
333+
},
334+
},
335+
})
336+
}
337+
308338
func testAccCheckComputeInstanceFromMachineImageDestroyProducer(t *testing.T) func(s *terraform.State) error {
309339
return func(s *terraform.State) error {
310340
config := acctest.GoogleProviderConfig(t)
@@ -1104,3 +1134,88 @@ resource "google_compute_instance_from_machine_image" "foobar" {
11041134
}
11051135
`, projectID, projectID, org, billingId, instance, instance, newInstance)
11061136
}
1137+
1138+
func testAccComputeInstanceFromMachineImage_withSourceMachineImageEncryptionKey(instanceName, machineImageName, bootDiskID, serviceAccountEmail, keyRingSuffix, keyNameSuffix string) string {
1139+
return fmt.Sprintf(`
1140+
data "google_compute_image" "my_image" {
1141+
family = "debian-11"
1142+
project = "debian-cloud"
1143+
}
1144+
1145+
resource "google_service_account" "test_service_account" {
1146+
account_id = "tf-test-sa"
1147+
display_name = "Test Service Account"
1148+
}
1149+
1150+
resource "google_kms_key_ring" "keyring" {
1151+
name = "tf-test-keyring-%s"
1152+
location = "global"
1153+
}
1154+
1155+
resource "google_kms_crypto_key" "key" {
1156+
name = "tf-test-key-%s"
1157+
key_ring = google_kms_key_ring.keyring.id
1158+
1159+
lifecycle {
1160+
prevent_destroy = false
1161+
}
1162+
}
1163+
1164+
resource "google_kms_crypto_key_iam_member" "crypto_key" {
1165+
crypto_key_id = google_kms_crypto_key.key.id
1166+
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
1167+
member = "serviceAccount:${google_service_account.test_service_account.email}"
1168+
}
1169+
1170+
resource "google_compute_machine_image" "foobar" {
1171+
name = "%s"
1172+
source_instance = google_compute_instance.mi-source.id
1173+
machine_image_encryption_key {
1174+
kms_key_name = google_kms_crypto_key.key.id
1175+
kms_key_service_account = google_service_account.test_service_account.email
1176+
}
1177+
}
1178+
1179+
resource "google_compute_instance" "mi-source" {
1180+
name = "%s-source"
1181+
machine_type = "e2-medium"
1182+
zone = "us-central1-a"
1183+
1184+
boot_disk {
1185+
initialize_params {
1186+
image = data.google_compute_image.my_image.self_link
1187+
}
1188+
}
1189+
1190+
network_interface {
1191+
network = "default"
1192+
}
1193+
1194+
service_account {
1195+
email = google_service_account.test_service_account.email
1196+
scopes = ["cloud-platform"]
1197+
}
1198+
1199+
scheduling {
1200+
automatic_restart = true
1201+
}
1202+
}
1203+
1204+
resource "google_compute_instance_from_machine_image" "foobar" {
1205+
name = "%s"
1206+
zone = "us-central1-a"
1207+
1208+
source_machine_image = google_compute_machine_image.foobar.self_link
1209+
1210+
source_machine_image_encryption_key {
1211+
kms_key_name = google_kms_crypto_key.key.id
1212+
kms_key_service_account = google_service_account.test_service_account.email
1213+
}
1214+
1215+
service_account {
1216+
email = google_service_account.test_service_account.email
1217+
scopes = ["cloud-platform"]
1218+
}
1219+
}
1220+
`, keyRingSuffix, keyNameSuffix, machineImageName, instanceName, instanceName)
1221+
}

0 commit comments

Comments
 (0)