Skip to content

Commit

Permalink
Support SEV_SNP instance type configuration
Browse files Browse the repository at this point in the history
Only SEV machines could be configured by using the former
confidentialCompute Enabled/Disabled. GCP allows now to also configure
the confidential instance type as well by using the appropriate
parameter, see [0].

This commit introduces confidentialInstanceType, which lets users choose
between sev or sev-snp as their confidential computing technology of
choice.

The reason confidentialInstanceType will preceed confidentialCompute is
to mimic GCP's behavior, and ensuring backwards compatibility.

Meanwhile, add c3d as a machine that supports AMD SEV.

[0] https://cloud.google.com/confidential-computing/confidential-vm/docs/create-a-confidential-vm-instance#rest
  • Loading branch information
bgartzi committed Jan 30, 2025
1 parent f24b413 commit ff8cf8e
Show file tree
Hide file tree
Showing 9 changed files with 426 additions and 4 deletions.
31 changes: 29 additions & 2 deletions api/v1beta1/gcpmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,22 @@ const (
ConfidentialComputePolicyDisabled ConfidentialComputePolicy = "Disabled"
)

// Confidential VM supports Compute Engine machine types in the following series:
// ConfidentialVMTechnology represents the confidential computing technology used by a GCP confidential machine.
type ConfidentialVMTechnology string

const (
// ConfidentialVMTechnologySEV sets AMD SEV as the VM instance's confidential computing technology of choice.
ConfidentialVMTechnologySEV ConfidentialVMTechnology = "sev"
// ConfidentialVMTechnologySEVSNP sets AMD SEV-SNP as the VM instance's confidential computing technology of choice.
ConfidentialVMTechnologySEVSNP ConfidentialVMTechnology = "sev-snp"
)

// Confidential VM Technology support depends on the configured machine types.
// reference: https://cloud.google.com/compute/confidential-vm/docs/os-and-machine-type#machine-type
var confidentialComputeSupportedMachineSeries = []string{"n2d", "c2d"}
var (
confidentialMachineSeriesSupportingSev = []string{"n2d", "c2d", "c3d"}
confidentialMachineSeriesSupportingSevsnp = []string{"n2d"}
)

