mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-18 02:50:30 +00:00
util: introduce VolumeEncryption type
Prepare for grouping encryption related functions together. The main rbdVolume object should not be cluttered with KMS or DEK procedures. Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
parent
aa52afff09
commit
d4076d6216
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user