kms: add support for MinKMS and remove some unused/broken code (#19368)

This commit adds support for MinKMS. Now, there are three KMS
implementations in `internal/kms`: Builtin, MinIO KES and MinIO KMS.

Adding another KMS integration required some cleanup. In particular:
 - Various KMS APIs that haven't been and are not used have been
   removed. A lot of the code was broken anyway.
 - Metrics are now monitored by the `kms.KMS` itself. For basic
   metrics this is simpler than collecting metrics for external
   servers. In particular, each KES server returns its own metrics
   and no cluster-level view.
 - The builtin KMS now uses the same en/decryption implemented by
   MinKMS and KES. It still supports decryption of the previous
   ciphertext format. It's backwards compatible.
 - Data encryption keys now include a master key version since MinKMS
   supports multiple versions (~4 billion in total and 10000 concurrent)
   per key name.

Signed-off-by: Andreas Auernhammer <github@aead.dev>
This commit is contained in:
Andreas Auernhammer
2024-05-08 01:55:37 +02:00
committed by GitHub
parent 981497799a
commit 8b660e18f2
36 changed files with 1794 additions and 1808 deletions

View File

@@ -106,7 +106,7 @@ func (ssekms) IsEncrypted(metadata map[string]string) bool {
// UnsealObjectKey extracts and decrypts the sealed object key
// from the metadata using KMS and returns the decrypted object
// key.
func (s3 ssekms) UnsealObjectKey(k kms.KMS, metadata map[string]string, bucket, object string) (key ObjectKey, err error) {
func (s3 ssekms) UnsealObjectKey(k *kms.KMS, metadata map[string]string, bucket, object string) (key ObjectKey, err error) {
if k == nil {
return key, Errorf("KMS not configured")
}
@@ -120,7 +120,11 @@ func (s3 ssekms) UnsealObjectKey(k kms.KMS, metadata map[string]string, bucket,
} else if _, ok := ctx[bucket]; !ok {
ctx[bucket] = path.Join(bucket, object)
}
unsealKey, err := k.DecryptKey(keyID, kmsKey, ctx)
unsealKey, err := k.Decrypt(context.TODO(), &kms.DecryptRequest{
Name: keyID,
Ciphertext: kmsKey,
AssociatedData: ctx,
})
if err != nil {
return key, err
}

View File

@@ -71,7 +71,7 @@ func (sses3) IsEncrypted(metadata map[string]string) bool {
// UnsealObjectKey extracts and decrypts the sealed object key
// from the metadata using KMS and returns the decrypted object
// key.
func (s3 sses3) UnsealObjectKey(k kms.KMS, metadata map[string]string, bucket, object string) (key ObjectKey, err error) {
func (s3 sses3) UnsealObjectKey(k *kms.KMS, metadata map[string]string, bucket, object string) (key ObjectKey, err error) {
if k == nil {
return key, Errorf("KMS not configured")
}
@@ -79,7 +79,11 @@ func (s3 sses3) UnsealObjectKey(k kms.KMS, metadata map[string]string, bucket, o
if err != nil {
return key, err
}
unsealKey, err := k.DecryptKey(keyID, kmsKey, kms.Context{bucket: path.Join(bucket, object)})
unsealKey, err := k.Decrypt(context.TODO(), &kms.DecryptRequest{
Name: keyID,
Ciphertext: kmsKey,
AssociatedData: kms.Context{bucket: path.Join(bucket, object)},
})
if err != nil {
return key, err
}
@@ -92,7 +96,7 @@ func (s3 sses3) UnsealObjectKey(k kms.KMS, metadata map[string]string, bucket, o
// keys.
//
// The metadata, buckets and objects slices must have the same length.
func (s3 sses3) UnsealObjectKeys(ctx context.Context, k kms.KMS, metadata []map[string]string, buckets, objects []string) ([]ObjectKey, error) {
func (s3 sses3) UnsealObjectKeys(ctx context.Context, k *kms.KMS, metadata []map[string]string, buckets, objects []string) ([]ObjectKey, error) {
if k == nil {
return nil, Errorf("KMS not configured")
}
@@ -100,45 +104,8 @@ func (s3 sses3) UnsealObjectKeys(ctx context.Context, k kms.KMS, metadata []map[
if len(metadata) != len(buckets) || len(metadata) != len(objects) {
return nil, Errorf("invalid metadata/object count: %d != %d != %d", len(metadata), len(buckets), len(objects))
}
keyIDs := make([]string, 0, len(metadata))
kmsKeys := make([][]byte, 0, len(metadata))
sealedKeys := make([]SealedKey, 0, len(metadata))
sameKeyID := true
keys := make([]ObjectKey, 0, len(metadata))
for i := range metadata {
keyID, kmsKey, sealedKey, err := s3.ParseMetadata(metadata[i])
if err != nil {
return nil, err
}
keyIDs = append(keyIDs, keyID)
kmsKeys = append(kmsKeys, kmsKey)
sealedKeys = append(sealedKeys, sealedKey)
if i > 0 && keyID != keyIDs[i-1] {
sameKeyID = false
}
}
if sameKeyID {
contexts := make([]kms.Context, 0, len(keyIDs))
for i := range buckets {
contexts = append(contexts, kms.Context{buckets[i]: path.Join(buckets[i], objects[i])})
}
unsealKeys, err := k.DecryptAll(ctx, keyIDs[0], kmsKeys, contexts)
if err != nil {
return nil, err
}
keys := make([]ObjectKey, len(unsealKeys))
for i := range keys {
if err := keys[i].Unseal(unsealKeys[i], sealedKeys[i], s3.String(), buckets[i], objects[i]); err != nil {
return nil, err
}
}
return keys, nil
}
keys := make([]ObjectKey, 0, len(keyIDs))
for i := range keyIDs {
key, err := s3.UnsealObjectKey(k, metadata[i], buckets[i], objects[i])
if err != nil {
return nil, err