diff --git a/examples/instance_template/confidential_computing/main.tf b/examples/instance_template/confidential_computing/main.tf new file mode 100644 index 00000000..9dba4505 --- /dev/null +++ b/examples/instance_template/confidential_computing/main.tf @@ -0,0 +1,32 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module "instance_template" { + source = "../../../modules/instance_template" + + region = var.region + project_id = var.project_id + service_account = var.service_account + subnetwork = var.subnetwork + + name_prefix = "confidential-template" + source_image_project = "ubuntu-os-cloud" + source_image = "ubuntu-2004-lts" + machine_type = "n2d-standard-2" + min_cpu_platform = "AMD Milan" + enable_confidential_vm = true + confidential_instance_type = "SEV" +} diff --git a/examples/instance_template/confidential_computing/outputs.tf b/examples/instance_template/confidential_computing/outputs.tf new file mode 100644 index 00000000..4f405c44 --- /dev/null +++ b/examples/instance_template/confidential_computing/outputs.tf @@ -0,0 +1,26 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +output "self_link" { + description = "Self-link to the instance template." + value = module.instance_template.self_link +} + +output "name" { + description = "Name of the instance templates." + value = module.instance_template.name +} diff --git a/examples/instance_template/confidential_computing/variables.tf b/examples/instance_template/confidential_computing/variables.tf new file mode 100644 index 00000000..ea9b5990 --- /dev/null +++ b/examples/instance_template/confidential_computing/variables.tf @@ -0,0 +1,40 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + description = "The Google Cloud project ID." + type = string +} + +variable "region" { + description = "The GCP region to create and test resources in." + type = string + default = "us-central1" +} + +variable "subnetwork" { + description = "The subnetwork selflink to host the compute instances in." + type = string +} + +variable "service_account" { + description = "Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account." + type = object({ + email = string, + scopes = set(string) + }) + default = null +} diff --git a/metadata.yaml b/metadata.yaml index 20a33f59..23332753 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -48,6 +48,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/modules/compute_disk_snapshot/metadata.yaml b/modules/compute_disk_snapshot/metadata.yaml index 4b36f6cc..b536f0eb 100644 --- a/modules/compute_disk_snapshot/metadata.yaml +++ b/modules/compute_disk_snapshot/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/modules/compute_instance/metadata.yaml b/modules/compute_instance/metadata.yaml index 8682c855..f8002ab7 100644 --- a/modules/compute_instance/metadata.yaml +++ b/modules/compute_instance/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/modules/instance_template/README.md b/modules/instance_template/README.md index 1d8045e8..ea16fde5 100644 --- a/modules/instance_template/README.md +++ b/modules/instance_template/README.md @@ -20,6 +20,7 @@ See the [simple](../../examples/instance_template/simple) for a usage example. | auto\_delete | Whether or not the boot disk should be auto-deleted | `string` | `"true"` | no | | automatic\_restart | (Optional) Specifies whether the instance should be automatically restarted if it is terminated by Compute Engine (not terminated by a user). | `bool` | `true` | no | | can\_ip\_forward | Enable IP forwarding, for NAT instances for example | `string` | `"false"` | no | +| confidential\_instance\_type | Defines the confidential computing technology the instance uses. If this is set to "SEV\_SNP", var.min\_cpu\_platform will be automatically set to "AMD Milan". See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#confidential_instance_type. | `string` | `null` | no | | description | The template's description | `string` | `""` | no | | disk\_encryption\_key | The id of the encryption key that is stored in Google Cloud KMS to use to encrypt all the disks on this instance | `string` | `null` | no | | disk\_labels | Labels to be assigned to boot disk, provided as a map | `map(string)` | `{}` | no | diff --git a/modules/instance_template/main.tf b/modules/instance_template/main.tf index 9971fd61..5c5917bb 100644 --- a/modules/instance_template/main.tf +++ b/modules/instance_template/main.tf @@ -43,13 +43,18 @@ locals { # initialize the block only if it is enabled. shielded_vm_configs = var.enable_shielded_vm ? [true] : [] - gpu_enabled = var.gpu != null - alias_ip_range_enabled = var.alias_ip_range != null + gpu_enabled = var.gpu != null + alias_ip_range_enabled = var.alias_ip_range != null + confidential_terminate_condition = var.enable_confidential_vm && (var.confidential_instance_type != "SEV" || var.min_cpu_platform != "AMD Milan") on_host_maintenance = ( - var.preemptible || var.enable_confidential_vm || local.gpu_enabled || var.spot + var.preemptible || local.gpu_enabled || var.spot || local.confidential_terminate_condition ? "TERMINATE" : var.on_host_maintenance ) + + # must be set to "AMD Milan" if confidential_instance_type is set to "SEV_SNP", or this will fail to create the VM. + min_cpu_platform = var.confidential_instance_type == "SEV_SNP" ? "AMD Milan" : var.min_cpu_platform + automatic_restart = ( # must be false when preemptible or spot is true var.preemptible || var.spot ? false : var.automatic_restart @@ -76,7 +81,7 @@ resource "google_compute_instance_template" "tpl" { can_ip_forward = var.can_ip_forward metadata_startup_script = var.startup_script region = var.region - min_cpu_platform = var.min_cpu_platform + min_cpu_platform = local.min_cpu_platform resource_policies = var.resource_policies dynamic "disk" { for_each = local.all_disks @@ -204,6 +209,7 @@ resource "google_compute_instance_template" "tpl" { confidential_instance_config { enable_confidential_compute = var.enable_confidential_vm + confidential_instance_type = var.confidential_instance_type } network_performance_config { diff --git a/modules/instance_template/metadata.yaml b/modules/instance_template/metadata.yaml index 6141ce76..4dd52c84 100644 --- a/modules/instance_template/metadata.yaml +++ b/modules/instance_template/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks @@ -146,6 +148,9 @@ spec: description: Enable IP forwarding, for NAT instances for example varType: string defaultValue: "false" + - name: confidential_instance_type + description: Defines the confidential computing technology the instance uses. If this is set to "SEV_SNP", var.min_cpu_platform will be automatically set to "AMD Milan". See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#confidential_instance_type. + varType: string - name: description description: The template's description varType: string diff --git a/modules/instance_template/variables.tf b/modules/instance_template/variables.tf index 45528f68..5fe65be0 100644 --- a/modules/instance_template/variables.tf +++ b/modules/instance_template/variables.tf @@ -365,6 +365,12 @@ variable "enable_confidential_vm" { description = "Whether to enable the Confidential VM configuration on the instance. Note that the instance image must support Confidential VMs. See https://cloud.google.com/compute/docs/images" } +variable "confidential_instance_type" { + type = string + default = null + description = "Defines the confidential computing technology the instance uses. If this is set to \"SEV_SNP\", var.min_cpu_platform will be automatically set to \"AMD Milan\". See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#confidential_instance_type." +} + ########################### # Public IP ########################### diff --git a/modules/instance_template/versions.tf b/modules/instance_template/versions.tf index eac8c416..319a1fbd 100644 --- a/modules/instance_template/versions.tf +++ b/modules/instance_template/versions.tf @@ -19,7 +19,7 @@ terraform { required_providers { google-beta = { source = "hashicorp/google-beta" - version = ">= 5.5, < 6" + version = ">= 5.36, < 6" } } provider_meta "google" { diff --git a/modules/mig/metadata.yaml b/modules/mig/metadata.yaml index 31fd6d7a..fbecdc82 100644 --- a/modules/mig/metadata.yaml +++ b/modules/mig/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/modules/mig_with_percent/metadata.yaml b/modules/mig_with_percent/metadata.yaml index ba7e9b66..9baa487d 100644 --- a/modules/mig_with_percent/metadata.yaml +++ b/modules/mig_with_percent/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/modules/preemptible_and_regular_instance_templates/metadata.yaml b/modules/preemptible_and_regular_instance_templates/metadata.yaml index b642b32e..ede089cd 100644 --- a/modules/preemptible_and_regular_instance_templates/metadata.yaml +++ b/modules/preemptible_and_regular_instance_templates/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/modules/umig/metadata.yaml b/modules/umig/metadata.yaml index b74b16c5..588ac192 100644 --- a/modules/umig/metadata.yaml +++ b/modules/umig/metadata.yaml @@ -38,6 +38,8 @@ spec: location: examples/instance_template/alias_ip_range - name: autoscaler location: examples/mig/autoscaler + - name: confidential_computing + location: examples/instance_template/confidential_computing - name: disk_snapshot location: examples/compute_instance/disk_snapshot - name: encrypted_disks diff --git a/test/fixtures/confidential_instance_template/main.tf b/test/fixtures/confidential_instance_template/main.tf new file mode 100644 index 00000000..ee4c7c60 --- /dev/null +++ b/test/fixtures/confidential_instance_template/main.tf @@ -0,0 +1,23 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module "confidential_simple" { + source = "../../../examples/instance_template/confidential_computing" + project_id = var.project_id + region = "us-central1" + subnetwork = google_compute_subnetwork.main.self_link + service_account = var.service_account +} diff --git a/test/fixtures/confidential_instance_template/network.tf b/test/fixtures/confidential_instance_template/network.tf new file mode 120000 index 00000000..98e7464a --- /dev/null +++ b/test/fixtures/confidential_instance_template/network.tf @@ -0,0 +1 @@ +../shared/network.tf \ No newline at end of file diff --git a/test/fixtures/confidential_instance_template/outputs.tf b/test/fixtures/confidential_instance_template/outputs.tf new file mode 100644 index 00000000..0d3686b7 --- /dev/null +++ b/test/fixtures/confidential_instance_template/outputs.tf @@ -0,0 +1,35 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "self_link" { + description = "Self-link to the instance template." + value = module.confidential_simple.self_link +} + +output "name" { + description = "Name of the instance templates." + value = module.confidential_simple.name +} + +output "project_id" { + description = "The GCP project to use for integration tests." + value = var.project_id +} + +output "service_account" { + description = "Service account to attach to the instance" + value = var.service_account +} diff --git a/test/fixtures/confidential_instance_template/variables.tf b/test/fixtures/confidential_instance_template/variables.tf new file mode 100644 index 00000000..f74bdc25 --- /dev/null +++ b/test/fixtures/confidential_instance_template/variables.tf @@ -0,0 +1,29 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + description = "The GCP project to use for integration tests." + type = string +} + +variable "service_account" { + description = "Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account." + type = object({ + email = string + scopes = list(string) + }) + default = null +} diff --git a/test/fixtures/confidential_instance_template/versions.tf b/test/fixtures/confidential_instance_template/versions.tf new file mode 100644 index 00000000..940b48d4 --- /dev/null +++ b/test/fixtures/confidential_instance_template/versions.tf @@ -0,0 +1,19 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">=0.13" +} diff --git a/test/integration/confidential_instance_template/confidential_instance_template_test.go b/test/integration/confidential_instance_template/confidential_instance_template_test.go new file mode 100644 index 00000000..adfdf66a --- /dev/null +++ b/test/integration/confidential_instance_template/confidential_instance_template_test.go @@ -0,0 +1,43 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package confidential_instance_template + +import ( + "fmt" + "testing" + + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" + "github.com/stretchr/testify/assert" +) + +func TestConfidentialInstanceTemplate(t *testing.T) { + const instanceNamePrefix = "confidential-template" + + confInsTempl := tft.NewTFBlueprintTest(t) + confInsTempl.DefineVerify(func(assert *assert.Assertions) { + confInsTempl.DefaultVerify(assert) + + instance_template := gcloud.Run(t, fmt.Sprintf("compute instance-templates list --format=json --project %s --filter name~%s", confInsTempl.GetStringOutput("project_id"), instanceNamePrefix)) + + assert.Len(instance_template.Array(), 1) + instanceConfigProperties := instance_template.Array()[0].Get("properties") + confidentialInstanceConfig := instanceConfigProperties.Get("confidentialInstanceConfig") + assert.True(confidentialInstanceConfig.Get("enableConfidentialCompute").Bool()) + assert.Equal("SEV", confidentialInstanceConfig.Get("confidentialInstanceType").String()) + assert.Equal("MIGRATE", instanceConfigProperties.Get("scheduling").Get("onHostMaintenance").String()) + }) + confInsTempl.Test() +}