Skip to content

Commit

Permalink
Merge pull request #673 from akutz/feature/vm-encryption-class-name
Browse files Browse the repository at this point in the history
✨ Bring your own (encryption) key (BYOK)
  • Loading branch information
akutz authored Sep 27, 2024
2 parents 3229d9d + 00f5f8b commit d771479
Show file tree
Hide file tree
Showing 74 changed files with 6,819 additions and 279 deletions.
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
// 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
// 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
// key provider, the VM will be not be rekeyed.
//
// Please note, this could result in a VirtualMachine that cannot be
// 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"
VirtualMachineEncryptionTypeDisks VirtualMachineEncryptionType = "Disks"
)

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

0 comments on commit d771479

Please sign in to comment.