diff --git a/internal/rbd/controllerserver.go b/internal/rbd/controllerserver.go index 982b77467..11b28d3a5 100644 --- a/internal/rbd/controllerserver.go +++ b/internal/rbd/controllerserver.go @@ -153,7 +153,7 @@ func (cs *ControllerServer) parseVolCreateRequest(ctx context.Context, req *csi. } func buildCreateVolumeResponse(ctx context.Context, req *csi.CreateVolumeRequest, rbdVol *rbdVolume) (*csi.CreateVolumeResponse, error) { - if rbdVol.Encrypted { + if rbdVol.isEncrypted() { err := rbdVol.setupEncryption(ctx) if err != nil { util.ErrorLog(ctx, err.Error()) @@ -516,7 +516,7 @@ func (cs *ControllerServer) createBackingImage(ctx context.Context, cr *util.Cre return err } } - if rbdVol.Encrypted { + if rbdVol.isEncrypted() { err = rbdVol.setupEncryption(ctx) if err != nil { util.ErrorLog(ctx, "failed to setup encroption for image %s: %v", rbdVol, err) @@ -690,8 +690,8 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol return nil, status.Error(codes.Internal, err.Error()) } - if rbdVol.Encrypted { - if err = rbdVol.KMS.DeletePassphrase(rbdVol.VolID); err != nil { + if rbdVol.isEncrypted() { + if err = rbdVol.encryption.KMS.DeletePassphrase(rbdVol.VolID); err != nil { util.WarningLog(ctx, "failed to clean the passphrase for volume %s: %s", rbdVol.VolID, err) } } @@ -755,7 +755,7 @@ func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS } // TODO: re-encrypt snapshot with a new passphrase - if rbdVol.Encrypted { + if rbdVol.isEncrypted() { return nil, status.Errorf(codes.Unimplemented, "source Volume %s is encrypted, "+ "snapshotting is not supported currently", rbdVol.VolID) } @@ -1124,7 +1124,7 @@ func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi return nil, err } - if rbdVol.Encrypted { + if rbdVol.isEncrypted() { return nil, status.Errorf(codes.InvalidArgument, "encrypted volumes do not support resize (%s)", rbdVol) } diff --git a/internal/rbd/encryption.go b/internal/rbd/encryption.go index 3241468f2..e22f53994 100644 --- a/internal/rbd/encryption.go +++ b/internal/rbd/encryption.go @@ -81,11 +81,16 @@ func (rv *rbdVolume) ensureEncryptionMetadataSet(status rbdEncryptionState) erro return nil } +// isEncrypted returns `true` if the rbdVolume is (or needs to be) encrypted. +func (rv *rbdVolume) isEncrypted() bool { + return rv.encryption != nil +} + // setupEncryption configures the metadata of the RBD image for encryption: // - the Data-Encryption-Key (DEK) will be generated stored for use by the KMS; // - the RBD image will be marked to support encryption in its metadata. func (rv *rbdVolume) setupEncryption(ctx context.Context) error { - err := util.StoreNewCryptoPassphrase(rv.VolID, rv.KMS) + err := util.StoreNewCryptoPassphrase(rv.VolID, rv.encryption.KMS) if err != nil { util.ErrorLog(ctx, "failed to save encryption passphrase for "+ "image %s: %s", rv.String(), err) @@ -103,7 +108,7 @@ func (rv *rbdVolume) setupEncryption(ctx context.Context) error { } func (rv *rbdVolume) encryptDevice(ctx context.Context, devicePath string) error { - passphrase, err := util.GetCryptoPassphrase(rv.VolID, rv.KMS) + passphrase, err := util.GetCryptoPassphrase(rv.VolID, rv.encryption.KMS) if err != nil { util.ErrorLog(ctx, "failed to get crypto passphrase for %s: %v", rv.String(), err) @@ -126,7 +131,7 @@ func (rv *rbdVolume) encryptDevice(ctx context.Context, devicePath string) error } func (rv *rbdVolume) openEncryptedDevice(ctx context.Context, devicePath string) (string, error) { - passphrase, err := util.GetCryptoPassphrase(rv.VolID, rv.KMS) + passphrase, err := util.GetCryptoPassphrase(rv.VolID, rv.encryption.KMS) if err != nil { util.ErrorLog(ctx, "failed to get passphrase for encrypted device %s: %v", rv.String(), err) @@ -175,21 +180,29 @@ func (rv *rbdVolume) initKMS(ctx context.Context, volOptions, credentials map[st return nil } - rv.Encrypted, err = strconv.ParseBool(encrypted) + isEncrypted, err := strconv.ParseBool(encrypted) if err != nil { return fmt.Errorf( "invalid value set in 'encrypted': %s (should be \"true\" or \"false\")", encrypted) - } else if !rv.Encrypted { + } else if !isEncrypted { return nil } - // deliberately ignore if parsing failed as GetKMS will return default - // implementation of kmsID is empty - kmsID := volOptions["encryptionKMSID"] - rv.KMS, err = util.GetKMS(rv.Owner, kmsID, credentials) + err = rv.setKMS(volOptions["encryptionKMSID"], credentials) if err != nil { return fmt.Errorf("invalid encryption kms configuration: %w", err) } return nil } + +func (rv *rbdVolume) setKMS(kmsID string, credentials map[string]string) error { + kms, err := util.GetKMS(rv.Owner, kmsID, credentials) + if err != nil { + return err + } + + rv.encryption = &util.VolumeEncryption{KMS: kms} + + return nil +} diff --git a/internal/rbd/nodeserver.go b/internal/rbd/nodeserver.go index a4430f08a..87fb32bfc 100644 --- a/internal/rbd/nodeserver.go +++ b/internal/rbd/nodeserver.go @@ -291,7 +291,7 @@ func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVo util.DebugLog(ctx, "rbd image: %s/%s was successfully mapped at %s\n", req.GetVolumeId(), volOptions.Pool, devicePath) - if volOptions.Encrypted { + if volOptions.isEncrypted() { devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath) if err != nil { return transaction, err diff --git a/internal/rbd/rbd_attach.go b/internal/rbd/rbd_attach.go index 3d89f9fd3..943cb14f2 100644 --- a/internal/rbd/rbd_attach.go +++ b/internal/rbd/rbd_attach.go @@ -270,7 +270,7 @@ func createPath(ctx context.Context, volOpt *rbdVolume, cr *util.Credentials) (s util.WarningLog(ctx, "rbd: map error %v, rbd output: %s", err, stderr) // unmap rbd image if connection timeout if strings.Contains(err.Error(), rbdMapConnectionTimeout) { - detErr := detachRBDImageOrDeviceSpec(ctx, imagePath, true, isNbd, volOpt.Encrypted, volOpt.VolID, volOpt.UnmapOptions) + detErr := detachRBDImageOrDeviceSpec(ctx, imagePath, true, isNbd, volOpt.isEncrypted(), volOpt.VolID, volOpt.UnmapOptions) if detErr != nil { util.WarningLog(ctx, "rbd: %s unmap error %v", imagePath, detErr) } diff --git a/internal/rbd/rbd_journal.go b/internal/rbd/rbd_journal.go index a39f5c558..734599aba 100644 --- a/internal/rbd/rbd_journal.go +++ b/internal/rbd/rbd_journal.go @@ -233,8 +233,8 @@ func (rv *rbdVolume) Exists(ctx context.Context, parentVol *rbdVolume) (bool, er } kmsID := "" - if rv.Encrypted { - kmsID = rv.KMS.GetID() + if rv.isEncrypted() { + kmsID = rv.encryption.KMS.GetID() } j, err := volJournal.Connect(rv.Monitors, rv.RadosNamespace, rv.conn.Creds) @@ -410,8 +410,8 @@ func reserveVol(ctx context.Context, rbdVol *rbdVolume, rbdSnap *rbdSnapshot, cr } kmsID := "" - if rbdVol.Encrypted { - kmsID = rbdVol.KMS.GetID() + if rbdVol.isEncrypted() { + kmsID = rbdVol.encryption.KMS.GetID() } j, err := volJournal.Connect(rbdVol.Monitors, rbdVol.RadosNamespace, cr) diff --git a/internal/rbd/rbd_util.go b/internal/rbd/rbd_util.go index 7dcf76523..88149e5b0 100644 --- a/internal/rbd/rbd_util.go +++ b/internal/rbd/rbd_util.go @@ -98,11 +98,10 @@ type rbdVolume struct { MonValueFromSecret string `json:"monValueFromSecret"` VolSize int64 `json:"volSize"` DisableInUseChecks bool `json:"disableInUseChecks"` - Encrypted bool readOnly bool Primary bool ThickProvision bool - KMS util.EncryptionKMS + encryption *util.VolumeEncryption // Owner is the creator (tenant, Kubernetes Namespace) of the volume. Owner string CreatedAt *timestamp.Timestamp @@ -167,8 +166,8 @@ func (rv *rbdVolume) Destroy() { if rv.conn != nil { rv.conn.Destroy() } - if rv.KMS != nil { - rv.KMS.Destroy() + if rv.isEncrypted() { + rv.encryption.Destroy() } } @@ -834,8 +833,7 @@ func genVolFromVolID(ctx context.Context, volumeID string, cr *util.Credentials, rbdVol.Owner = imageAttributes.Owner if imageAttributes.KmsID != "" { - rbdVol.Encrypted = true - rbdVol.KMS, err = util.GetKMS(rbdVol.Owner, imageAttributes.KmsID, secrets) + err = rbdVol.setKMS(imageAttributes.KmsID, secrets) if err != nil { return rbdVol, err } @@ -1168,7 +1166,7 @@ func stashRBDImageMetadata(volOptions *rbdVolume, path string) error { Pool: volOptions.Pool, RadosNamespace: volOptions.RadosNamespace, ImageName: volOptions.RbdImageName, - Encrypted: volOptions.Encrypted, + Encrypted: volOptions.isEncrypted(), UnmapOptions: volOptions.UnmapOptions, } diff --git a/internal/util/crypto.go b/internal/util/crypto.go index 82e1feee4..4a3e08a81 100644 --- a/internal/util/crypto.go +++ b/internal/util/crypto.go @@ -51,6 +51,22 @@ const ( defaultConfigMapToRead = "csi-kms-connection-details" ) +type VolumeEncryption struct { + KMS EncryptionKMS +} + +// NewVolumeEncryption creates a new instance of VolumeEncryption. +func NewVolumeEncryption(kms EncryptionKMS) (*VolumeEncryption, error) { + ve := &VolumeEncryption{KMS: kms} + + return ve, nil +} + +// Destroy frees any resources that the VolumeEncryption instance allocated. +func (ve *VolumeEncryption) Destroy() { + ve.KMS.Destroy() +} + // EncryptionKMS provides external Key Management System for encryption // passphrases storage. type EncryptionKMS interface { diff --git a/internal/util/secretskms.go b/internal/util/secretskms.go index 9d853c0f4..e6dc810ea 100644 --- a/internal/util/secretskms.go +++ b/internal/util/secretskms.go @@ -18,7 +18,6 @@ package util import ( "errors" - "fmt" ) const ( @@ -27,10 +26,6 @@ const ( // Default KMS type defaultKMSType = "default" - - // kmsTypeSecretsMetadata is the SecretsKMS with per-volume encryption, - // where the DEK is stored in the metadata of the volume itself. - kmsTypeSecretsMetadata = "metadata" ) // SecretsKMS is default KMS implementation that means no KMS is in use. @@ -59,19 +54,19 @@ func (kms SecretsKMS) Destroy() { // nothing to do } -// FetchDEK returns passphrase from Kubernetes secrets. -func (kms SecretsKMS) FetchDEK(key string) (string, error) { +// GetPassphrase returns passphrase from Kubernetes secrets. +func (kms SecretsKMS) GetPassphrase(key string) (string, error) { return kms.passphrase, nil } -// StoreDEK does nothing, as there is no passphrase per key (volume), so +// SavePassphrase does nothing, as there is no passphrase per key (volume), so // no need to store is anywhere. -func (kms SecretsKMS) StoreDEK(key, value string) error { +func (kms SecretsKMS) SavePassphrase(key, value string) error { return nil } -// RemoveDEK is doing nothing as no new passphrases are saved with +// DeletePassphrase is doing nothing as no new passphrases are saved with // SecretsKMS. -func (kms SecretsKMS) RemoveDEK(key string) error { +func (kms SecretsKMS) DeletePassphrase(key string) error { return nil }