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

✨ Bring your own (encryption) key (BYOK) #673

Merged
merged 1 commit into from
Sep 27, 2024
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ config/crd/external-crds/cns.vmware.com_*
!config/crd/external-crds/cns.vmware.com_storagepolicyquotas.yaml
!config/crd/external-crds/cns.vmware.com_storagepolicyusages.yaml

# Created by the VSCode ginkgo plug-in
ginkgo.report

.DS_Store
.cache

Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/virtualmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,10 @@ func Convert_v1alpha3_VirtualMachineStatus_To_v1alpha1_VirtualMachineStatus(
return nil
}

func restore_v1alpha3_VirtualMachineCryptoSpec(dst, src *vmopv1.VirtualMachine) {
dst.Spec.Crypto = src.Spec.Crypto
}

func restore_v1alpha3_VirtualMachineImage(dst, src *vmopv1.VirtualMachine) {
dst.Spec.Image = src.Spec.Image
dst.Spec.ImageName = src.Spec.ImageName
Expand Down Expand Up @@ -1239,6 +1243,7 @@ func (src *VirtualMachine) ConvertTo(dstRaw ctrlconversion.Hub) error {
restore_v1alpha3_VirtualMachineInstanceUUID(dst, restored)
restore_v1alpha3_VirtualMachineGuestID(dst, restored)
restore_v1alpha3_VirtualMachineCdrom(dst, restored)
restore_v1alpha3_VirtualMachineCryptoSpec(dst, restored)

// END RESTORE

Expand Down
71 changes: 71 additions & 0 deletions api/v1alpha1/virtualmachine_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1702,4 +1702,75 @@ func TestVirtualMachineConversion(t *testing.T) {
g.Expect(apiequality.Semantic.DeepEqual(hub, expectedHub)).To(BeTrue(), cmp.Diff(hub, expectedHub))
})
})

t.Run("VirtualMachine and spec.crypto", func(t *testing.T) {

t.Run("hub-spoke-hub", func(t *testing.T) {

t.Run("spec.crypto is nil", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{}
hubSpokeHub(g, &hub, &vmopv1a1.VirtualMachine{})
})

t.Run("spec.crypto is empty", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{},
},
}
hubSpokeHub(g, &hub, &vmopv1a1.VirtualMachine{})
})

t.Run("spec.crypto.className is non-empty", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
EncryptionClassName: "fake",
},
},
}
hubSpokeHub(g, &hub, &vmopv1a1.VirtualMachine{})
})

t.Run("spec.crypto.useDefaultKeyProvider is &true", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
UseDefaultKeyProvider: &[]bool{true}[0],
},
},
}
hubSpokeHub(g, &hub, &vmopv1a1.VirtualMachine{})
})

t.Run("spec.crypto.useDefaultKeyProvider is &false", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
UseDefaultKeyProvider: &[]bool{false}[0],
},
},
}
hubSpokeHub(g, &hub, &vmopv1a1.VirtualMachine{})
})

t.Run("spec.crypto is completely filled out", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
EncryptionClassName: "fake",
UseDefaultKeyProvider: &[]bool{false}[0],
},
},
}
hubSpokeHub(g, &hub, &vmopv1a1.VirtualMachine{})
})
})
})
}
2 changes: 2 additions & 0 deletions api/v1alpha1/zz_generated.conversion.go

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

5 changes: 5 additions & 0 deletions api/v1alpha2/virtualmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ func Convert_v1alpha3_VirtualMachine_To_v1alpha2_VirtualMachine(
return nil
}

func restore_v1alpha3_VirtualMachineCryptoSpec(dst, src *vmopv1.VirtualMachine) {
dst.Spec.Crypto = src.Spec.Crypto
}

