mirror of
https://github.com/minio/minio.git
synced 2024-12-25 22:55:54 -05:00
4d2fc530d0
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>
137 lines
4.1 KiB
Go
137 lines
4.1 KiB
Go
// Copyright (c) 2015-2021 MinIO, Inc.
|
|
//
|
|
// This file is part of MinIO Object Storage stack
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
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
|
|
// different KMS implementations.
|
|
type KMS interface {
|
|
// Stat returns the current KMS status.
|
|
Stat() (Status, error)
|
|
|
|
// CreateKey creates a new key at the KMS with the given key ID.
|
|
CreateKey(keyID string) error
|
|
|
|
// GenerateKey generates a new data encryption key using the
|
|
// key referenced by the key ID.
|
|
//
|
|
// The KMS may use a default key if the key ID is empty.
|
|
// GenerateKey returns an error if the referenced key does
|
|
// not exist.
|
|
//
|
|
// The context is associated and tied to the generated DEK.
|
|
// The same context must be provided when the generated key
|
|
// should be decrypted. Therefore, it is the callers
|
|
// responsibility to remember the corresponding context for
|
|
// a particular DEK. The context may be nil.
|
|
GenerateKey(keyID string, context Context) (DEK, error)
|
|
|
|
// DecryptKey decrypts the ciphertext with the key referenced
|
|
// 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.
|
|
type Status struct {
|
|
Name string // The name of the KMS
|
|
Endpoints []string // A set of the KMS endpoints
|
|
|
|
// DefaultKey is the key used when no explicit key ID
|
|
// is specified. It is empty if the KMS does not support
|
|
// a default key.
|
|
DefaultKey string
|
|
}
|
|
|
|
// DEK is a data encryption key. It consists of a
|
|
// plaintext-ciphertext pair and the ID of the key
|
|
// used to generate the ciphertext.
|
|
//
|
|
// The plaintext can be used for cryptographic
|
|
// operations - like encrypting some data. The
|
|
// ciphertext is the encrypted version of the
|
|
// plaintext data and can be stored on untrusted
|
|
// storage.
|
|
type DEK struct {
|
|
KeyID string
|
|
Plaintext []byte
|
|
Ciphertext []byte
|
|
}
|
|
|
|
var (
|
|
_ encoding.TextMarshaler = (*DEK)(nil)
|
|
_ encoding.TextUnmarshaler = (*DEK)(nil)
|
|
)
|
|
|
|
// MarshalText encodes the DEK's key ID and ciphertext
|
|
// as JSON.
|
|
func (d DEK) MarshalText() ([]byte, error) {
|
|
type JSON struct {
|
|
KeyID string `json:"keyid"`
|
|
Ciphertext []byte `json:"ciphertext"`
|
|
}
|
|
return json.Marshal(JSON{
|
|
KeyID: d.KeyID,
|
|
Ciphertext: d.Ciphertext,
|
|
})
|
|
}
|
|
|
|
// UnmarshalText tries to decode text as JSON representation
|
|
// of a DEK and sets DEK's key ID and ciphertext to the
|
|
// decoded values.
|
|
//
|
|
// It sets DEK's plaintext to nil.
|
|
func (d *DEK) UnmarshalText(text []byte) error {
|
|
type JSON struct {
|
|
KeyID string `json:"keyid"`
|
|
Ciphertext []byte `json:"ciphertext"`
|
|
}
|
|
var v JSON
|
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
|
if err := json.Unmarshal(text, &v); err != nil {
|
|
return err
|
|
}
|
|
d.KeyID, d.Plaintext, d.Ciphertext = v.KeyID, nil, v.Ciphertext
|
|
return nil
|
|
}
|