mirror of
https://github.com/minio/minio.git
synced 2025-11-07 12:52:58 -05:00
add support for SSE-S3 bulk ETag decryption (#14627)
This commit adds support for bulk ETag decryption for SSE-S3 encrypted objects. If KES supports a bulk decryption API, then MinIO will check whether its policy grants access to this API. If so, MinIO will use a bulk API call instead of sending encrypted ETags serially to KES. Note that MinIO will not use the KES bulk API if its client certificate is an admin identity. MinIO will process object listings in batches. A batch has a configurable size that can be set via `MINIO_KMS_KES_BULK_API_BATCH_SIZE=N`. It defaults to `500`. This env. variable is experimental and may be renamed / removed in the future. Signed-off-by: Andreas Auernhammer <hi@aead.dev>
This commit is contained in:
committed by
GitHub
parent
3970204009
commit
4d2fc530d0
@@ -22,6 +22,7 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/kes"
|
||||
@@ -69,15 +70,30 @@ func NewWithConfig(config Config) (KMS, error) {
|
||||
ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize),
|
||||
})
|
||||
client.Endpoints = endpoints
|
||||
|
||||
var bulkAvailable bool
|
||||
_, policy, err := client.DescribeSelf(context.Background())
|
||||
if err == nil {
|
||||
const BulkAPI = "/v1/key/bulk/decrypt/"
|
||||
for _, allow := range policy.Allow {
|
||||
if strings.HasPrefix(allow, BulkAPI) {
|
||||
bulkAvailable = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return &kesClient{
|
||||
client: client,
|
||||
defaultKeyID: config.DefaultKeyID,
|
||||
client: client,
|
||||
defaultKeyID: config.DefaultKeyID,
|
||||
bulkAvailable: bulkAvailable,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type kesClient struct {
|
||||
defaultKeyID string
|
||||
client *kes.Client
|
||||
|
||||
bulkAvailable bool
|
||||
}
|
||||
|
||||
var _ KMS = (*kesClient)(nil) // compiler check
|
||||
@@ -145,3 +161,38 @@ func (c *kesClient) DecryptKey(keyID string, ciphertext []byte, ctx Context) ([]
|
||||
}
|
||||
return c.client.Decrypt(context.Background(), keyID, ciphertext, ctxBytes)
|
||||
}
|
||||
|
||||
func (c *kesClient) DecryptAll(keyID string, ciphertexts [][]byte, contexts []Context) ([][]byte, error) {
|
||||
if c.bulkAvailable {
|
||||
CCPs := make([]kes.CCP, 0, len(ciphertexts))
|
||||
for i := range ciphertexts {
|
||||
bCtx, err := contexts[i].MarshalText()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
CCPs = append(CCPs, kes.CCP{
|
||||
Ciphertext: ciphertexts[i],
|
||||
Context: bCtx,
|
||||
})
|
||||
}
|
||||
PCPs, err := c.client.DecryptAll(context.Background(), keyID, CCPs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintexts := make([][]byte, 0, len(PCPs))
|
||||
for _, p := range PCPs {
|
||||
plaintexts = append(plaintexts, p.Plaintext)
|
||||
}
|
||||
return plaintexts, nil
|
||||
}
|
||||
|
||||
plaintexts := make([][]byte, 0, len(ciphertexts))
|
||||
for i := range ciphertexts {
|
||||
plaintext, err := c.DecryptKey(keyID, ciphertexts[i], contexts[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintexts = append(plaintexts, plaintext)
|
||||
}
|
||||
return plaintexts, nil
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ package kms
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/minio/pkg/env"
|
||||
)
|
||||
|
||||
// KMS is the generic interface that abstracts over
|
||||
@@ -51,6 +53,23 @@ type KMS interface {
|
||||
// by the key ID. The context must match the context value
|
||||
// used to generate the ciphertext.
|
||||
DecryptKey(keyID string, ciphertext []byte, context Context) ([]byte, error)
|
||||
|
||||
// DecryptAll decrypts all ciphertexts with the key referenced
|
||||
// by the key ID. The contexts must match the context value
|
||||
// used to generate the ciphertexts.
|
||||
DecryptAll(keyID string, ciphertext [][]byte, context []Context) ([][]byte, error)
|
||||
}
|
||||
|
||||
// BatchSize returns the size of the batches that should be used during
|
||||
// KES bulk decryption API calls.
|
||||
func BatchSize() int {
|
||||
const DefaultBatchSize = 500
|
||||
v := env.Get("MINIO_KMS_KES_BULK_API_BATCH_SIZE", strconv.Itoa(DefaultBatchSize))
|
||||
n, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return DefaultBatchSize
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Status describes the current state of a KMS.
|
||||
|
||||
@@ -224,6 +224,18 @@ func (kms secretKey) DecryptKey(keyID string, ciphertext []byte, context Context
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
func (kms secretKey) DecryptAll(keyID string, ciphertexts [][]byte, contexts []Context) ([][]byte, error) {
|
||||
plaintexts := make([][]byte, 0, len(ciphertexts))
|
||||
for i := range ciphertexts {
|
||||
plaintext, err := kms.DecryptKey(keyID, ciphertexts[i], contexts[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintexts = append(plaintexts, plaintext)
|
||||
}
|
||||
return plaintexts, nil
|
||||
}
|
||||
|
||||
type encryptedKey struct {
|
||||
Algorithm string `json:"aead"`
|
||||
IV []byte `json:"iv"`
|
||||
|
||||
Reference in New Issue
Block a user