func restore_v1alpha3_VirtualMachineImage(dst, src *vmopv1.VirtualMachine) {
dst.Spec.Image = src.Spec.Image
dst.Spec.ImageName = src.Spec.ImageName
Expand Down Expand Up @@ -293,6 +297,7 @@ func (src *VirtualMachine) ConvertTo(dstRaw ctrlconversion.Hub) error {
restore_v1alpha3_VirtualMachineSpecNetworkDomainName(dst, restored)
restore_v1alpha3_VirtualMachineGuestID(dst, restored)
restore_v1alpha3_VirtualMachineCdrom(dst, restored)
restore_v1alpha3_VirtualMachineCryptoSpec(dst, restored)

// END RESTORE

Expand Down
71 changes: 71 additions & 0 deletions api/v1alpha2/virtualmachine_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,4 +607,75 @@ func TestVirtualMachineConversion(t *testing.T) {
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})
})

t.Run("VirtualMachine and spec.crypto", func(t *testing.T) {

t.Run("hub-spoke-hub", func(t *testing.T) {

t.Run("spec.crypto is nil", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{}
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})

t.Run("spec.crypto is empty", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{},
},
}
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})

t.Run("spec.crypto.className is non-empty", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
EncryptionClassName: "fake",
},
},
}
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})

t.Run("spec.crypto.useDefaultKeyProvider is true", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
UseDefaultKeyProvider: &[]bool{true}[0],
},
},
}
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})

t.Run("spec.crypto.useDefaultKeyProvider is false", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
UseDefaultKeyProvider: &[]bool{false}[0],
},
},
}
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})

t.Run("spec.crypto is completely filled out", func(t *testing.T) {
g := NewWithT(t)
hub := vmopv1.VirtualMachine{
Spec: vmopv1.VirtualMachineSpec{
Crypto: &vmopv1.VirtualMachineCryptoSpec{
EncryptionClassName: "fake",
UseDefaultKeyProvider: &[]bool{false}[0],
},
},
}
hubSpokeHub(g, &hub, &vmopv1.VirtualMachine{}, &vmopv1a2.VirtualMachine{})
})
})
})
}
2 changes: 2 additions & 0 deletions api/v1alpha2/zz_generated.conversion.go

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

