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

✨ Rekey disks for encrypted VMs #765

Merged
merged 1 commit into from
Oct 24, 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
1 change: 1 addition & 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.

1 change: 1 addition & 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.

21 changes: 21 additions & 0 deletions api/v1alpha3/virtualmachine_storage_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ const (
VirtualMachineStorageDiskTypeManaged VirtualMachineVolumeType = "Managed"
)

type VirtualMachineVolumeCryptoStatus struct {
// +optional

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

// +optional

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

// VirtualMachineVolumeStatus defines the observed state of a
// VirtualMachineVolume instance.
type VirtualMachineVolumeStatus struct {
Expand All @@ -97,6 +113,11 @@ type VirtualMachineVolumeStatus struct {

// +optional

// Crypto describes the volume's encryption status.
Crypto *VirtualMachineVolumeCryptoStatus `json:"crypto,omitempty"`

// +optional

// Limit describes the storage limit for the volume.
Limit *resource.Quantity `json:"limit,omitempty"`

Expand Down
8 changes: 3 additions & 5 deletions api/v1alpha3/virtualmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,11 +745,9 @@ type VirtualMachineCryptoStatus struct {
//
// - 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.
// - Disks -- This refers to at least one of the VM's attached disks. To
// determine the encryption state of the individual disks,
// please refer to status.volumes[].crypto.
Encrypted []VirtualMachineEncryptionType `json:"encrypted,omitempty"`

// +optional
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha3/zz_generated.deepcopy.go

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

24 changes: 19 additions & 5 deletions config/crd/bases/vmoperator.vmware.com_virtualmachines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4688,11 +4688,9 @@ spec:

- 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.
- Disks -- This refers to at least one of the VM's attached disks. To
determine the encryption state of the individual disks,
please refer to status.volumes[].crypto.
items:
type: string
type: array
Expand Down Expand Up @@ -5403,6 +5401,22 @@ spec:
Attached represents whether a volume has been successfully attached to
the VirtualMachine or not.
type: boolean
crypto:
description: Crypto describes the volume's encryption status.
properties:
keyID:
description: |-
KeyID describes the key ID used to encrypt the volume.
Please note, this field will be empty if the volume is not
encrypted.
type: string
providerID:
description: |-
ProviderID describes the provider ID used to encrypt the volume.
Please note, this field will be empty if the volume is not
encrypted.
type: string
type: object
diskUUID:
description: |-
DiskUUID represents the underlying virtual disk UUID and is present when
Expand Down
4 changes: 2 additions & 2 deletions controllers/storageclass/storageclass_controller_intg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func intgTestsReconcile() {
})
It("should eventually mark the storage class as encrypted in the context", func() {
Eventually(func(g Gomega) {
ok, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
ok, _, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
Expect(err).ToNot(HaveOccurred())
Expect(ok).To(BeTrue())
})
Expand All @@ -69,7 +69,7 @@ func intgTestsReconcile() {
Context("reconciling a plain storage class", func() {
It("should never mark the storage class as encrypted in the context", func() {
Consistently(func(g Gomega) {
ok, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
ok, _, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
Expect(err).ToNot(HaveOccurred())
Expect(ok).To(BeFalse())
})
Expand Down
10 changes: 7 additions & 3 deletions controllers/storageclass/storageclass_controller_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ func unitTestsReconcile() {
When("no storage policy ID", func() {
It("should return an error", func() {
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(`StorageClass "my-storage-class" does not have 'storagePolicyID' parameter`))
Expect(err).To(MatchError(
kubeutil.ErrMissingParameter{
StorageClassName: "my-storage-class",
ParameterName: "storagePolicyID",
}))
})
})
When("not encrypted", func() {
Expand All @@ -123,7 +127,7 @@ func unitTestsReconcile() {
})
It("marks item as encrypted and returns success", func() {
Expect(err).ToNot(HaveOccurred())
ok, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
ok, _, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
Expect(err).ToNot(HaveOccurred())
Expect(ok).To(BeFalse())
})
Expand All @@ -136,7 +140,7 @@ func unitTestsReconcile() {
})
It("marks item as encrypted and returns success", func() {
Expect(err).ToNot(HaveOccurred())
ok, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
ok, _, err := kubeutil.IsEncryptedStorageClass(ctx, ctx.Client, obj.Name)
Expect(err).ToNot(HaveOccurred())
Expect(ok).To(BeTrue())
})
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/workloads/vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,14 +476,14 @@ The field `spec.crypto` may be used in conjunction with a VM's storage class and

#### Encryption type

The type of encryption depends on the storage class and hardware present in the VM as the chart below illustrates:
The type of encryption used by the VM is reported in the list `status.crypto.encrypted`. The list may contain the values `Config` and/or `Disks`, depending on the storage class and hardware present in the VM as the chart below illustrates:

| | Config | Disks |
|--------------------------|:------:|:-----:|
| Encryption storage class | ✓ | ✓ |
| vTPM | ✓ | |

The `Config` type refers to all files related to a VM except for virtual disks. The `Disks` type refers to a VM's virtual disks except for PVCs. To ascertain the encryption status of a PVC, please refer directly to the PVC resource.
The `Config` type refers to all files related to a VM except for virtual disks. The `Disks` type indicates at least one of a VM's virtual disks is encrypted. To determine which of the VM's disks are encrypted, please refer to `status.volumes[].crypto`.

#### Default Key Provider

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ require (
github.com/vmware-tanzu/vm-operator/external/tanzu-topology v0.0.0-00010101000000-000000000000
github.com/vmware-tanzu/vm-operator/pkg/backup/api v0.0.0-00010101000000-000000000000
github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels v0.0.0-00010101000000-000000000000
github.com/vmware/govmomi v0.31.1-0.20241015181712-cd4331eda367
github.com/vmware/govmomi v0.31.1-0.20241024144701-6df52891f229
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
// * https://github.com/vmware-tanzu/vm-operator/security/dependabot/24
golang.org/x/text v0.19.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,8 @@ github.com/vmware-tanzu/net-operator-api v0.0.0-20240523152550-862e2c4eb0e0 h1:y
github.com/vmware-tanzu/net-operator-api v0.0.0-20240523152550-862e2c4eb0e0/go.mod h1:w6QJGm3crIA16ZIz1FVQXD2NVeJhOgGXxW05RbVTSTo=
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240902045731-00a14868c72d h1:6pMXrQmTYpu5FipoQ9fT4FJG3VPMMbBoIi6h3KvdQc8=
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240902045731-00a14868c72d/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk=
github.com/vmware/govmomi v0.31.1-0.20241015181712-cd4331eda367 h1:4gP1VC+N9onypUJh52dSrAKsnpyhQLHc/g3tH9qd4vM=
github.com/vmware/govmomi v0.31.1-0.20241015181712-cd4331eda367/go.mod h1:uoLVU9zlXC4p4GmLVG+ZJmBC0Gn3Q7mytOJvi39OhxA=
github.com/vmware/govmomi v0.31.1-0.20241024144701-6df52891f229 h1:XopiNtNFPXBeamYFQRQBQsv2kYYhwYGNYdhbEuoaHxQ=
github.com/vmware/govmomi v0.31.1-0.20241024144701-6df52891f229/go.mod h1:uoLVU9zlXC4p4GmLVG+ZJmBC0Gn3Q7mytOJvi39OhxA=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
Expand Down
31 changes: 21 additions & 10 deletions pkg/providers/vsphere/vmlifecycle/update_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -827,21 +827,32 @@ func updateVolumeStatus(vm *vmopv1.VirtualMachine, moVM mo.VirtualMachine) {
// existing status with the usage information.
di, _ := vmdk.GetVirtualDiskInfoByUUID(ctx, nil, moVM, false, diskUUID)
vm.Status.Volumes[diskIndex].Used = BytesToResourceGiB(di.UniqueSize)
if di.CryptoKey.ProviderID != "" || di.CryptoKey.KeyID != "" {
vm.Status.Volumes[diskIndex].Crypto = &vmopv1.VirtualMachineVolumeCryptoStatus{
ProviderID: di.CryptoKey.ProviderID,
KeyID: di.CryptoKey.KeyID,
}
}
} else if !isFCD {
// The disk is a classic, non-FCD that must be added to the list of
// volume statuses.
di, _ := vmdk.GetVirtualDiskInfoByUUID(ctx, nil, moVM, false, diskUUID)
dp := diskPath.Path
vm.Status.Volumes = append(
vm.Status.Volumes,
vmopv1.VirtualMachineVolumeStatus{
Name: strings.TrimSuffix(path.Base(dp), path.Ext(dp)),
Type: vmopv1.VirtualMachineStorageDiskTypeClassic,
Attached: true,
DiskUUID: diskUUID,
Limit: BytesToResourceGiB(di.CapacityInBytes),
Used: BytesToResourceGiB(di.UniqueSize),
})
volStatus := vmopv1.VirtualMachineVolumeStatus{
Name: strings.TrimSuffix(path.Base(dp), path.Ext(dp)),
Type: vmopv1.VirtualMachineStorageDiskTypeClassic,
Attached: true,
DiskUUID: diskUUID,
Limit: BytesToResourceGiB(di.CapacityInBytes),
Used: BytesToResourceGiB(di.UniqueSize),
}
if di.CryptoKey.ProviderID != "" || di.CryptoKey.KeyID != "" {
volStatus.Crypto = &vmopv1.VirtualMachineVolumeCryptoStatus{
ProviderID: di.CryptoKey.ProviderID,
KeyID: di.CryptoKey.KeyID,
}
}
vm.Status.Volumes = append(vm.Status.Volumes, volStatus)
}
}

Expand Down
28 changes: 28 additions & 0 deletions pkg/providers/vsphere/vmlifecycle/update_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,12 @@ var _ = Describe("UpdateStatus", func() {
FileName: "[datastore] vm/my-disk-100.vmdk",
},
Uuid: "100",
KeyId: &vimtypes.CryptoKeyId{
KeyId: "my-key-id",
ProviderId: &vimtypes.KeyProviderId{
Id: "my-provider-id",
},
},
},
Key: 100,
},
Expand Down Expand Up @@ -610,6 +616,12 @@ var _ = Describe("UpdateStatus", func() {
FileName: "[datastore] vm/my-disk-105.vmdk",
},
Uuid: "105",
KeyId: &vimtypes.CryptoKeyId{
KeyId: "my-key-id",
ProviderId: &vimtypes.KeyProviderId{
Id: "my-provider-id",
},
},
},
Key: 105,
},
Expand Down Expand Up @@ -788,6 +800,10 @@ var _ = Describe("UpdateStatus", func() {
Name: "my-disk-100",
DiskUUID: "100",
Type: vmopv1.VirtualMachineStorageDiskTypeClassic,
Crypto: &vmopv1.VirtualMachineVolumeCryptoStatus{
KeyID: "my-key-id",
ProviderID: "my-provider-id",
},
Attached: true,
Limit: vmlifecycle.BytesToResourceGiB(10 * oneGiBInBytes),
Used: vmlifecycle.BytesToResourceGiB(500 + (1 * oneGiBInBytes)),
Expand Down Expand Up @@ -846,6 +862,10 @@ var _ = Describe("UpdateStatus", func() {
Name: "my-disk-100",
DiskUUID: "100",
Type: vmopv1.VirtualMachineStorageDiskTypeClassic,
Crypto: &vmopv1.VirtualMachineVolumeCryptoStatus{
KeyID: "my-key-id",
ProviderID: "my-provider-id",
},
Attached: true,
Limit: vmlifecycle.BytesToResourceGiB(10 * oneGiBInBytes),
Used: vmlifecycle.BytesToResourceGiB(500 + (1 * oneGiBInBytes)),
Expand Down Expand Up @@ -886,6 +906,10 @@ var _ = Describe("UpdateStatus", func() {
Name: "my-disk-105",
DiskUUID: "105",
Type: vmopv1.VirtualMachineStorageDiskTypeManaged,
Crypto: &vmopv1.VirtualMachineVolumeCryptoStatus{
KeyID: "my-key-id",
ProviderID: "my-provider-id",
},
Attached: false,
Limit: vmlifecycle.BytesToResourceGiB(100 * oneGiBInBytes),
Used: vmlifecycle.BytesToResourceGiB(500 + (50 * oneGiBInBytes)),
Expand All @@ -912,6 +936,10 @@ var _ = Describe("UpdateStatus", func() {
Name: "my-disk-100",
DiskUUID: "100",
Type: vmopv1.VirtualMachineStorageDiskTypeClassic,
Crypto: &vmopv1.VirtualMachineVolumeCryptoStatus{
ProviderID: "my-provider-id",
KeyID: "my-key-id",
},
Attached: true,
Limit: vmlifecycle.BytesToResourceGiB(10 * oneGiBInBytes),
Used: vmlifecycle.BytesToResourceGiB(500 + (1 * oneGiBInBytes)),
Expand Down
Loading
Loading