mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-26 08:10:20 +00:00
rbd: add user secret based metadata encryption
This commit adds capability to `metadata` encryption to be able to fetch `encryptionPassphrase` from user specified secret name and namespace(if not specified, will default to namespace where PVC was created). This behavior is followed if `secretName` key is found in the encryption configuration else defaults to fetching `encryptionPassphrase` from storageclass secrets. Closes: 2107 Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
parent
c4060b8aa2
commit
3352d4aabd
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -26,6 +27,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"golang.org/x/crypto/scrypt"
|
"golang.org/x/crypto/scrypt"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -38,6 +40,13 @@ const (
|
|||||||
// kmsTypeSecretsMetadata is the SecretsKMS with per-volume encryption,
|
// kmsTypeSecretsMetadata is the SecretsKMS with per-volume encryption,
|
||||||
// where the DEK is stored in the metadata of the volume itself.
|
// where the DEK is stored in the metadata of the volume itself.
|
||||||
kmsTypeSecretsMetadata = "metadata"
|
kmsTypeSecretsMetadata = "metadata"
|
||||||
|
|
||||||
|
// metadataSecretNameKey contains the key which corresponds to the
|
||||||
|
// kubernetes secret name from where encryptionPassphrase is feteched
|
||||||
|
metadataSecretNameKey = "secretName"
|
||||||
|
// metadataSecretNamespaceKey contains the key which corresponds to the
|
||||||
|
// kubernetes secret namespace from where encryptionPassphrase is feteched
|
||||||
|
metadataSecretNamespaceKey = "secretNamespace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecretsKMS is default KMS implementation that means no KMS is in use.
|
// SecretsKMS is default KMS implementation that means no KMS is in use.
|
||||||
@ -91,26 +100,77 @@ var _ = RegisterKMSProvider(KMSProvider{
|
|||||||
Initializer: initSecretsMetadataKMS,
|
Initializer: initSecretsMetadataKMS,
|
||||||
})
|
})
|
||||||
|
|
||||||
// initSecretsMetadataKMS initializes a SecretsMetadataKMS that wraps a
|
// initSecretsMetadataKMS initializes a SecretsMetadataKMS that wraps a SecretsKMS,
|
||||||
// SecretsKMS, so that the passphrase from the 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 KMSInitializerArgs) (EncryptionKMS, error) {
|
func initSecretsMetadataKMS(args KMSInitializerArgs) (EncryptionKMS, error) {
|
||||||
eKMS, err := initSecretsKMS(args.Secrets)
|
var (
|
||||||
|
smKMS SecretsMetadataKMS
|
||||||
|
encryptionPassphrase string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
encryptionPassphrase, err = smKMS.fetchEncryptionPassphrase(
|
||||||
|
args.Config, args.Tenant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if !errors.Is(err, errConfigOptionMissing) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// if 'userSecret' option is not specified, fetch encryptionPassphrase
|
||||||
sKMS, ok := eKMS.(SecretsKMS)
|
// from storageclass secrets.
|
||||||
|
encryptionPassphrase, ok = args.Secrets[encryptionPassphraseKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to convert %T to SecretsKMS", eKMS)
|
return nil, fmt.Errorf(
|
||||||
|
"missing %q in storageclass secret", encryptionPassphraseKey)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
smKMS := SecretsMetadataKMS{}
|
smKMS.SecretsKMS = SecretsKMS{passphrase: encryptionPassphrase}
|
||||||
smKMS.SecretsKMS = sKMS
|
|
||||||
|
|
||||||
return smKMS, nil
|
return smKMS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetchEncryptionPassphrase fetches encryptionPassphrase from user provided secret.
|
||||||
|
func (kms SecretsMetadataKMS) fetchEncryptionPassphrase(
|
||||||
|
config map[string]interface{},
|
||||||
|
defaultNamespace string) (string, error) {
|
||||||
|
var (
|
||||||
|
secretName string
|
||||||
|
secretNamespace string
|
||||||
|
)
|
||||||
|
|
||||||
|
err := setConfigString(&secretName, config, metadataSecretNameKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = setConfigString(&secretNamespace, config, metadataSecretNamespaceKey)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, errConfigOptionMissing) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// if 'secretNamespace' option is not specified, defaults to namespace in
|
||||||
|
// which PVC was created
|
||||||
|
secretNamespace = defaultNamespace
|
||||||
|
}
|
||||||
|
|
||||||
|
c := NewK8sClient()
|
||||||
|
secret, err := c.CoreV1().Secrets(secretNamespace).Get(context.TODO(),
|
||||||
|
secretName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get Secret %s/%s: %w",
|
||||||
|
secretNamespace, secretName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
passphraseValue, ok := secret.Data[encryptionPassphraseKey]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("missing %q in Secret %s/%s",
|
||||||
|
encryptionPassphraseKey, secretNamespace, secretName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(passphraseValue), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Destroy frees all used resources.
|
// Destroy frees all used resources.
|
||||||
func (kms SecretsMetadataKMS) Destroy() {
|
func (kms SecretsMetadataKMS) Destroy() {
|
||||||
kms.SecretsKMS.Destroy()
|
kms.SecretsKMS.Destroy()
|
||||||
|
Loading…
Reference in New Issue
Block a user