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 23, 2025
1 parent f24b413 commit 8269aa6
Show file tree
Hide file tree
Showing 9 changed files with 341 additions and 4 deletions.
23 changes: 22 additions & 1 deletion 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"
)

// ConfidentialVMTechnology represents the confidential computing technology used by a GCP confidential machine.
type ConfidentialVMTechnology string

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

// Confidential VM supports Compute Engine machine types in the following series:
// reference: https://cloud.google.com/compute/confidential-vm/docs/os-and-machine-type#machine-type
var confidentialComputeSupportedMachineSeries = []string{"n2d", "c2d"}
var confidentialComputeSupportedMachineSeries = map[ConfidentialVMTechnology][]string{
ConfidentialVMTechSEV: {"n2d", "c2d", "c3d"},
ConfidentialVMTechSEVSNP: {"n2d"},
}

// HostMaintenancePolicy represents the desired behavior ase of a host maintenance event.
type HostMaintenancePolicy string
Expand Down Expand Up @@ -339,10 +352,18 @@ type GCPMachineSpec struct {
// ConfidentialCompute Defines whether the instance should have confidential compute enabled.
// If enabled OnHostMaintenance is required to be set to "Terminate".
// If omitted, the platform chooses a default, which is subject to change over time, currently that default is false.
// If ConfidentialInstanceType is configured, even if ConfidentialCompute is Disabled, a confidential compute instance will be configured.
// +kubebuilder:validation:Enum=Enabled;Disabled
// +optional
ConfidentialCompute *ConfidentialComputePolicy `json:"confidentialCompute,omitempty"`

// confidentialInstanceType determines the required type of confidential computing technology.
// confidentialInstanceType will precede confidentialCompute. That is, if confidentialCompute is "Disabled" but a valid confidentialInstanceType is specified, a confidential instance will be configured.
// If confidentialInstanceType isn't set and confidentialCompute is "Enabled" the platform will set the default, which is subject to change over time. Currently the default is "sev" for "c2d", "c3d", and "n2d" machineTypes. For the other machine cases, a valid confidentialInstanceType must be specified.
// +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
23 changes: 20 additions & 3 deletions api/v1beta1/gcpmachine_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,32 @@ func (m *GCPMachine) Default() {
clusterlog.Info("default", "name", m.Name)
}

func targetConfidentialType(tech *ConfidentialVMTechnology) (ConfidentialVMTechnology, error) {
if tech == nil || tech != nil && *tech == "" {
return ConfidentialVMTechSEV, nil
}
_, ok := confidentialComputeSupportedMachineSeries[*tech]
if !ok {
return "", fmt.Errorf("Invalid ConfidentialInstanceType %s", *tech)

Check failure on line 117 in api/v1beta1/gcpmachine_webhook.go

View workflow job for this annotation

GitHub Actions / lint

ST1005: error strings should not be capitalized (stylecheck)
}
return *tech, nil
}

func validateConfidentialCompute(spec GCPMachineSpec) error {
if spec.ConfidentialCompute != nil && *spec.ConfidentialCompute == ConfidentialComputePolicyEnabled {
if spec.ConfidentialCompute != nil && *spec.ConfidentialCompute == ConfidentialComputePolicyEnabled || spec.ConfidentialInstanceType != nil && *spec.ConfidentialInstanceType != "" {
if spec.OnHostMaintenance == nil || *spec.OnHostMaintenance == HostMaintenancePolicyMigrate {
return fmt.Errorf("ConfidentialCompute require OnHostMaintenance to be set to %s, the current value is: %s", HostMaintenancePolicyTerminate, HostMaintenancePolicyMigrate)
}

confidentialType, err := targetConfidentialType(spec.ConfidentialInstanceType)
if err != nil {
return err
}
supportedMachines := confidentialComputeSupportedMachineSeries[confidentialType]

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 !slices.Contains(supportedMachines, machineSeries) {
return fmt.Errorf("ConfidentialInstanceType %s requires an instance type in the following series: %s", confidentialType, supportedMachines)
}
}
return nil
Expand Down
46 changes: 46 additions & 0 deletions api/v1beta1/gcpmachine_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func TestGCPMachine_ValidateCreate(t *testing.T) {
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
confidentialInstanceTypeSEV := ConfidentialVMTechSEV
confidentialInstanceTypeSEVSNP := ConfidentialVMTechSEVSNP
tests := []struct {
name string
*GCPMachine
Expand Down Expand Up @@ -85,6 +87,50 @@ func TestGCPMachine_ValidateCreate(t *testing.T) {
},
wantErr: true,
},
{
name: "GCPMachine with explicit ConfidentialInstanceType and OnHostMaintenance Migrate - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceMigrate,
},
},
wantErr: true,
},
{
name: "GCPMachine with SEVSNP ConfidentialInstanceType and unsupported machine type - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "c2d-standard-4",
ConfidentialInstanceType: &confidentialInstanceTypeSEVSNP,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: true,
},
{
name: "GCPMachine with SEVSNP ConfidentialInstanceType and supported machine type - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
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",
ConfidentialInstanceType: &confidentialInstanceTypeSEV,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: false,
},
{
name: "GCPMachine with RootDiskEncryptionKey KeyType Managed and Managed field set",
GCPMachine: &GCPMachine{
Expand Down
62 changes: 62 additions & 0 deletions api/v1beta1/gcpmachinetemplate_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func TestGCPMachineTemplate_ValidateCreate(t *testing.T) {
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
confidentialInstanceTypeSEV := ConfidentialVMTechSEV
confidentialInstanceTypeSEVSNP := ConfidentialVMTechSEVSNP
tests := []struct {
name string
template *GCPMachineTemplate
Expand Down Expand Up @@ -105,6 +107,66 @@ func TestGCPMachineTemplate_ValidateCreate(t *testing.T) {
},
wantErr: true,
},
{
name: "GCPMachine with explicit ConfidentialInstanceType and OnHostMaintenance Migrate - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
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",
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",
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",
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.ConfidentialVMTechSEV:
instance.ConfidentialInstanceConfig.ConfidentialInstanceType = "SEV"
case infrav1.ConfidentialVMTechSEVSNP:
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 8269aa6

Please sign in to comment.