113 changes: 113 additions & 0 deletions api/v1alpha3/virtualmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const (
// VirtualMachineConditionPlacementReady indicates that the placement decision for the VM is ready.
VirtualMachineConditionPlacementReady = "VirtualMachineConditionPlacementReady"

// VirtualMachineEncryptionSynced indicates that the VirtualMachine's
// encryption state is synced to the desired encryption state.
VirtualMachineEncryptionSynced = "VirtualMachineEncryptionSynced"

// VirtualMachineConditionCreated indicates that the VM has been created.
VirtualMachineConditionCreated = "VirtualMachineCreated"

Expand Down Expand Up @@ -357,6 +361,67 @@ type VirtualMachineCdromSpec struct {
AllowGuestControl *bool `json:"allowGuestControl,omitempty"`
}

// VirtualMachineCryptoSpec defines the desired state of a VirtualMachine's
// encryption state.
type VirtualMachineCryptoSpec struct {
// +optional

// EncryptionClassName describes the name of the EncryptionClass resource
// used to encrypt this VM.
//
// Please note, this field is not required to encrypt the VM. If the
// underlying platform has a default key provider, the VM may still be fully
// or partially encrypted depending on the specified storage and VM classes.
//
// If there is a default key provider and an encryption storage class is
akutz marked this conversation as resolved.
Show resolved Hide resolved
// selected, the files in the VM's home directory and non-PVC virtual disks
// will be encrypted
//
// If there is a default key provider and a VM Class with a virtual, trusted
// platform module (vTPM) is selected, the files in the VM's home directory,
// minus any virtual disks, will be encrypted.
//
// If the underlying vSphere platform does not have a default key provider,
// then this field is required when specifying an encryption storage class
// and/or a VM Class with a vTPM.
EncryptionClassName string `json:"encryptionClassName,omitempty"`

// +optional
// +kubebuilder:default=true

// UseDefaultKeyProvider describes the desired behavior for when an explicit
// EncryptionClass is not provided.
//
// When an explicit EncryptionClass is not provided and this value is true:
//
// - Deploying a VirtualMachine with an encryption storage policy or vTPM
akutz marked this conversation as resolved.
Show resolved Hide resolved
// will be encrypted using the default key provider.
//
// - If a VirtualMachine is not encrypted, uses an encryption storage
// policy or has a virtual, trusted platform module (vTPM), there is a
// default key provider, the VM will be encrypted using the default key
// provider.
//
// - If a VirtualMachine is encrypted with a provider other than the default
// key provider, the VM will be rekeyed using the default key provider.
//
// When an explicit EncryptionClass is not provided and this value is false:
//
// - Deploying a VirtualMachine with an encryption storage policy or vTPM
// will fail.
//
// - If a VirtualMachine is encrypted with a provider other than the default
akutz marked this conversation as resolved.
Show resolved Hide resolved
// key provider, the VM will be not be rekeyed.
//
// Please note, this could result in a VirtualMachine that cannot be
akutz marked this conversation as resolved.
Show resolved Hide resolved
// powered on since it is encrypted using a provider or key that may have
// been removed. Without the key, the VM cannot be decrypted and thus
// cannot be powered on.
//
// Defaults to true if omitted.
UseDefaultKeyProvider *bool `json:"useDefaultKeyProvider,omitempty"`
}

// VirtualMachineSpec defines the desired state of a VirtualMachine.
type VirtualMachineSpec struct {
// +optional
Expand Down Expand Up @@ -439,6 +504,11 @@ type VirtualMachineSpec struct {

// +optional

// Crypto describes the desired encryption state of the VirtualMachine.
Crypto *VirtualMachineCryptoSpec `json:"crypto,omitempty"`

// +optional

// StorageClass describes the name of a Kubernetes StorageClass resource
// used to configure this VM's storage-related attributes.
//
Expand Down Expand Up @@ -694,6 +764,43 @@ type VirtualMachineAdvancedSpec struct {
ChangeBlockTracking *bool `json:"changeBlockTracking,omitempty"`
}

type VirtualMachineEncryptionType string

const (
VirtualMachineEncryptionTypeConfig VirtualMachineEncryptionType = "Config"
akutz marked this conversation as resolved.
Show resolved Hide resolved
VirtualMachineEncryptionTypeDisks VirtualMachineEncryptionType = "Disks"
akutz marked this conversation as resolved.
Show resolved Hide resolved
)

type VirtualMachineCryptoStatus struct {
// +optional

// Encrypted describes the observed state of the VirtualMachine's
// encryption. There may be two values in this list:
//
// - Config -- This refers to all of the files related to a VM except any
// virtual disks.
// - Disk -- This refers to all of the VM's virtual disks that are *not*
// PVCs.
//
// To determine whether or not a PVC is encrypted, please refer to the PVC
// resource.
Encrypted []VirtualMachineEncryptionType `json:"encrypted,omitempty"`

// +optional

// ProviderID describes the provider ID used to encrypt the VirtualMachine.
// Please note, this field will be empty if the VirtualMachine is not
// encrypted.
ProviderID string `json:"providerID,omitempty"`

// +optional

// KeyID describes the key ID used to encrypt the VirtualMachine.
// Please note, this field will be empty if the VirtualMachine is not
// encrypted.
KeyID string `json:"keyID,omitempty"`
}

// VirtualMachineStatus defines the observed state of a VirtualMachine instance.
type VirtualMachineStatus struct {
// +optional
Expand All @@ -720,6 +827,12 @@ type VirtualMachineStatus struct {

// +optional

// Crypto describes the observed state of the VirtualMachine's encryption
// configuration.
Crypto *VirtualMachineCryptoStatus `json:"crypto,omitempty"`

// +optional

// Network describes the observed state of the VM's network configuration.
// Please note much of the network status information is only available if
// the guest has VM Tools installed.
Expand Down
Loading
Loading