mirror of
https://github.com/minio/minio.git
synced 2025-04-12 15:32:07 -04:00
simplify error responses for KMS (#16793)
This commit is contained in:
parent
58266c9e2c
commit
46f9049fb4
@ -38,6 +38,7 @@ import (
|
|||||||
"github.com/minio/minio/internal/bucket/replication"
|
"github.com/minio/minio/internal/bucket/replication"
|
||||||
"github.com/minio/minio/internal/config/dns"
|
"github.com/minio/minio/internal/config/dns"
|
||||||
"github.com/minio/minio/internal/crypto"
|
"github.com/minio/minio/internal/crypto"
|
||||||
|
"github.com/minio/minio/internal/kms"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
|
|
||||||
objectlock "github.com/minio/minio/internal/bucket/object/lock"
|
objectlock "github.com/minio/minio/internal/bucket/object/lock"
|
||||||
@ -2317,6 +2318,12 @@ func toAPIError(ctx context.Context, err error) APIError {
|
|||||||
// any underlying errors if possible depending on
|
// any underlying errors if possible depending on
|
||||||
// their internal error types.
|
// their internal error types.
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
|
case kms.Error:
|
||||||
|
apiErr = APIError{
|
||||||
|
Description: e.Err.Error(),
|
||||||
|
Code: e.APICode,
|
||||||
|
HTTPStatusCode: e.HTTPStatusCode,
|
||||||
|
}
|
||||||
case batchReplicationJobError:
|
case batchReplicationJobError:
|
||||||
apiErr = APIError(e)
|
apiErr = APIError(e)
|
||||||
case InvalidArgument:
|
case InvalidArgument:
|
||||||
|
29
internal/kms/errors.go
Normal file
29
internal/kms/errors.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) 2015-2023 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
|
||||||
|
|
||||||
|
// Error encapsulates S3 API error response fields.
|
||||||
|
type Error struct {
|
||||||
|
Err error
|
||||||
|
APICode string
|
||||||
|
HTTPStatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Error) Error() string {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
@ -25,6 +25,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -107,14 +108,22 @@ func (kms secretKey) List() []kes.KeyInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (secretKey) Metrics(ctx context.Context) (kes.Metric, error) {
|
func (secretKey) Metrics(ctx context.Context) (kes.Metric, error) {
|
||||||
return kes.Metric{}, errors.New("kms: metrics are not supported")
|
return kes.Metric{}, Error{
|
||||||
|
HTTPStatusCode: http.StatusNotImplemented,
|
||||||
|
APICode: "KMS.NotImplemented",
|
||||||
|
Err: errors.New("metrics are not supported"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kms secretKey) CreateKey(_ context.Context, keyID string) error {
|
func (kms secretKey) CreateKey(_ context.Context, keyID string) error {
|
||||||
if keyID == kms.keyID {
|
if keyID == kms.keyID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("kms: creating custom key %q is not supported", keyID)
|
return Error{
|
||||||
|
HTTPStatusCode: http.StatusNotImplemented,
|
||||||
|
APICode: "KMS.NotImplemented",
|
||||||
|
Err: fmt.Errorf("creating custom key %q is not supported", keyID),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kms secretKey) GenerateKey(_ context.Context, keyID string, context Context) (DEK, error) {
|
func (kms secretKey) GenerateKey(_ context.Context, keyID string, context Context) (DEK, error) {
|
||||||
@ -122,7 +131,11 @@ func (kms secretKey) GenerateKey(_ context.Context, keyID string, context Contex
|
|||||||
keyID = kms.keyID
|
keyID = kms.keyID
|
||||||
}
|
}
|
||||||
if keyID != kms.keyID {
|
if keyID != kms.keyID {
|
||||||
return DEK{}, fmt.Errorf("kms: key %q does not exist", keyID)
|
return DEK{}, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.NotFoundException",
|
||||||
|
Err: fmt.Errorf("key %q does not exist", keyID),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iv, err := sioutil.Random(16)
|
iv, err := sioutil.Random(16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -163,7 +176,11 @@ func (kms secretKey) GenerateKey(_ context.Context, keyID string, context Contex
|
|||||||
return DEK{}, err
|
return DEK{}, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return DEK{}, errors.New("invalid algorithm: " + algorithm)
|
return DEK{}, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.InternalException",
|
||||||
|
Err: errors.New("invalid algorithm: " + algorithm),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := sioutil.Random(aead.NonceSize())
|
nonce, err := sioutil.Random(aead.NonceSize())
|
||||||
@ -197,17 +214,29 @@ func (kms secretKey) GenerateKey(_ context.Context, keyID string, context Contex
|
|||||||
|
|
||||||
func (kms secretKey) DecryptKey(keyID string, ciphertext []byte, context Context) ([]byte, error) {
|
func (kms secretKey) DecryptKey(keyID string, ciphertext []byte, context Context) ([]byte, error) {
|
||||||
if keyID != kms.keyID {
|
if keyID != kms.keyID {
|
||||||
return nil, fmt.Errorf("kms: key %q does not exist", keyID)
|
return nil, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.NotFoundException",
|
||||||
|
Err: fmt.Errorf("key %q does not exist", keyID),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var encryptedKey encryptedKey
|
var encryptedKey encryptedKey
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
if err := json.Unmarshal(ciphertext, &encryptedKey); err != nil {
|
if err := json.Unmarshal(ciphertext, &encryptedKey); err != nil {
|
||||||
return nil, err
|
return nil, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.InternalException",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n := len(encryptedKey.IV); n != 16 {
|
if n := len(encryptedKey.IV); n != 16 {
|
||||||
return nil, fmt.Errorf("kms: invalid iv size")
|
return nil, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.InternalException",
|
||||||
|
Err: fmt.Errorf("invalid iv size: %d", n),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var aead cipher.AEAD
|
var aead cipher.AEAD
|
||||||
@ -235,17 +264,29 @@ func (kms secretKey) DecryptKey(keyID string, ciphertext []byte, context Context
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("kms: invalid algorithm: %q", encryptedKey.Algorithm)
|
return nil, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.InternalException",
|
||||||
|
Err: fmt.Errorf("invalid algorithm: %q", encryptedKey.Algorithm),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n := len(encryptedKey.Nonce); n != aead.NonceSize() {
|
if n := len(encryptedKey.Nonce); n != aead.NonceSize() {
|
||||||
return nil, fmt.Errorf("kms: invalid nonce size %d", n)
|
return nil, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.InternalException",
|
||||||
|
Err: fmt.Errorf("invalid nonce size %d", n),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
associatedData, _ := context.MarshalText()
|
associatedData, _ := context.MarshalText()
|
||||||
plaintext, err := aead.Open(nil, encryptedKey.Nonce, encryptedKey.Bytes, associatedData)
|
plaintext, err := aead.Open(nil, encryptedKey.Nonce, encryptedKey.Bytes, associatedData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("kms: encrypted key is not authentic")
|
return nil, Error{
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
APICode: "KMS.InternalException",
|
||||||
|
Err: fmt.Errorf("encrypted key is not authentic"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return plaintext, nil
|
return plaintext, nil
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,14 @@ import (
|
|||||||
// LogOnce provides the function type for logger.LogOnceIf() function
|
// LogOnce provides the function type for logger.LogOnceIf() function
|
||||||
type LogOnce func(ctx context.Context, err error, id string, errKind ...interface{})
|
type LogOnce func(ctx context.Context, err error, id string, errKind ...interface{})
|
||||||
|
|
||||||
|
type onceErr struct {
|
||||||
|
Err error
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
// Holds a map of recently logged errors.
|
// Holds a map of recently logged errors.
|
||||||
type logOnceType struct {
|
type logOnceType struct {
|
||||||
IDMap map[string]error
|
IDMap map[string]onceErr
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +46,17 @@ func (l *logOnceType) logOnceConsoleIf(ctx context.Context, err error, id string
|
|||||||
nerr := unwrapErrs(err)
|
nerr := unwrapErrs(err)
|
||||||
l.Lock()
|
l.Lock()
|
||||||
shouldLog := true
|
shouldLog := true
|
||||||
prevErr, ok := l.IDMap[id]
|
prev, ok := l.IDMap[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
l.IDMap[id] = nerr
|
l.IDMap[id] = onceErr{
|
||||||
} else {
|
Err: nerr,
|
||||||
|
Count: 1,
|
||||||
|
}
|
||||||
|
} else if prev.Err.Error() == nerr.Error() {
|
||||||
// if errors are equal do not log.
|
// if errors are equal do not log.
|
||||||
shouldLog = prevErr.Error() != nerr.Error()
|
prev.Count++
|
||||||
|
l.IDMap[id] = prev
|
||||||
|
shouldLog = false
|
||||||
}
|
}
|
||||||
l.Unlock()
|
l.Unlock()
|
||||||
|
|
||||||
@ -88,37 +98,41 @@ func (l *logOnceType) logOnceIf(ctx context.Context, err error, id string, errKi
|
|||||||
}
|
}
|
||||||
|
|
||||||
nerr := unwrapErrs(err)
|
nerr := unwrapErrs(err)
|
||||||
|
|
||||||
l.Lock()
|
l.Lock()
|
||||||
shouldLog := true
|
shouldLog := true
|
||||||
prevErr, ok := l.IDMap[id]
|
prev, ok := l.IDMap[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
l.IDMap[id] = nerr
|
l.IDMap[id] = onceErr{
|
||||||
} else {
|
Err: nerr,
|
||||||
|
Count: 1,
|
||||||
|
}
|
||||||
|
} else if prev.Err.Error() == nerr.Error() {
|
||||||
// if errors are equal do not log.
|
// if errors are equal do not log.
|
||||||
shouldLog = prevErr.Error() != nerr.Error()
|
prev.Count++
|
||||||
|
l.IDMap[id] = prev
|
||||||
|
shouldLog = false
|
||||||
}
|
}
|
||||||
l.Unlock()
|
l.Unlock()
|
||||||
|
|
||||||
if shouldLog {
|
if shouldLog {
|
||||||
LogIf(ctx, err, errKind...)
|
logIf(ctx, err, errKind...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup the map every 30 minutes so that the log message is printed again for the user to notice.
|
// Cleanup the map every 30 minutes so that the log message is printed again for the user to notice.
|
||||||
func (l *logOnceType) cleanupRoutine() {
|
func (l *logOnceType) cleanupRoutine() {
|
||||||
for {
|
for {
|
||||||
l.Lock()
|
time.Sleep(time.Hour)
|
||||||
l.IDMap = make(map[string]error)
|
|
||||||
l.Unlock()
|
|
||||||
|
|
||||||
time.Sleep(30 * time.Minute)
|
l.Lock()
|
||||||
|
l.IDMap = make(map[string]onceErr)
|
||||||
|
l.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns logOnceType
|
// Returns logOnceType
|
||||||
func newLogOnceType() *logOnceType {
|
func newLogOnceType() *logOnceType {
|
||||||
l := &logOnceType{IDMap: make(map[string]error)}
|
l := &logOnceType{IDMap: make(map[string]onceErr)}
|
||||||
go l.cleanupRoutine()
|
go l.cleanupRoutine()
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user