mirror of
https://github.com/minio/minio.git
synced 2025-01-27 06:33:18 -05:00
prepare SSE-S3 metadata parsing for K/V data key store (#8259)
This commit allows the MinIO server to parse the metadata if: - either the `X-Minio-Internal-Server-Side-Encryption-S3-Key-Id` and the `X-Minio-Internal-Server-Side-Encryption-S3-Kms-Sealed-Key` entries are present. - or *both* headers are not present. This is in service to support a K/V data key store.
This commit is contained in:
parent
8dc897b5f5
commit
e34369c860
@ -17,6 +17,7 @@ package crypto
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
@ -119,28 +120,46 @@ func CreateMultipartMetadata(metadata map[string]string) map[string]string {
|
|||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMetadata encodes the keyID, the sealed kms data key and the sealed key
|
// CreateMetadata encodes the sealed object key into the metadata and returns
|
||||||
// into the metadata and returns the modified metadata. It allocates a new
|
// the modified metadata. If the keyID and the kmsKey is not empty it encodes
|
||||||
// metadata map if metadata is nil.
|
// both into the metadata as well. It allocates a new metadata map if metadata
|
||||||
|
// is nil.
|
||||||
func (s3) CreateMetadata(metadata map[string]string, keyID string, kmsKey []byte, sealedKey SealedKey) map[string]string {
|
func (s3) CreateMetadata(metadata map[string]string, keyID string, kmsKey []byte, sealedKey SealedKey) map[string]string {
|
||||||
if sealedKey.Algorithm != SealAlgorithm {
|
if sealedKey.Algorithm != SealAlgorithm {
|
||||||
logger.CriticalIf(context.Background(), fmt.Errorf("The seal algorithm '%s' is invalid for SSE-S3", sealedKey.Algorithm))
|
logger.CriticalIf(context.Background(), fmt.Errorf("The seal algorithm '%s' is invalid for SSE-S3", sealedKey.Algorithm))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There are two possibilites:
|
||||||
|
// - We use a KMS -> There must be non-empty key ID and a KMS data key.
|
||||||
|
// - We use a K/V -> There must be no key ID and no KMS data key.
|
||||||
|
// Otherwise, the caller has passed an invalid argument combination.
|
||||||
|
if keyID == "" && len(kmsKey) != 0 {
|
||||||
|
logger.CriticalIf(context.Background(), errors.New("The key ID must not be empty if a KMS data key is present"))
|
||||||
|
}
|
||||||
|
if keyID != "" && len(kmsKey) == 0 {
|
||||||
|
logger.CriticalIf(context.Background(), errors.New("The KMS data key must not be empty if a key ID is present"))
|
||||||
|
}
|
||||||
|
|
||||||
if metadata == nil {
|
if metadata == nil {
|
||||||
metadata = map[string]string{}
|
metadata = map[string]string{}
|
||||||
}
|
}
|
||||||
metadata[S3KMSKeyID] = keyID
|
|
||||||
metadata[SSESealAlgorithm] = sealedKey.Algorithm
|
metadata[SSESealAlgorithm] = sealedKey.Algorithm
|
||||||
metadata[SSEIV] = base64.StdEncoding.EncodeToString(sealedKey.IV[:])
|
metadata[SSEIV] = base64.StdEncoding.EncodeToString(sealedKey.IV[:])
|
||||||
metadata[S3SealedKey] = base64.StdEncoding.EncodeToString(sealedKey.Key[:])
|
metadata[S3SealedKey] = base64.StdEncoding.EncodeToString(sealedKey.Key[:])
|
||||||
|
if len(kmsKey) > 0 && keyID != "" { // We use a KMS -> Store key ID and sealed KMS data key.
|
||||||
|
metadata[S3KMSKeyID] = keyID
|
||||||
metadata[S3KMSSealedKey] = base64.StdEncoding.EncodeToString(kmsKey)
|
metadata[S3KMSSealedKey] = base64.StdEncoding.EncodeToString(kmsKey)
|
||||||
|
}
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseMetadata extracts all SSE-S3 related values from the object metadata
|
// ParseMetadata extracts all SSE-S3 related values from the object metadata
|
||||||
// and checks whether they are well-formed. It returns the KMS key-ID, the
|
// and checks whether they are well-formed. It returns the sealed object key
|
||||||
// sealed KMS key and the sealed object key on success.
|
// on success. If the metadata contains both, a KMS master key ID and a sealed
|
||||||
|
// KMS data key it returns both. If the metadata does not contain neither a
|
||||||
|
// KMS master key ID nor a sealed KMS data key it returns an empty keyID and
|
||||||
|
// KMS data key. Otherwise, it returns an error.
|
||||||
func (s3) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []byte, sealedKey SealedKey, err error) {
|
func (s3) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []byte, sealedKey SealedKey, err error) {
|
||||||
// Extract all required values from object metadata
|
// Extract all required values from object metadata
|
||||||
b64IV, ok := metadata[SSEIV]
|
b64IV, ok := metadata[SSEIV]
|
||||||
@ -155,12 +174,17 @@ func (s3) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []byte
|
|||||||
if !ok {
|
if !ok {
|
||||||
return keyID, kmsKey, sealedKey, Error{"The object metadata is missing the internal sealed key for SSE-S3"}
|
return keyID, kmsKey, sealedKey, Error{"The object metadata is missing the internal sealed key for SSE-S3"}
|
||||||
}
|
}
|
||||||
keyID, ok = metadata[S3KMSKeyID]
|
|
||||||
if !ok {
|
// There are two possibilites:
|
||||||
|
// - We use a KMS -> There must be a key ID and a KMS data key.
|
||||||
|
// - We use a K/V -> There must be no key ID and no KMS data key.
|
||||||
|
// Otherwise, the metadata is corrupted.
|
||||||
|
keyID, idPresent := metadata[S3KMSKeyID]
|
||||||
|
b64KMSSealedKey, kmsKeyPresent := metadata[S3KMSSealedKey]
|
||||||
|
if !idPresent && kmsKeyPresent {
|
||||||
return keyID, kmsKey, sealedKey, Error{"The object metadata is missing the internal KMS key-ID for SSE-S3"}
|
return keyID, kmsKey, sealedKey, Error{"The object metadata is missing the internal KMS key-ID for SSE-S3"}
|
||||||
}
|
}
|
||||||
b64KMSSealedKey, ok := metadata[S3KMSSealedKey]
|
if idPresent && !kmsKeyPresent {
|
||||||
if !ok {
|
|
||||||
return keyID, kmsKey, sealedKey, Error{"The object metadata is missing the internal sealed KMS data key for SSE-S3"}
|
return keyID, kmsKey, sealedKey, Error{"The object metadata is missing the internal sealed KMS data key for SSE-S3"}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,10 +200,12 @@ func (s3) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []byte
|
|||||||
if err != nil || len(encryptedKey) != 64 {
|
if err != nil || len(encryptedKey) != 64 {
|
||||||
return keyID, kmsKey, sealedKey, Error{"The internal sealed key for SSE-S3 is invalid"}
|
return keyID, kmsKey, sealedKey, Error{"The internal sealed key for SSE-S3 is invalid"}
|
||||||
}
|
}
|
||||||
|
if idPresent && kmsKeyPresent { // We are using a KMS -> parse the sealed KMS data key.
|
||||||
kmsKey, err = base64.StdEncoding.DecodeString(b64KMSSealedKey)
|
kmsKey, err = base64.StdEncoding.DecodeString(b64KMSSealedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return keyID, kmsKey, sealedKey, Error{"The internal sealed KMS data key for SSE-S3 is invalid"}
|
return keyID, kmsKey, sealedKey, Error{"The internal sealed KMS data key for SSE-S3 is invalid"}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealedKey.Algorithm = algorithm
|
sealedKey.Algorithm = algorithm
|
||||||
copy(sealedKey.IV[:], iv)
|
copy(sealedKey.IV[:], iv)
|
||||||
|
@ -130,7 +130,7 @@ var s3ParseMetadataTests = []struct {
|
|||||||
}, // 2
|
}, // 2
|
||||||
{
|
{
|
||||||
ExpectedErr: Error{"The object metadata is missing the internal KMS key-ID for SSE-S3"},
|
ExpectedErr: Error{"The object metadata is missing the internal KMS key-ID for SSE-S3"},
|
||||||
Metadata: map[string]string{SSEIV: "", SSESealAlgorithm: "", S3SealedKey: ""}, DataKey: []byte{}, KeyID: "", SealedKey: SealedKey{},
|
Metadata: map[string]string{SSEIV: "", SSESealAlgorithm: "", S3SealedKey: "", S3KMSSealedKey: "IAAF0b=="}, DataKey: []byte{}, KeyID: "", SealedKey: SealedKey{},
|
||||||
}, // 3
|
}, // 3
|
||||||
{
|
{
|
||||||
ExpectedErr: Error{"The object metadata is missing the internal sealed KMS data key for SSE-S3"},
|
ExpectedErr: Error{"The object metadata is missing the internal sealed KMS data key for SSE-S3"},
|
||||||
@ -287,7 +287,9 @@ var s3CreateMetadataTests = []struct {
|
|||||||
SealedDataKey []byte
|
SealedDataKey []byte
|
||||||
SealedKey SealedKey
|
SealedKey SealedKey
|
||||||
}{
|
}{
|
||||||
{KeyID: "", SealedDataKey: make([]byte, 48), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
|
||||||
|
{KeyID: "", SealedDataKey: nil, SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||||
|
{KeyID: "my-minio-key", SealedDataKey: make([]byte, 48), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||||
{KeyID: "cafebabe", SealedDataKey: make([]byte, 48), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
{KeyID: "cafebabe", SealedDataKey: make([]byte, 48), SealedKey: SealedKey{Algorithm: SealAlgorithm}},
|
||||||
{KeyID: "deadbeef", SealedDataKey: make([]byte, 32), SealedKey: SealedKey{IV: [32]byte{0xf7}, Key: [64]byte{0xea}, Algorithm: SealAlgorithm}},
|
{KeyID: "deadbeef", SealedDataKey: make([]byte, 32), SealedKey: SealedKey{IV: [32]byte{0xf7}, Key: [64]byte{0xea}, Algorithm: SealAlgorithm}},
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user