// HostMaintenancePolicy represents the desired behavior ase of a host maintenance event.
type HostMaintenancePolicy string
Expand Down Expand Up @@ -343,6 +356,20 @@ type GCPMachineSpec struct {
// +optional
ConfidentialCompute *ConfidentialComputePolicy `json:"confidentialCompute,omitempty"`

// ConfidentialInstanceType determines the required type of confidential computing technology.
// To set a ConfidentialInstanceType ConfidentialCompute must be first set to "Enabled".
// If ConfidentialCompute is "Enabled" and ConfidentialInstanceType isn't provided, the default ConfidentialInstanceType will be set. At this moment, the default for this case is "sev".
// If ConfidentialCompute is "Enabled" and ConfidentialInstanceType is provided, the provided ConfidentialInstanceType will be set.
// If ConfidentialCompute is "Disabled" and ConfidentialInstanceType isn't provided, confidential computing technology won't be enabled and the instance will be run normally.
// Setting ConfidentialCompute to "Disabled" and ConfidentialInstanceType to a valid value isn't supported. That will raise an error.
// Valid ConfidentialInstanceType values are "sev" and "sev-snp".
// Note that supported ConfidentialInstanceType values will depend on the configured instance machine types.
// "sev" is supported in "n2d", "c2d" and "c3d" machines.
// "sev-snp" is supported in "n2d" machines.
// +kubebuilder:validation:Enum=sev;sev-snp;
// +optional
ConfidentialInstanceType *ConfidentialVMTechnology `json:"confidentialInstanceType,omitempty"`

// RootDiskEncryptionKey defines the KMS key to be used to encrypt the root disk.
// +optional
RootDiskEncryptionKey *CustomerEncryptionKey `json:"rootDiskEncryptionKey,omitempty"`
Expand Down
21 changes: 19 additions & 2 deletions api/v1beta1/gcpmachine_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,26 @@ func validateConfidentialCompute(spec GCPMachineSpec) error {
}

machineSeries := strings.Split(spec.InstanceType, "-")[0]
if !slices.Contains(confidentialComputeSupportedMachineSeries, machineSeries) {
return fmt.Errorf("ConfidentialCompute require instance type in the following series: %s", confidentialComputeSupportedMachineSeries)
if spec.ConfidentialInstanceType == nil || *spec.ConfidentialInstanceType == "" {
if !slices.Contains(confidentialMachineSeriesSupportingSev, machineSeries) {
return fmt.Errorf("ConfidentialCompute requires any of the following machine series: %s. %s was found instead", strings.Join(confidentialMachineSeriesSupportingSev, ", "), spec.InstanceType)
}
} else {
switch *spec.ConfidentialInstanceType {
case ConfidentialVMTechnologySEV:
if !slices.Contains(confidentialMachineSeriesSupportingSev, machineSeries) {
return fmt.Errorf("ConfidentialInstanceType %s requires any of the following machine series: %s. %s was found instead", *spec.ConfidentialInstanceType, strings.Join(confidentialMachineSeriesSupportingSev, ", "), spec.InstanceType)
}
case ConfidentialVMTechnologySEVSNP:
if !slices.Contains(confidentialMachineSeriesSupportingSevsnp, machineSeries) {
return fmt.Errorf("ConfidentialInstanceType %s requires any of the following machine series: %s. %s was found instead", *spec.ConfidentialInstanceType, strings.Join(confidentialMachineSeriesSupportingSevsnp, ", "), spec.InstanceType)
}
default:
return fmt.Errorf("invalid ConfidentialInstanceType %s", *spec.ConfidentialInstanceType)
}
}
} else if (spec.ConfidentialCompute == nil || *spec.ConfidentialCompute != ConfidentialComputePolicyEnabled) && spec.ConfidentialInstanceType != nil && *spec.ConfidentialInstanceType != "" {
return fmt.Errorf("ConfidentialCompute is Disabled but a ConfidentialInstanceType value was provided. ConfidentialCompute must be set to %s to configure a ConfidentialInstanceType", ConfidentialComputePolicyEnabled)
}
return nil
}
Expand Down
76 changes: 76 additions & 0 deletions api/v1beta1/gcpmachine_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ import (
func TestGCPMachine_ValidateCreate(t *testing.T) {
g := NewWithT(t)
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
confidentialComputeDisabled := ConfidentialComputePolicyDisabled
foobar := ConfidentialVMTechnology("foobar")
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
confidentialInstanceTypeSEV := ConfidentialVMTechnologySEV
confidentialInstanceTypeSEVSNP := ConfidentialVMTechnologySEVSNP
tests := []struct {
name string
*GCPMachine
Expand Down Expand Up @@ -85,6 +89,78 @@ func TestGCPMachine_ValidateCreate(t *testing.T) {
},
wantErr: true,
},
{
name: "GCPMachine with explicit ConfidentialInstanceType and ConfidentialCompute Disabled - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeDisabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEV,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: true,
},
{
name: "GCPMachine with explicit ConfidentialInstanceType and OnHostMaintenance Migrate - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceMigrate,
},
},
wantErr: true,
},
{
name: "GCPMachine with SEVSNP ConfidentialInstanceType and unsupported machine type - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "c2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: true,
},
{
name: "GCPMachine with SEVSNP ConfidentialInstanceType and supported machine type - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: false,
},
{
name: "GCPMachine with explicit SEV ConfidentialInstanceType and supported machine type - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "c3d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEV,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: false,
},
{
name: "GCPMachine with unknown ConfidentialInstanceType and ConfidentialCompute Enabled - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &foobar,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: true,
},
{
name: "GCPMachine with RootDiskEncryptionKey KeyType Managed and Managed field set",
GCPMachine: &GCPMachine{
Expand Down
99 changes: 99 additions & 0 deletions api/v1beta1/gcpmachinetemplate_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ import (
func TestGCPMachineTemplate_ValidateCreate(t *testing.T) {
g := NewWithT(t)
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
confidentialComputeDisabled := ConfidentialComputePolicyDisabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
confidentialInstanceTypeSEV := ConfidentialVMTechnologySEV
confidentialInstanceTypeSEVSNP := ConfidentialVMTechnologySEVSNP
tests := []struct {
name string
template *GCPMachineTemplate
Expand Down Expand Up @@ -105,6 +108,102 @@ func TestGCPMachineTemplate_ValidateCreate(t *testing.T) {
},
wantErr: true,
},
{
name: "GCPMachine with explicit ConfidentialInstanceType and ConfidentialCompute Disabled - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeDisabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
},
},
wantErr: true,
},
{
name: "GCPMachine with explicit ConfidentialInstanceType and OnHostMaintenance Migrate - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceMigrate,
},
},
},
},
wantErr: true,
},
{
name: "GCPMachine with SEVSNP ConfidentialInstanceType and unsupported machine type - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "c3d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
},
},
wantErr: true,
},
{
name: "GCPMachine with SEVSNP ConfidentialInstanceType and supported machine type - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
},
},
wantErr: false,
},
{
name: "GCPMachine with explicit SEV ConfidentialInstanceType and supported machine type - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "c3d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEV,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
},
},
wantErr: false,
},
{
name: "GCPMachine with explicit SEV ConfidentialInstanceType and supported machine type - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "c3d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
ConfidentialInstanceType: &confidentialInstanceTypeSEV,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
},
},
wantErr: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions cloud/scope/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,19 @@ func (m *MachineScope) InstanceSpec(log logr.Logger) *compute.Instance {
EnableConfidentialCompute: enabled,
}
}
if m.GCPMachine.Spec.ConfidentialInstanceType != nil {
if instance.ConfidentialInstanceConfig == nil {
instance.ConfidentialInstanceConfig = &compute.ConfidentialInstanceConfig{}
}
switch *m.GCPMachine.Spec.ConfidentialInstanceType {
case infrav1.ConfidentialVMTechnologySEV:
instance.ConfidentialInstanceConfig.ConfidentialInstanceType = "SEV"
case infrav1.ConfidentialVMTechnologySEVSNP:
instance.ConfidentialInstanceConfig.ConfidentialInstanceType = "SEV_SNP"
default:
log.Error(errors.New("Invalid value"), "Unknown ConfidentialInstanceType value", "Spec.ConfidentialInstanceType", *m.GCPMachine.Spec.ConfidentialInstanceType)
}
}

instance.Disks = append(instance.Disks, m.InstanceImageSpec())
instance.Disks = append(instance.Disks, m.InstanceAdditionalDiskSpec()...)
Expand Down
Loading

0 comments on commit ff8cf8e

Please sign in to comment.