diff --git a/pkg/webhooks/machine_webhook.go b/pkg/webhooks/machine_webhook.go index 4b04ed283..e13712ae1 100644 --- a/pkg/webhooks/machine_webhook.go +++ b/pkg/webhooks/machine_webhook.go @@ -229,6 +229,10 @@ var gcpConfidentialTypeMachineSeriesSupportingSEV = []string{"n2d", "c2d", "c3d" var gcpConfidentialTypeMachineSeriesSupportingSEVSNP = []string{"n2d"} var gcpConfidentialTypeMachineSeriesSupportingTDX = []string{"c3"} +// GCP onHostMaintenance Migrate with Confidential Compute is supported only on certain series: +// reference: https://cloud.google.com/confidential-computing/confidential-vm/docs/troubleshoot-live-migration +var gcpConfidentialTypeMachineSeriesSupportingOnHostMaintenanceMigrate = []string{"n2d"} + // defaultInstanceTypeForCloudProvider returns the default instance type for the given cloud provider and architecture. // If the cloud provider is not supported, an empty string is returned. // If the architecture is not supported, the default instance type for AMD64 is returned as a fallback. @@ -1325,14 +1329,15 @@ func validateShieldedInstanceConfig(providerSpec *machinev1beta1.GCPMachineProvi func validateGCPConfidentialComputing(providerSpec *machinev1beta1.GCPMachineProviderSpec) field.ErrorList { var errs field.ErrorList if providerSpec.ConfidentialCompute != "" && providerSpec.ConfidentialCompute != machinev1beta1.ConfidentialComputePolicyDisabled { + // Get machine series + machineSeries := strings.Split(providerSpec.MachineType, "-")[0] // Check on host maintenance - if providerSpec.OnHostMaintenance != machinev1beta1.TerminateHostMaintenanceType { + if providerSpec.OnHostMaintenance != machinev1beta1.TerminateHostMaintenanceType && !slices.Contains(gcpConfidentialTypeMachineSeriesSupportingOnHostMaintenanceMigrate, machineSeries) { errs = append(errs, field.Invalid(field.NewPath("providerSpec", "onHostMaintenance"), providerSpec.OnHostMaintenance, fmt.Sprintf("ConfidentialCompute %s requires OnHostMaintenance to be set to %s, the current value is: %s", providerSpec.ConfidentialCompute, machinev1beta1.TerminateHostMaintenanceType, providerSpec.OnHostMaintenance))) } // Check machine series supports confidential computing - machineSeries := strings.Split(providerSpec.MachineType, "-")[0] switch providerSpec.ConfidentialCompute { case machinev1beta1.ConfidentialComputePolicyEnabled, machinev1beta1.ConfidentialComputePolicySEV: if !slices.Contains(gcpConfidentialTypeMachineSeriesSupportingSEV, machineSeries) { @@ -1348,6 +1353,12 @@ func validateGCPConfidentialComputing(providerSpec *machinev1beta1.GCPMachinePro fmt.Sprintf("ConfidentialCompute %s requires a machine type in the following series: %s", providerSpec.ConfidentialCompute, strings.Join(gcpConfidentialTypeMachineSeriesSupportingSEVSNP, `,`))), ) } + // Check on host maintenance for ConfidentialComputePolicySEVSNP + if providerSpec.OnHostMaintenance != machinev1beta1.TerminateHostMaintenanceType { + errs = append(errs, field.Invalid(field.NewPath("providerSpec", "onHostMaintenance"), + providerSpec.OnHostMaintenance, + fmt.Sprintf("ConfidentialCompute %s requires OnHostMaintenance to be set to %s, the current value is: %s", providerSpec.ConfidentialCompute, machinev1beta1.TerminateHostMaintenanceType, providerSpec.OnHostMaintenance))) + } case machinev1beta1.ConfidentialComputePolicyTDX: if !slices.Contains(gcpConfidentialTypeMachineSeriesSupportingTDX, machineSeries) { errs = append(errs, field.Invalid(field.NewPath("providerSpec", "machineType"), diff --git a/pkg/webhooks/machine_webhook_test.go b/pkg/webhooks/machine_webhook_test.go index 4a4b44413..965a42c5a 100644 --- a/pkg/webhooks/machine_webhook_test.go +++ b/pkg/webhooks/machine_webhook_test.go @@ -3934,13 +3934,23 @@ func TestValidateGCPProviderSpec(t *testing.T) { expectedError: "providerSpec.confidentialCompute: Invalid value: \"invalid-value\": ConfidentialCompute must be Enabled, Disabled, AMDEncryptedVirtualization, AMDEncryptedVirtualizationNestedPaging, or IntelTrustedDomainExtensions", }, { - testCase: "with ConfidentialCompute enabled while onHostMaintenance is set to Migrate", + testCase: "with ConfidentialCompute enabled while onHostMaintenance is set to Migrate on n2d instances", modifySpec: func(p *machinev1beta1.GCPMachineProviderSpec) { p.ConfidentialCompute = machinev1beta1.ConfidentialComputePolicyEnabled p.OnHostMaintenance = machinev1beta1.MigrateHostMaintenanceType p.MachineType = "n2d-standard-4" p.GPUs = []machinev1beta1.GCPGPUConfig{} }, + expectedOk: true, + }, + { + testCase: "with ConfidentialCompute enabled while onHostMaintenance is set to Migrate on non n2d instances (c2d)", + modifySpec: func(p *machinev1beta1.GCPMachineProviderSpec) { + p.ConfidentialCompute = machinev1beta1.ConfidentialComputePolicyEnabled + p.OnHostMaintenance = machinev1beta1.MigrateHostMaintenanceType + p.MachineType = "c2d-standard-4" + p.GPUs = []machinev1beta1.GCPGPUConfig{} + }, expectedOk: false, expectedError: "providerSpec.onHostMaintenance: Invalid value: \"Migrate\": ConfidentialCompute Enabled requires OnHostMaintenance to be set to Terminate, the current value is: Migrate", }, @@ -4006,7 +4016,7 @@ func TestValidateGCPProviderSpec(t *testing.T) { expectedError: "", }, { - testCase: "with ConfidentialCompute AMDEncryptedVirtualizationNestedPaging and onHostMaintenance set to Migrate", + testCase: "with ConfidentialCompute AMDEncryptedVirtualizationNestedPaging and onHostMaintenance set to Migrate on n2d instances", modifySpec: func(p *machinev1beta1.GCPMachineProviderSpec) { p.ConfidentialCompute = machinev1beta1.ConfidentialComputePolicySEVSNP p.OnHostMaintenance = machinev1beta1.MigrateHostMaintenanceType