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) {
|
func buildCreateVolumeResponse(ctx context.Context, req *csi.CreateVolumeRequest, rbdVol *rbdVolume) (*csi.CreateVolumeResponse, error) {
|
||||||
if rbdVol.Encrypted {
|
if rbdVol.isEncrypted() {
|
||||||
err := rbdVol.setupEncryption(ctx)
|
err := rbdVol.setupEncryption(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.ErrorLog(ctx, err.Error())
|
util.ErrorLog(ctx, err.Error())
|
||||||
@ -516,7 +516,7 @@ func (cs *ControllerServer) createBackingImage(ctx context.Context, cr *util.Cre
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rbdVol.Encrypted {
|
if rbdVol.isEncrypted() {
|
||||||
err = rbdVol.setupEncryption(ctx)
|
err = rbdVol.setupEncryption(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.ErrorLog(ctx, "failed to setup encroption for image %s: %v", rbdVol, err)
|
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())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if rbdVol.Encrypted {
|
if rbdVol.isEncrypted() {
|
||||||
if err = rbdVol.KMS.DeletePassphrase(rbdVol.VolID); err != nil {
|
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)
|
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
|
// 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, "+
|
return nil, status.Errorf(codes.Unimplemented, "source Volume %s is encrypted, "+
|
||||||
"snapshotting is not supported currently", rbdVol.VolID)
|
"snapshotting is not supported currently", rbdVol.VolID)
|
||||||
}
|
}
|
||||||
@ -1124,7 +1124,7 @@ func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if rbdVol.Encrypted {
|
if rbdVol.isEncrypted() {
|
||||||
return nil, status.Errorf(codes.InvalidArgument, "encrypted volumes do not support resize (%s)",
|
return nil, status.Errorf(codes.InvalidArgument, "encrypted volumes do not support resize (%s)",
|
||||||
rbdVol)
|
rbdVol)
|
||||||
}
|
}
|
||||||
|
@ -81,11 +81,16 @@ func (rv *rbdVolume) ensureEncryptionMetadataSet(status rbdEncryptionState) erro
|
|||||||
return nil
|
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:
|
// 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 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.
|
// - the RBD image will be marked to support encryption in its metadata.
|
||||||
func (rv *rbdVolume) setupEncryption(ctx context.Context) error {
|
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 {
|
if err != nil {
|
||||||
util.ErrorLog(ctx, "failed to save encryption passphrase for "+
|
util.ErrorLog(ctx, "failed to save encryption passphrase for "+
|
||||||
"image %s: %s", rv.String(), err)
|
"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 {
|
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 {
|
if err != nil {
|
||||||
util.ErrorLog(ctx, "failed to get crypto passphrase for %s: %v",
|
util.ErrorLog(ctx, "failed to get crypto passphrase for %s: %v",
|
||||||
rv.String(), err)
|
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) {
|
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 {
|
if err != nil {
|
||||||
util.ErrorLog(ctx, "failed to get passphrase for encrypted device %s: %v",
|
util.ErrorLog(ctx, "failed to get passphrase for encrypted device %s: %v",
|
||||||
rv.String(), err)
|
rv.String(), err)
|
||||||
@ -175,21 +180,29 @@ func (rv *rbdVolume) initKMS(ctx context.Context, volOptions, credentials map[st
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rv.Encrypted, err = strconv.ParseBool(encrypted)
|
isEncrypted, err := strconv.ParseBool(encrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid value set in 'encrypted': %s (should be \"true\" or \"false\")", encrypted)
|
"invalid value set in 'encrypted': %s (should be \"true\" or \"false\")", encrypted)
|
||||||
} else if !rv.Encrypted {
|
} else if !isEncrypted {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliberately ignore if parsing failed as GetKMS will return default
|
err = rv.setKMS(volOptions["encryptionKMSID"], credentials)
|
||||||
// implementation of kmsID is empty
|
|
||||||
kmsID := volOptions["encryptionKMSID"]
|
|
||||||
rv.KMS, err = util.GetKMS(rv.Owner, kmsID, credentials)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid encryption kms configuration: %w", err)
|
return fmt.Errorf("invalid encryption kms configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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",
|
util.DebugLog(ctx, "rbd image: %s/%s was successfully mapped at %s\n",
|
||||||
req.GetVolumeId(), volOptions.Pool, devicePath)
|
req.GetVolumeId(), volOptions.Pool, devicePath)
|
||||||
|
|
||||||
if volOptions.Encrypted {
|
if volOptions.isEncrypted() {
|
||||||
devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath)
|
devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return transaction, err
|
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)
|
util.WarningLog(ctx, "rbd: map error %v, rbd output: %s", err, stderr)
|
||||||
// unmap rbd image if connection timeout
|
// unmap rbd image if connection timeout
|
||||||
if strings.Contains(err.Error(), rbdMapConnectionTimeout) {
|
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 {
|
if detErr != nil {
|
||||||
util.WarningLog(ctx, "rbd: %s unmap error %v", imagePath, detErr)
|
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 := ""
|
kmsID := ""
|
||||||
if rv.Encrypted {
|
if rv.isEncrypted() {
|
||||||
kmsID = rv.KMS.GetID()
|
kmsID = rv.encryption.KMS.GetID()
|
||||||
}
|
}
|
||||||
|
|
||||||
j, err := volJournal.Connect(rv.Monitors, rv.RadosNamespace, rv.conn.Creds)
|
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 := ""
|
kmsID := ""
|
||||||
if rbdVol.Encrypted {
|
if rbdVol.isEncrypted() {
|
||||||
kmsID = rbdVol.KMS.GetID()
|
kmsID = rbdVol.encryption.KMS.GetID()
|
||||||
}
|
}
|
||||||
|
|
||||||
j, err := volJournal.Connect(rbdVol.Monitors, rbdVol.RadosNamespace, cr)
|
j, err := volJournal.Connect(rbdVol.Monitors, rbdVol.RadosNamespace, cr)
|
||||||
|
@ -98,11 +98,10 @@ type rbdVolume struct {
|
|||||||
MonValueFromSecret string `json:"monValueFromSecret"`
|
MonValueFromSecret string `json:"monValueFromSecret"`
|
||||||
VolSize int64 `json:"volSize"`
|
VolSize int64 `json:"volSize"`
|
||||||
DisableInUseChecks bool `json:"disableInUseChecks"`
|
DisableInUseChecks bool `json:"disableInUseChecks"`
|
||||||
Encrypted bool
|
|
||||||
readOnly bool
|
readOnly bool
|
||||||
Primary bool
|
Primary bool
|
||||||
ThickProvision bool
|
ThickProvision bool
|
||||||
KMS util.EncryptionKMS
|
encryption *util.VolumeEncryption
|
||||||
// Owner is the creator (tenant, Kubernetes Namespace) of the volume.
|
// Owner is the creator (tenant, Kubernetes Namespace) of the volume.
|
||||||
Owner string
|
Owner string
|
||||||
CreatedAt *timestamp.Timestamp
|
CreatedAt *timestamp.Timestamp
|
||||||
@ -167,8 +166,8 @@ func (rv *rbdVolume) Destroy() {
|
|||||||
if rv.conn != nil {
|
if rv.conn != nil {
|
||||||
rv.conn.Destroy()
|
rv.conn.Destroy()
|
||||||
}
|
}
|
||||||
if rv.KMS != nil {
|
if rv.isEncrypted() {
|
||||||
rv.KMS.Destroy()
|
rv.encryption.Destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,8 +833,7 @@ func genVolFromVolID(ctx context.Context, volumeID string, cr *util.Credentials,
|
|||||||
rbdVol.Owner = imageAttributes.Owner
|
rbdVol.Owner = imageAttributes.Owner
|
||||||
|
|
||||||
if imageAttributes.KmsID != "" {
|
if imageAttributes.KmsID != "" {
|
||||||
rbdVol.Encrypted = true
|
err = rbdVol.setKMS(imageAttributes.KmsID, secrets)
|
||||||
rbdVol.KMS, err = util.GetKMS(rbdVol.Owner, imageAttributes.KmsID, secrets)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rbdVol, err
|
return rbdVol, err
|
||||||
}
|
}
|
||||||
@ -1168,7 +1166,7 @@ func stashRBDImageMetadata(volOptions *rbdVolume, path string) error {
|
|||||||
Pool: volOptions.Pool,
|
Pool: volOptions.Pool,
|
||||||
RadosNamespace: volOptions.RadosNamespace,
|
RadosNamespace: volOptions.RadosNamespace,
|
||||||
ImageName: volOptions.RbdImageName,
|
ImageName: volOptions.RbdImageName,
|
||||||
Encrypted: volOptions.Encrypted,
|
Encrypted: volOptions.isEncrypted(),
|
||||||
UnmapOptions: volOptions.UnmapOptions,
|
UnmapOptions: volOptions.UnmapOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,22 @@ const (
|
|||||||
defaultConfigMapToRead = "csi-kms-connection-details"
|
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
|
// EncryptionKMS provides external Key Management System for encryption
|
||||||
// passphrases storage.
|
// passphrases storage.
|
||||||
type EncryptionKMS interface {
|
type EncryptionKMS interface {
|
||||||
|
@ -18,7 +18,6 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -27,10 +26,6 @@ const (
|
|||||||
|
|
||||||
// Default KMS type
|
// Default KMS type
|
||||||
defaultKMSType = "default"
|
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.
|
// SecretsKMS is default KMS implementation that means no KMS is in use.
|
||||||
@ -59,19 +54,19 @@ func (kms SecretsKMS) Destroy() {
|
|||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchDEK returns passphrase from Kubernetes secrets.
|
// GetPassphrase returns passphrase from Kubernetes secrets.
|
||||||
func (kms SecretsKMS) FetchDEK(key string) (string, error) {
|
func (kms SecretsKMS) GetPassphrase(key string) (string, error) {
|
||||||
return kms.passphrase, nil
|
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.
|
// no need to store is anywhere.
|
||||||
func (kms SecretsKMS) StoreDEK(key, value string) error {
|
func (kms SecretsKMS) SavePassphrase(key, value string) error {
|
||||||
return nil
|
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.
|
// SecretsKMS.
|
||||||
func (kms SecretsKMS) RemoveDEK(key string) error {
|
func (kms SecretsKMS) DeletePassphrase(key string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user