mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-03-06 07:29:29 +00:00
rbd: fix encrypted PVC with metadata KMS cannot be deleted
Signed-off-by: Zerotens <12968743+zerotens@users.noreply.github.com>
(cherry picked from commit 5b587c9484
)
# Conflicts:
# PendingReleaseNotes.md
This commit is contained in:
parent
63d64a8558
commit
60d940137b
@ -54,8 +54,11 @@ func newDefaultTestDummy() EncryptionKMS {
|
|||||||
|
|
||||||
func newSecretsMetadataTestDummy() EncryptionKMS {
|
func newSecretsMetadataTestDummy() EncryptionKMS {
|
||||||
smKMS := secretsMetadataKMS{}
|
smKMS := secretsMetadataKMS{}
|
||||||
smKMS.secretsKMS = secretsKMS{passphrase: base64.URLEncoding.EncodeToString(
|
smKMS.Secrets = map[string]string{
|
||||||
[]byte("test dummy passphrase"))}
|
encryptionPassphraseKey: "test dummy passphrase",
|
||||||
|
}
|
||||||
|
smKMS.Tenant = "tenant"
|
||||||
|
smKMS.Config = nil
|
||||||
|
|
||||||
return smKMS
|
return smKMS
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ func (kms secretsKMS) RemoveDEK(ctx context.Context, key string) error {
|
|||||||
// secretsMetadataKMS is a KMS based on the secretKMS, but stores the
|
// secretsMetadataKMS is a KMS based on the secretKMS, but stores the
|
||||||
// Data-Encryption-Key (DEK) in the metadata of the volume.
|
// Data-Encryption-Key (DEK) in the metadata of the volume.
|
||||||
type secretsMetadataKMS struct {
|
type secretsMetadataKMS struct {
|
||||||
secretsKMS
|
ProviderInitArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = RegisterProvider(Provider{
|
var _ = RegisterProvider(Provider{
|
||||||
@ -109,28 +109,9 @@ var _ = RegisterProvider(Provider{
|
|||||||
// so that the passphrase from the user provided or StorageClass secrets can be used
|
// so that the passphrase from the user provided or StorageClass secrets can be used
|
||||||
// for encrypting/decrypting DEKs that are stored in a detached DEKStore.
|
// for encrypting/decrypting DEKs that are stored in a detached DEKStore.
|
||||||
func initSecretsMetadataKMS(args ProviderInitArgs) (EncryptionKMS, error) {
|
func initSecretsMetadataKMS(args ProviderInitArgs) (EncryptionKMS, error) {
|
||||||
var (
|
var smKMS secretsMetadataKMS
|
||||||
smKMS secretsMetadataKMS
|
|
||||||
encryptionPassphrase string
|
|
||||||
ok bool
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
encryptionPassphrase, err = smKMS.fetchEncryptionPassphrase(
|
smKMS.ProviderInitArgs = args
|
||||||
args.Config, args.Tenant)
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, errConfigOptionMissing) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// if 'userSecret' option is not specified, fetch encryptionPassphrase
|
|
||||||
// from storageclass secrets.
|
|
||||||
encryptionPassphrase, ok = args.Secrets[encryptionPassphraseKey]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"missing %q in storageclass secret", encryptionPassphraseKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
smKMS.secretsKMS = secretsKMS{passphrase: encryptionPassphrase}
|
|
||||||
|
|
||||||
return smKMS, nil
|
return smKMS, nil
|
||||||
}
|
}
|
||||||
@ -184,7 +165,45 @@ func (kms secretsMetadataKMS) fetchEncryptionPassphrase(
|
|||||||
|
|
||||||
// Destroy frees all used resources.
|
// Destroy frees all used resources.
|
||||||
func (kms secretsMetadataKMS) Destroy() {
|
func (kms secretsMetadataKMS) Destroy() {
|
||||||
kms.secretsKMS.Destroy()
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchDEK returns passphrase from Kubernetes secrets.
|
||||||
|
func (kms secretsMetadataKMS) FetchDEK(ctx context.Context, key string) (string, error) {
|
||||||
|
var (
|
||||||
|
encryptionPassphrase string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
encryptionPassphrase, err = kms.fetchEncryptionPassphrase(
|
||||||
|
kms.Config, kms.Tenant)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, errConfigOptionMissing) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// if 'userSecret' option is not specified, fetch encryptionPassphrase
|
||||||
|
// from storageclass secrets.
|
||||||
|
encryptionPassphrase, ok = kms.Secrets[encryptionPassphraseKey]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf(
|
||||||
|
"missing %q in storageclass secret", encryptionPassphraseKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encryptionPassphrase, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreDEK does nothing, as there is no passphrase per key (volume), so
|
||||||
|
// no need to store is anywhere.
|
||||||
|
func (kms secretsMetadataKMS) StoreDEK(ctx context.Context, key, value string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveDEK is doing nothing as no new passphrases are saved with
|
||||||
|
// secretsKMS.
|
||||||
|
func (kms secretsMetadataKMS) RemoveDEK(ctx context.Context, key string) error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kms secretsMetadataKMS) RequiresDEKStore() DEKStoreType {
|
func (kms secretsMetadataKMS) RequiresDEKStore() DEKStoreType {
|
||||||
@ -208,7 +227,7 @@ type encryptedMetedataDEK struct {
|
|||||||
// nonce that was used for encrypting.
|
// nonce that was used for encrypting.
|
||||||
func (kms secretsMetadataKMS) EncryptDEK(ctx context.Context, volumeID, plainDEK string) (string, error) {
|
func (kms secretsMetadataKMS) EncryptDEK(ctx context.Context, volumeID, plainDEK string) (string, error) {
|
||||||
// use the passphrase from the secretKMS
|
// use the passphrase from the secretKMS
|
||||||
passphrase, err := kms.secretsKMS.FetchDEK(ctx, volumeID)
|
passphrase, err := kms.FetchDEK(ctx, volumeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get passphrase: %w", err)
|
return "", fmt.Errorf("failed to get passphrase: %w", err)
|
||||||
}
|
}
|
||||||
@ -238,7 +257,7 @@ func (kms secretsMetadataKMS) EncryptDEK(ctx context.Context, volumeID, plainDEK
|
|||||||
// fetches secretKMS passphrase to decrypt the DEK.
|
// fetches secretKMS passphrase to decrypt the DEK.
|
||||||
func (kms secretsMetadataKMS) DecryptDEK(ctx context.Context, volumeID, encryptedDEK string) (string, error) {
|
func (kms secretsMetadataKMS) DecryptDEK(ctx context.Context, volumeID, encryptedDEK string) (string, error) {
|
||||||
// use the passphrase from the secretKMS
|
// use the passphrase from the secretKMS
|
||||||
passphrase, err := kms.secretsKMS.FetchDEK(ctx, volumeID)
|
passphrase, err := kms.FetchDEK(ctx, volumeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get passphrase: %w", err)
|
return "", fmt.Errorf("failed to get passphrase: %w", err)
|
||||||
}
|
}
|
||||||
@ -265,7 +284,7 @@ func (kms secretsMetadataKMS) DecryptDEK(ctx context.Context, volumeID, encrypte
|
|||||||
|
|
||||||
func (kms secretsMetadataKMS) GetSecret(ctx context.Context, volumeID string) (string, error) {
|
func (kms secretsMetadataKMS) GetSecret(ctx context.Context, volumeID string) (string, error) {
|
||||||
// use the passphrase from the secretKMS
|
// use the passphrase from the secretKMS
|
||||||
return kms.secretsKMS.FetchDEK(ctx, volumeID)
|
return kms.FetchDEK(ctx, volumeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateCipher returns a AEAD cipher based on a passphrase and salt
|
// generateCipher returns a AEAD cipher based on a passphrase and salt
|
||||||
|
@ -70,15 +70,7 @@ func TestInitSecretsMetadataKMS(t *testing.T) {
|
|||||||
Secrets: map[string]string{},
|
Secrets: map[string]string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// passphrase it not set, init should fail
|
|
||||||
kms, err := initSecretsMetadataKMS(args)
|
kms, err := initSecretsMetadataKMS(args)
|
||||||
require.Error(t, err)
|
|
||||||
require.Nil(t, kms)
|
|
||||||
|
|
||||||
// set a passphrase to get a working KMS
|
|
||||||
args.Secrets[encryptionPassphraseKey] = "my-passphrase-from-kubernetes"
|
|
||||||
|
|
||||||
kms, err = initSecretsMetadataKMS(args)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, kms)
|
require.NotNil(t, kms)
|
||||||
require.Equal(t, DEKStoreMetadata, kms.RequiresDEKStore())
|
require.Equal(t, DEKStoreMetadata, kms.RequiresDEKStore())
|
||||||
@ -86,25 +78,40 @@ func TestInitSecretsMetadataKMS(t *testing.T) {
|
|||||||
|
|
||||||
func TestWorkflowSecretsMetadataKMS(t *testing.T) {
|
func TestWorkflowSecretsMetadataKMS(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
secrets := map[string]string{
|
|
||||||
encryptionPassphraseKey: "my-passphrase-from-kubernetes",
|
|
||||||
}
|
|
||||||
args := ProviderInitArgs{
|
args := ProviderInitArgs{
|
||||||
Tenant: "tenant",
|
Tenant: "tenant",
|
||||||
Config: nil,
|
Config: nil,
|
||||||
Secrets: secrets,
|
Secrets: map[string]string{},
|
||||||
}
|
}
|
||||||
volumeID := "csi-vol-1b00f5f8-b1c1-11e9-8421-9243c1f659f0"
|
volumeID := "csi-vol-1b00f5f8-b1c1-11e9-8421-9243c1f659f0"
|
||||||
|
|
||||||
kms, err := initSecretsMetadataKMS(args)
|
kms, err := initSecretsMetadataKMS(args)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, kms)
|
require.NotNil(t, kms)
|
||||||
|
require.Equal(t, DEKStoreMetadata, kms.RequiresDEKStore())
|
||||||
|
|
||||||
// plainDEK is the (LUKS) passphrase for the volume
|
// plainDEK is the (LUKS) passphrase for the volume
|
||||||
plainDEK := "usually created with generateNewEncryptionPassphrase()"
|
plainDEK := "usually created with generateNewEncryptionPassphrase()"
|
||||||
|
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
// with missing encryptionPassphraseKey, encrypting should fail
|
||||||
|
_, err = kms.EncryptDEK(ctx, volumeID, plainDEK)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
secrets := map[string]string{
|
||||||
|
encryptionPassphraseKey: "my-passphrase-from-kubernetes",
|
||||||
|
}
|
||||||
|
args = ProviderInitArgs{
|
||||||
|
Tenant: "tenant",
|
||||||
|
Config: nil,
|
||||||
|
Secrets: secrets,
|
||||||
|
}
|
||||||
|
|
||||||
|
kms, err = initSecretsMetadataKMS(args)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, kms)
|
||||||
|
|
||||||
encryptedDEK, err := kms.EncryptDEK(ctx, volumeID, plainDEK)
|
encryptedDEK, err := kms.EncryptDEK(ctx, volumeID, plainDEK)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEqual(t, "", encryptedDEK)
|
require.NotEqual(t, "", encryptedDEK)
|
||||||
|
Loading…
Reference in New Issue
Block a user