Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for confidential compute #809

Merged
merged 1 commit into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions api/v1alpha3/gcpmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (src *GCPMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint
dst.Spec.ShieldedInstanceConfig = restored.Spec.ShieldedInstanceConfig
}

if restored.Spec.OnHostMaintenance != nil {
dst.Spec.OnHostMaintenance = restored.Spec.OnHostMaintenance
}

if restored.Spec.ConfidentialCompute != nil {
dst.Spec.ConfidentialCompute = restored.Spec.ConfidentialCompute
}

return nil
}

Expand Down
8 changes: 8 additions & 0 deletions api/v1alpha3/gcpmachinetemplate_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (src *GCPMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { // nolin
dst.Spec.Template.Spec.ShieldedInstanceConfig = restored.Spec.Template.Spec.ShieldedInstanceConfig
}

if restored.Spec.Template.Spec.OnHostMaintenance != nil {
dst.Spec.Template.Spec.OnHostMaintenance = restored.Spec.Template.Spec.OnHostMaintenance
}

if restored.Spec.Template.Spec.ConfidentialCompute != nil {
dst.Spec.Template.Spec.ConfidentialCompute = restored.Spec.Template.Spec.ConfidentialCompute
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions api/v1alpha3/zz_generated.conversion.go

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

8 changes: 8 additions & 0 deletions api/v1alpha4/gcpmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (src *GCPMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint
dst.Spec.ShieldedInstanceConfig = restored.Spec.ShieldedInstanceConfig
}

if restored.Spec.OnHostMaintenance != nil {
dst.Spec.OnHostMaintenance = restored.Spec.OnHostMaintenance
}

if restored.Spec.ConfidentialCompute != nil {
dst.Spec.ConfidentialCompute = restored.Spec.ConfidentialCompute
}

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions api/v1alpha4/gcpmachinetemplate_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ func (src *GCPMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { // nolin
if restored.Spec.Template.Spec.ShieldedInstanceConfig != nil {
dst.Spec.Template.Spec.ShieldedInstanceConfig = restored.Spec.Template.Spec.ShieldedInstanceConfig
}
if restored.Spec.Template.Spec.OnHostMaintenance != nil {
dst.Spec.Template.Spec.OnHostMaintenance = restored.Spec.Template.Spec.OnHostMaintenance
}

if restored.Spec.Template.Spec.ConfidentialCompute != nil {
dst.Spec.Template.Spec.ConfidentialCompute = restored.Spec.Template.Spec.ConfidentialCompute
}

return nil
}
Expand Down
2 changes: 2 additions & 0 deletions api/v1alpha4/zz_generated.conversion.go

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

37 changes: 37 additions & 0 deletions api/v1beta1/gcpmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,30 @@ type GCPShieldedInstanceConfig struct {
IntegrityMonitoring IntegrityMonitoringPolicy `json:"integrityMonitoring,omitempty"`
}

// ConfidentialComputePolicy represents the confidential compute configuration for the GCP machine.
type ConfidentialComputePolicy string
richardcase marked this conversation as resolved.
Show resolved Hide resolved

const (
// ConfidentialComputePolicyEnabled enables confidential compute for the GCP machine.
ConfidentialComputePolicyEnabled ConfidentialComputePolicy = "Enabled"
// ConfidentialComputePolicyDisabled disables confidential compute for the GCP machine.
ConfidentialComputePolicyDisabled ConfidentialComputePolicy = "Disabled"
)

// 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"}

// HostMaintenancePolicy represents the desired behavior ase of a host maintenance event.
type HostMaintenancePolicy string

const (
// HostMaintenancePolicyMigrate causes Compute Engine to live migrate an instance when there is a maintenance event.
HostMaintenancePolicyMigrate HostMaintenancePolicy = "Migrate"
// HostMaintenancePolicyTerminate - stops an instance instead of migrating it.
HostMaintenancePolicyTerminate HostMaintenancePolicy = "Terminate"
)

// GCPMachineSpec defines the desired state of GCPMachine.
type GCPMachineSpec struct {
// InstanceType is the type of instance to create. Example: n1.standard-2
Expand Down Expand Up @@ -209,6 +233,19 @@ type GCPMachineSpec struct {
// ShieldedInstanceConfig is the Shielded VM configuration for this machine
// +optional
ShieldedInstanceConfig *GCPShieldedInstanceConfig `json:"shieldedInstanceConfig,omitempty"`

// OnHostMaintenance determines the behavior when a maintenance event occurs that might cause the instance to reboot.
// If omitted, the platform chooses a default, which is subject to change over time, currently that default is "Migrate".
// +kubebuilder:validation:Enum=Migrate;Terminate;
// +optional
OnHostMaintenance *HostMaintenancePolicy `json:"onHostMaintenance,omitempty"`

// 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.
// +kubebuilder:validation:Enum=Enabled;Disabled
// +optional
ConfidentialCompute *ConfidentialComputePolicy `json:"confidentialCompute,omitempty"`
}

// MetadataItem defines a single piece of metadata associated with an instance.
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 @@ -17,7 +17,11 @@ limitations under the License.
package v1beta1

import (
"fmt"
"reflect"
"strings"

"k8s.io/utils/strings/slices"

"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -45,8 +49,7 @@ var _ webhook.Validator = &GCPMachine{}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (m *GCPMachine) ValidateCreate() error {
clusterlog.Info("validate create", "name", m.Name)

return nil
return validateConfidentialCompute(m.Spec)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
Expand Down Expand Up @@ -99,3 +102,17 @@ func (m *GCPMachine) ValidateDelete() error {
func (m *GCPMachine) Default() {
clusterlog.Info("default", "name", m.Name)
}

func validateConfidentialCompute(spec GCPMachineSpec) error {
if spec.ConfidentialCompute != nil && *spec.ConfidentialCompute == ConfidentialComputePolicyEnabled {
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)
}

machineSeries := strings.Split(spec.InstanceType, "-")[0]
if !slices.Contains(confidentialComputeSupportedMachineSeries, machineSeries) {
return fmt.Errorf("ConfidentialCompute require instance type in the following series: %s", confidentialComputeSupportedMachineSeries)
}
}
return nil
}
101 changes: 101 additions & 0 deletions api/v1beta1/gcpmachine_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
Copyright 2023 The Kubernetes Authors.

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 v1beta1

import (
"testing"

. "github.com/onsi/gomega"
)

func TestGCPMachine_ValidateCreate(t *testing.T) {
g := NewWithT(t)
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
tests := []struct {
name string
*GCPMachine
wantErr bool
}{
{
name: "GCPMachined with OnHostMaintenance set to Terminate - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: false,
},
{
name: "GCPMachined with ConfidentialCompute enabled and OnHostMaintenance set to Terminate - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceTerminate,
ConfidentialCompute: &confidentialComputeEnabled,
},
},
wantErr: false,
},
{
name: "GCPMachined with ConfidentialCompute enabled and OnHostMaintenance set to Migrate - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceMigrate,
ConfidentialCompute: &confidentialComputeEnabled,
},
},
wantErr: true,
},
{
name: "GCPMachined with ConfidentialCompute enabled and default OnHostMaintenance (Migrate) - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
},
},
wantErr: true,
},
{
name: "GCPMachined with ConfidentialCompute enabled and unsupported instance type - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "e2-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: true,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
err := test.GCPMachine.ValidateCreate()
if test.wantErr {
g.Expect(err).To(HaveOccurred())
} else {
g.Expect(err).NotTo(HaveOccurred())
}
})
}
}
2 changes: 1 addition & 1 deletion api/v1beta1/gcpmachinetemplate_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var _ webhook.Validator = &GCPMachineTemplate{}
func (r *GCPMachineTemplate) ValidateCreate() error {
clusterlog.Info("validate create", "name", r.Name)

return nil
return validateConfidentialCompute(r.Spec.Template.Spec)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
Expand Down
116 changes: 116 additions & 0 deletions api/v1beta1/gcpmachinetemplate_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Copyright 2023 The Kubernetes Authors.

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 v1beta1

import (
"testing"

. "github.com/onsi/gomega"
)

func TestGCPMachineTemplate_ValidateCreate(t *testing.T) {
g := NewWithT(t)
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
tests := []struct {
name string
template *GCPMachineTemplate
wantErr bool
}{
{
name: "GCPMachineTemplate with OnHostMaintenance set to Terminate - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceTerminate,
}},
},
},
wantErr: false,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and OnHostMaintenance set to Terminate - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceTerminate,
}},
},
},
wantErr: false,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and OnHostMaintenance set to Migrate - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceMigrate,
}},
},
},
wantErr: true,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and default OnHostMaintenance (Migrate) - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
}},
},
},
wantErr: true,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and unsupported instance type - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "e2-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceTerminate,
}},
},
},
wantErr: true,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
err := test.template.ValidateCreate()
if test.wantErr {
g.Expect(err).To(HaveOccurred())
} else {
g.Expect(err).NotTo(HaveOccurred())
}
})
}
}
Loading