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

@@ -874,8 +874,10 @@ func (a adminAPIHandlers) ImportBucketMetadataHandler(w http.ResponseWriter, r *
}
kmsKey := encConfig.KeyID()
if kmsKey != "" {
kmsContext := kms.Context{"MinIO admin API": "ServerInfoHandler"} // Context for a test key operation
_, err := GlobalKMS.GenerateKey(ctx, kmsKey, kmsContext)
_, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{
Name: kmsKey,
AssociatedData: kms.Context{"MinIO admin API": "ServerInfoHandler"}, // Context for a test key operation
})
if err != nil {
if errors.Is(err, kes.ErrKeyNotFound) {
rpt.SetStatus(bucket, fileName, errKMSKeyNotFound)

View File

@@ -2173,7 +2173,9 @@ func (a adminAPIHandlers) KMSCreateKeyHandler(w http.ResponseWriter, r *http.Req
return
}
if err := GlobalKMS.CreateKey(ctx, r.Form.Get("key-id")); err != nil {
if err := GlobalKMS.CreateKey(ctx, &kms.CreateKeyRequest{
Name: r.Form.Get("key-id"),
}); err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
@@ -2194,22 +2196,12 @@ func (a adminAPIHandlers) KMSStatusHandler(w http.ResponseWriter, r *http.Reques
return
}
stat, err := GlobalKMS.Stat(ctx)
stat, err := GlobalKMS.Status(ctx)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
status := madmin.KMSStatus{
Name: stat.Name,
DefaultKeyID: stat.DefaultKey,
Endpoints: make(map[string]madmin.ItemState, len(stat.Endpoints)),
}
for _, endpoint := range stat.Endpoints {
status.Endpoints[endpoint] = madmin.ItemOnline // TODO(aead): Implement an online check for mTLS
}
resp, err := json.Marshal(status)
resp, err := json.Marshal(stat)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
@@ -2231,15 +2223,9 @@ func (a adminAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Req
return
}
stat, err := GlobalKMS.Stat(ctx)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
keyID := r.Form.Get("key-id")
if keyID == "" {
keyID = stat.DefaultKey
keyID = GlobalKMS.DefaultKey
}
response := madmin.KMSKeyStatus{
KeyID: keyID,
@@ -2247,7 +2233,10 @@ func (a adminAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Req
kmsContext := kms.Context{"MinIO admin API": "KMSKeyStatusHandler"} // Context for a test key operation
// 1. Generate a new key using the KMS.
key, err := GlobalKMS.GenerateKey(ctx, keyID, kmsContext)
key, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{
Name: keyID,
AssociatedData: kmsContext,
})
if err != nil {
response.EncryptionErr = err.Error()
resp, err := json.Marshal(response)
@@ -2260,7 +2249,11 @@ func (a adminAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Req
}
// 2. Verify that we can indeed decrypt the (encrypted) key
decryptedKey, err := GlobalKMS.DecryptKey(key.KeyID, key.Ciphertext, kmsContext)
decryptedKey, err := GlobalKMS.Decrypt(ctx, &kms.DecryptRequest{
Name: key.KeyID,
Ciphertext: key.Ciphertext,
AssociatedData: kmsContext,
})
if err != nil {
response.DecryptionErr = err.Error()
resp, err := json.Marshal(response)
@@ -2413,8 +2406,7 @@ func getServerInfo(ctx context.Context, pools, metrics bool, r *http.Request) ma
domain := globalDomainNames
services := madmin.Services{
KMS: fetchKMSStatus(),
KMSStatus: fetchKMSStatusV2(ctx),
KMSStatus: fetchKMSStatus(ctx),
LDAP: ldap,
Logger: log,
Audit: audit,
@@ -3024,66 +3016,25 @@ func fetchLambdaInfo() []map[string][]madmin.TargetIDStatus {
return notify
}
// fetchKMSStatus fetches KMS-related status information.
func fetchKMSStatus() madmin.KMS {
kmsStat := madmin.KMS{}
if GlobalKMS == nil {
kmsStat.Status = "disabled"
return kmsStat
}
stat, err := GlobalKMS.Stat(context.Background())
if err != nil {
kmsStat.Status = string(madmin.ItemOffline)
return kmsStat
}
if len(stat.Endpoints) == 0 {
kmsStat.Status = stat.Name
return kmsStat
}
kmsStat.Status = string(madmin.ItemOnline)
kmsContext := kms.Context{"MinIO admin API": "ServerInfoHandler"} // Context for a test key operation
// 1. Generate a new key using the KMS.
key, err := GlobalKMS.GenerateKey(context.Background(), "", kmsContext)
if err != nil {
kmsStat.Encrypt = fmt.Sprintf("Encryption failed: %v", err)
} else {
kmsStat.Encrypt = "success"
}
// 2. Verify that we can indeed decrypt the (encrypted) key
decryptedKey, err := GlobalKMS.DecryptKey(key.KeyID, key.Ciphertext, kmsContext)
switch {
case err != nil:
kmsStat.Decrypt = fmt.Sprintf("Decryption failed: %v", err)
case subtle.ConstantTimeCompare(key.Plaintext, decryptedKey) != 1:
kmsStat.Decrypt = "Decryption failed: decrypted key does not match generated key"
default:
kmsStat.Decrypt = "success"
}
return kmsStat
}
// fetchKMSStatusV2 fetches KMS-related status information for all instances
func fetchKMSStatusV2(ctx context.Context) []madmin.KMS {
// fetchKMSStatus fetches KMS-related status information for all instances
func fetchKMSStatus(ctx context.Context) []madmin.KMS {
if GlobalKMS == nil {
return []madmin.KMS{}
}
results := GlobalKMS.Verify(ctx)
stats := []madmin.KMS{}
for _, result := range results {
stats = append(stats, madmin.KMS{
Status: result.Status,
Endpoint: result.Endpoint,
Encrypt: result.Encrypt,
Decrypt: result.Decrypt,
Version: result.Version,
})
stat, err := GlobalKMS.Status(ctx)
if err != nil {
kmsLogIf(ctx, err, "failed to fetch KMS status information")
return []madmin.KMS{}
}
stats := make([]madmin.KMS, 0, len(stat.Endpoints))
for endpoint, state := range stat.Endpoints {
stats = append(stats, madmin.KMS{
Status: string(state),
Endpoint: endpoint,
})
}
return stats
}

View File

@@ -2430,9 +2430,9 @@ func toAPIError(ctx context.Context, err error) APIError {
switch e := err.(type) {
case kms.Error:
apiErr = APIError{
Description: e.Err.Error(),
Code: e.APICode,
HTTPStatusCode: e.HTTPStatusCode,
Description: e.Err,
HTTPStatusCode: e.Code,
}
case batchReplicationJobError:
apiErr = APIError{

View File

@@ -95,6 +95,7 @@ func (e BatchJobKeyRotateEncryption) Validate() error {
if e.Type == ssekms && spaces {
return crypto.ErrInvalidEncryptionKeyID
}
if e.Type == ssekms && GlobalKMS != nil {
ctx := kms.Context{}
if e.Context != "" {
@@ -113,7 +114,7 @@ func (e BatchJobKeyRotateEncryption) Validate() error {
e.kmsContext[k] = v
}
ctx["MinIO batch API"] = "batchrotate" // Context for a test key operation
if _, err := GlobalKMS.GenerateKey(GlobalContext, e.Key, ctx); err != nil {
if _, err := GlobalKMS.GenerateKey(GlobalContext, &kms.GenerateKeyRequest{Name: e.Key, AssociatedData: ctx}); err != nil {
return err
}
}
@@ -478,8 +479,5 @@ func (r *BatchJobKeyRotateV1) Validate(ctx context.Context, job BatchJobRequest,
}
}
if err := r.Flags.Retry.Validate(); err != nil {
return err
}
return nil
return r.Flags.Retry.Validate()
}

View File

@@ -85,7 +85,7 @@ func (api objectAPIHandlers) PutBucketEncryptionHandler(w http.ResponseWriter, r
kmsKey := encConfig.KeyID()
if kmsKey != "" {
kmsContext := kms.Context{"MinIO admin API": "ServerInfoHandler"} // Context for a test key operation
_, err := GlobalKMS.GenerateKey(ctx, kmsKey, kmsContext)
_, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{Name: kmsKey, AssociatedData: kmsContext})
if err != nil {
if errors.Is(err, kes.ErrKeyNotFound) {
writeErrorResponse(ctx, w, toAPIError(ctx, errKMSKeyNotFound), r.URL)

View File

@@ -490,7 +490,7 @@ func encryptBucketMetadata(ctx context.Context, bucket string, input []byte, kms
}
metadata := make(map[string]string)
key, err := GlobalKMS.GenerateKey(ctx, "", kmsContext)
key, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{AssociatedData: kmsContext})
if err != nil {
return
}
@@ -519,7 +519,11 @@ func decryptBucketMetadata(input []byte, bucket string, meta map[string]string,
if err != nil {
return nil, err
}
extKey, err := GlobalKMS.DecryptKey(keyID, kmsKey, kmsContext)
extKey, err := GlobalKMS.Decrypt(context.TODO(), &kms.DecryptRequest{
Name: keyID,
Ciphertext: kmsKey,
AssociatedData: kmsContext,
})
if err != nil {
return nil, err
}

View File

@@ -21,10 +21,8 @@ import (
"bufio"
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/gob"
"encoding/pem"
"errors"
"fmt"
"net"
@@ -49,7 +47,6 @@ import (
"github.com/minio/console/api/operations"
consoleoauth2 "github.com/minio/console/pkg/auth/idp/oauth2"
consoleCerts "github.com/minio/console/pkg/certs"
"github.com/minio/kms-go/kes"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/set"
@@ -60,7 +57,6 @@ import (
"github.com/minio/minio/internal/logger"
"github.com/minio/pkg/v2/certs"
"github.com/minio/pkg/v2/console"
"github.com/minio/pkg/v2/ellipses"
"github.com/minio/pkg/v2/env"
xnet "github.com/minio/pkg/v2/net"
"golang.org/x/term"
@@ -865,127 +861,28 @@ func loadRootCredentials() {
// Initialize KMS global variable after valiadating and loading the configuration.
// It depends on KMS env variables and global cli flags.
func handleKMSConfig() {
if env.IsSet(kms.EnvKMSSecretKey) && env.IsSet(kms.EnvKESEndpoint) {
logger.Fatal(errors.New("ambiguous KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKMSSecretKey, kms.EnvKESEndpoint))
present, err := kms.IsPresent()
if err != nil {
logger.Fatal(err, "Invalid KMS configuration specified")
}
if !present {
return
}
if env.IsSet(kms.EnvKMSSecretKey) {
KMS, err := kms.Parse(env.Get(kms.EnvKMSSecretKey, ""))
if err != nil {
logger.Fatal(err, "Unable to parse the KMS secret key inherited from the shell environment")
}
GlobalKMS = KMS
KMS, err := kms.Connect(GlobalContext, &kms.ConnectionOptions{
CADir: globalCertsCADir.Get(),
})
if err != nil {
logger.Fatal(err, "Failed to connect to KMS")
}
if env.IsSet(kms.EnvKESEndpoint) {
if env.IsSet(kms.EnvKESAPIKey) {
if env.IsSet(kms.EnvKESClientKey) {
logger.Fatal(errors.New("ambiguous KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKESAPIKey, kms.EnvKESClientKey))
}
if env.IsSet(kms.EnvKESClientCert) {
logger.Fatal(errors.New("ambiguous KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKESAPIKey, kms.EnvKESClientCert))
}
}
if !env.IsSet(kms.EnvKESKeyName) {
logger.Fatal(errors.New("Invalid KES configuration"), fmt.Sprintf("The mandatory environment variable %q not set", kms.EnvKESKeyName))
}
var endpoints []string
for _, endpoint := range strings.Split(env.Get(kms.EnvKESEndpoint, ""), ",") {
if strings.TrimSpace(endpoint) == "" {
continue
}
if !ellipses.HasEllipses(endpoint) {
endpoints = append(endpoints, endpoint)
continue
}
patterns, err := ellipses.FindEllipsesPatterns(endpoint)
if err != nil {
logger.Fatal(err, fmt.Sprintf("Invalid KES endpoint %q", endpoint))
}
for _, lbls := range patterns.Expand() {
endpoints = append(endpoints, strings.Join(lbls, ""))
}
}
rootCAs, err := certs.GetRootCAs(env.Get(kms.EnvKESServerCA, globalCertsCADir.Get()))
if err != nil {
logger.Fatal(err, fmt.Sprintf("Unable to load X.509 root CAs for KES from %q", env.Get(kms.EnvKESServerCA, globalCertsCADir.Get())))
}
var kmsConf kms.Config
if env.IsSet(kms.EnvKESAPIKey) {
key, err := kes.ParseAPIKey(env.Get(kms.EnvKESAPIKey, ""))
if err != nil {
logger.Fatal(err, fmt.Sprintf("Failed to parse KES API key from %q", env.Get(kms.EnvKESAPIKey, "")))
}
kmsConf = kms.Config{
Endpoints: endpoints,
DefaultKeyID: env.Get(kms.EnvKESKeyName, ""),
APIKey: key,
RootCAs: rootCAs,
}
} else {
loadX509KeyPair := func(certFile, keyFile string) (tls.Certificate, error) {
// Manually load the certificate and private key into memory.
// We need to check whether the private key is encrypted, and
// if so, decrypt it using the user-provided password.
certBytes, err := os.ReadFile(certFile)
if err != nil {
return tls.Certificate{}, fmt.Errorf("Unable to load KES client certificate as specified by the shell environment: %v", err)
}
keyBytes, err := os.ReadFile(keyFile)
if err != nil {
return tls.Certificate{}, fmt.Errorf("Unable to load KES client private key as specified by the shell environment: %v", err)
}
privateKeyPEM, rest := pem.Decode(bytes.TrimSpace(keyBytes))
if len(rest) != 0 {
return tls.Certificate{}, errors.New("Unable to load KES client private key as specified by the shell environment: private key contains additional data")
}
if x509.IsEncryptedPEMBlock(privateKeyPEM) {
keyBytes, err = x509.DecryptPEMBlock(privateKeyPEM, []byte(env.Get(kms.EnvKESClientPassword, "")))
if err != nil {
return tls.Certificate{}, fmt.Errorf("Unable to decrypt KES client private key as specified by the shell environment: %v", err)
}
keyBytes = pem.EncodeToMemory(&pem.Block{Type: privateKeyPEM.Type, Bytes: keyBytes})
}
certificate, err := tls.X509KeyPair(certBytes, keyBytes)
if err != nil {
return tls.Certificate{}, fmt.Errorf("Unable to load KES client certificate as specified by the shell environment: %v", err)
}
return certificate, nil
}
reloadCertEvents := make(chan tls.Certificate, 1)
certificate, err := certs.NewCertificate(env.Get(kms.EnvKESClientCert, ""), env.Get(kms.EnvKESClientKey, ""), loadX509KeyPair)
if err != nil {
logger.Fatal(err, "Failed to load KES client certificate")
}
certificate.Watch(context.Background(), 15*time.Minute, syscall.SIGHUP)
certificate.Notify(reloadCertEvents)
kmsConf = kms.Config{
Endpoints: endpoints,
DefaultKeyID: env.Get(kms.EnvKESKeyName, ""),
Certificate: certificate,
ReloadCertEvents: reloadCertEvents,
RootCAs: rootCAs,
}
}
KMS, err := kms.NewWithConfig(kmsConf, KMSLogger{})
if err != nil {
logger.Fatal(err, "Unable to initialize a connection to KES as specified by the shell environment")
}
// Try to generate a data encryption key. Only try to create key if this fails.
// This implicitly checks that we can communicate to KES.
// We don't treat a policy error as failure condition since MinIO may not have the permission
// to create keys - just to generate/decrypt data encryption keys.
if _, err = KMS.GenerateKey(GlobalContext, env.Get(kms.EnvKESKeyName, ""), kms.Context{}); err != nil && errors.Is(err, kes.ErrKeyNotFound) {
if err = KMS.CreateKey(GlobalContext, env.Get(kms.EnvKESKeyName, "")); err != nil && !errors.Is(err, kes.ErrKeyExists) && !errors.Is(err, kes.ErrNotAllowed) {
logger.Fatal(err, "Unable to initialize a connection to KES as specified by the shell environment")
}
}
GlobalKMS = KMS
if _, err = KMS.GenerateKey(GlobalContext, &kms.GenerateKeyRequest{}); errors.Is(err, kms.ErrKeyNotFound) {
err = KMS.CreateKey(GlobalContext, &kms.CreateKeyRequest{Name: KMS.DefaultKey})
}
if err != nil && !errors.Is(err, kms.ErrKeyExists) && !errors.Is(err, kms.ErrPermission) {
logger.Fatal(err, "Failed to connect to KMS")
}
GlobalKMS = KMS
}
func getTLSConfig() (x509Certs []*x509.Certificate, manager *certs.Manager, secureConn bool, err error) {

View File

@@ -753,41 +753,33 @@ func autoGenerateRootCredentials() {
return
}
if manager, ok := GlobalKMS.(kms.KeyManager); ok {
stat, err := GlobalKMS.Stat(GlobalContext)
if err != nil {
kmsLogIf(GlobalContext, err, "Unable to generate root credentials using KMS")
return
}
aKey, err := GlobalKMS.MAC(GlobalContext, &kms.MACRequest{Message: []byte("root access key")})
if errors.Is(err, kes.ErrNotAllowed) || errors.Is(err, errors.ErrUnsupported) {
return // If we don't have permission to compute the HMAC, don't change the cred.
}
if err != nil {
logger.Fatal(err, "Unable to generate root access key using KMS")
}
aKey, err := manager.HMAC(GlobalContext, stat.DefaultKey, []byte("root access key"))
if errors.Is(err, kes.ErrNotAllowed) {
return // If we don't have permission to compute the HMAC, don't change the cred.
}
if err != nil {
logger.Fatal(err, "Unable to generate root access key using KMS")
}
sKey, err := GlobalKMS.MAC(GlobalContext, &kms.MACRequest{Message: []byte("root secret key")})
if err != nil {
// Here, we must have permission. Otherwise, we would have failed earlier.
logger.Fatal(err, "Unable to generate root secret key using KMS")
}
sKey, err := manager.HMAC(GlobalContext, stat.DefaultKey, []byte("root secret key"))
if err != nil {
// Here, we must have permission. Otherwise, we would have failed earlier.
logger.Fatal(err, "Unable to generate root secret key using KMS")
}
accessKey, err := auth.GenerateAccessKey(20, bytes.NewReader(aKey))
if err != nil {
logger.Fatal(err, "Unable to generate root access key")
}
secretKey, err := auth.GenerateSecretKey(32, bytes.NewReader(sKey))
if err != nil {
logger.Fatal(err, "Unable to generate root secret key")
}
accessKey, err := auth.GenerateAccessKey(20, bytes.NewReader(aKey))
if err != nil {
logger.Fatal(err, "Unable to generate root access key")
}
secretKey, err := auth.GenerateSecretKey(32, bytes.NewReader(sKey))
if err != nil {
logger.Fatal(err, "Unable to generate root secret key")
}
logger.Info("Automatically generated root access key and secret key with the KMS")
globalActiveCred = auth.Credentials{
AccessKey: accessKey,
SecretKey: secretKey,
}
logger.Info("Automatically generated root access key and secret key with the KMS")
globalActiveCred = auth.Credentials{
AccessKey: accessKey,
SecretKey: secretKey,
}
}

View File

@@ -110,7 +110,7 @@ func kmsKeyIDFromMetadata(metadata map[string]string) string {
//
// DecryptETags uses a KMS bulk decryption API, if available, which
// is more efficient than decrypting ETags sequentually.
func DecryptETags(ctx context.Context, k kms.KMS, objects []ObjectInfo) error {
func DecryptETags(ctx context.Context, k *kms.KMS, objects []ObjectInfo) error {
const BatchSize = 250 // We process the objects in batches - 250 is a reasonable default.
var (
metadata = make([]map[string]string, 0, BatchSize)
@@ -267,7 +267,11 @@ func rotateKey(ctx context.Context, oldKey []byte, newKeyID string, newKey []byt
if err != nil {
return err
}
oldKey, err := GlobalKMS.DecryptKey(keyID, kmsKey, kms.Context{bucket: path.Join(bucket, object)})
oldKey, err := GlobalKMS.Decrypt(ctx, &kms.DecryptRequest{
Name: keyID,
Ciphertext: kmsKey,
AssociatedData: kms.Context{bucket: path.Join(bucket, object)},
})
if err != nil {
return err
}
@@ -276,7 +280,10 @@ func rotateKey(ctx context.Context, oldKey []byte, newKeyID string, newKey []byt
return err
}
newKey, err := GlobalKMS.GenerateKey(ctx, "", kms.Context{bucket: path.Join(bucket, object)})
newKey, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{
Name: GlobalKMS.DefaultKey,
AssociatedData: kms.Context{bucket: path.Join(bucket, object)},
})
if err != nil {
return err
}
@@ -312,7 +319,10 @@ func rotateKey(ctx context.Context, oldKey []byte, newKeyID string, newKey []byt
if _, ok := kmsCtx[bucket]; !ok {
kmsCtx[bucket] = path.Join(bucket, object)
}
newKey, err := GlobalKMS.GenerateKey(ctx, newKeyID, kmsCtx)
newKey, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{
Name: newKeyID,
AssociatedData: kmsCtx,
})
if err != nil {
return err
}
@@ -352,7 +362,9 @@ func newEncryptMetadata(ctx context.Context, kind crypto.Type, keyID string, key
if GlobalKMS == nil {
return crypto.ObjectKey{}, errKMSNotConfigured
}
key, err := GlobalKMS.GenerateKey(ctx, "", kms.Context{bucket: path.Join(bucket, object)})
key, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{
AssociatedData: kms.Context{bucket: path.Join(bucket, object)},
})
if err != nil {
return crypto.ObjectKey{}, err
}
@@ -379,7 +391,10 @@ func newEncryptMetadata(ctx context.Context, kind crypto.Type, keyID string, key
if _, ok := kmsCtx[bucket]; !ok {
kmsCtx[bucket] = path.Join(bucket, object)
}
key, err := GlobalKMS.GenerateKey(ctx, keyID, kmsCtx)
key, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{
Name: keyID,
AssociatedData: kmsCtx,
})
if err != nil {
if errors.Is(err, kes.ErrKeyNotFound) {
return crypto.ObjectKey{}, errKMSKeyNotFound
@@ -475,11 +490,10 @@ func EncryptRequest(content io.Reader, r *http.Request, bucket, object string, m
func decryptObjectMeta(key []byte, bucket, object string, metadata map[string]string) ([]byte, error) {
switch kind, _ := crypto.IsEncrypted(metadata); kind {
case crypto.S3:
KMS := GlobalKMS
if KMS == nil {
if GlobalKMS == nil {
return nil, errKMSNotConfigured
}
objectKey, err := crypto.S3.UnsealObjectKey(KMS, metadata, bucket, object)
objectKey, err := crypto.S3.UnsealObjectKey(GlobalKMS, metadata, bucket, object)
if err != nil {
return nil, err
}

View File

@@ -349,7 +349,7 @@ var (
globalDNSConfig dns.Store
// GlobalKMS initialized KMS configuration
GlobalKMS kms.KMS
GlobalKMS *kms.KMS
// Common lock for various subsystems performing the leader tasks
globalLeaderLock *sharedLock

View File

@@ -135,7 +135,7 @@ func ReadinessCheckHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
defer cancel()
if _, err := GlobalKMS.GenerateKey(ctx, "", kms.Context{"healthcheck": ""}); err != nil {
if _, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{AssociatedData: kms.Context{"healthcheck": ""}}); err != nil {
switch r.Method {
case http.MethodHead:
apiErr := toAPIError(r.Context(), err)

View File

@@ -20,10 +20,7 @@ package cmd
import (
"crypto/subtle"
"encoding/json"
"io"
"net/http"
"strings"
"time"
"github.com/minio/kms-go/kes"
"github.com/minio/madmin-go/v3"
@@ -46,22 +43,12 @@ func (a kmsAPIHandlers) KMSStatusHandler(w http.ResponseWriter, r *http.Request)
return
}
stat, err := GlobalKMS.Stat(ctx)
stat, err := GlobalKMS.Status(ctx)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
status := madmin.KMSStatus{
Name: stat.Name,
DefaultKeyID: stat.DefaultKey,
Endpoints: make(map[string]madmin.ItemState, len(stat.Endpoints)),
}
for _, endpoint := range stat.Endpoints {
status.Endpoints[endpoint] = madmin.ItemOnline // TODO(aead): Implement an online check for mTLS
}
resp, err := json.Marshal(status)
resp, err := json.Marshal(stat)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
@@ -84,11 +71,6 @@ func (a kmsAPIHandlers) KMSMetricsHandler(w http.ResponseWriter, r *http.Request
return
}
if _, ok := GlobalKMS.(kms.KeyManager); !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
metrics, err := GlobalKMS.Metrics(ctx)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
@@ -116,13 +98,7 @@ func (a kmsAPIHandlers) KMSAPIsHandler(w http.ResponseWriter, r *http.Request) {
return
}
manager, ok := GlobalKMS.(kms.StatusManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
apis, err := manager.APIs(ctx)
apis, err := GlobalKMS.APIs(ctx)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
@@ -153,13 +129,7 @@ func (a kmsAPIHandlers) KMSVersionHandler(w http.ResponseWriter, r *http.Request
return
}
manager, ok := GlobalKMS.(kms.StatusManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
version, err := manager.Version(ctx)
version, err := GlobalKMS.Version(ctx)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
@@ -177,10 +147,6 @@ func (a kmsAPIHandlers) KMSVersionHandler(w http.ResponseWriter, r *http.Request
func (a kmsAPIHandlers) KMSCreateKeyHandler(w http.ResponseWriter, r *http.Request) {
// If env variable MINIO_KMS_SECRET_KEY is populated, prevent creation of new keys
ctx := newContext(r, w, "KMSCreateKey")
if GlobalKMS != nil && GlobalKMS.IsLocal() {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSDefaultKeyAlreadyConfigured), r.URL)
return
}
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSCreateKeyAction)
@@ -193,39 +159,7 @@ func (a kmsAPIHandlers) KMSCreateKeyHandler(w http.ResponseWriter, r *http.Reque
return
}
manager, ok := GlobalKMS.(kms.KeyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
if err := manager.CreateKey(ctx, r.Form.Get("key-id")); err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
writeSuccessResponseHeadersOnly(w)
}
// KMSDeleteKeyHandler - DELETE /minio/kms/v1/key/delete?key-id=<master-key-id>
func (a kmsAPIHandlers) KMSDeleteKeyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSDeleteKey")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSDeleteKeyAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.KeyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
if err := manager.DeleteKey(ctx, r.Form.Get("key-id")); err != nil {
if err := GlobalKMS.CreateKey(ctx, &kms.CreateKeyRequest{Name: r.Form.Get("key-id")}); err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
@@ -235,15 +169,6 @@ func (a kmsAPIHandlers) KMSDeleteKeyHandler(w http.ResponseWriter, r *http.Reque
// KMSListKeysHandler - GET /minio/kms/v1/key/list?pattern=<pattern>
func (a kmsAPIHandlers) KMSListKeysHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSListKeys")
if GlobalKMS != nil && GlobalKMS.IsLocal() {
res, err := json.Marshal(GlobalKMS.List())
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
writeSuccessResponseJSON(w, res)
return
}
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSListKeysAction)
@@ -255,28 +180,16 @@ func (a kmsAPIHandlers) KMSListKeysHandler(w http.ResponseWriter, r *http.Reques
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.KeyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
keys, err := manager.ListKeys(ctx)
names, _, err := GlobalKMS.ListKeyNames(ctx, &kms.ListRequest{
Prefix: r.Form.Get("pattern"),
})
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
pattern := r.Form.Get("pattern")
if !strings.Contains(pattern, "*") {
pattern += "*"
}
var values []kes.KeyInfo
for name, err := keys.SeekTo(ctx, pattern); err != io.EOF; name, err = keys.Next(ctx) {
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
values := make([]kes.KeyInfo, 0, len(names))
for _, name := range names {
values = append(values, kes.KeyInfo{
Name: name,
})
@@ -288,41 +201,6 @@ func (a kmsAPIHandlers) KMSListKeysHandler(w http.ResponseWriter, r *http.Reques
}
}
type importKeyRequest struct {
Bytes string
}
// KMSImportKeyHandler - POST /minio/kms/v1/key/import?key-id=<master-key-id>
func (a kmsAPIHandlers) KMSImportKeyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSImportKey")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSImportKeyAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.KeyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
var request importKeyRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
if err := manager.ImportKey(ctx, r.Form.Get("key-id"), []byte(request.Bytes)); err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
writeSuccessResponseHeadersOnly(w)
}
// KMSKeyStatusHandler - GET /minio/kms/v1/key/status?key-id=<master-key-id>
func (a kmsAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSKeyStatus")
@@ -338,15 +216,9 @@ func (a kmsAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Reque
return
}
stat, err := GlobalKMS.Stat(ctx)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
keyID := r.Form.Get("key-id")
if keyID == "" {
keyID = stat.DefaultKey
keyID = GlobalKMS.DefaultKey
}
response := madmin.KMSKeyStatus{
KeyID: keyID,
@@ -354,7 +226,7 @@ func (a kmsAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Reque
kmsContext := kms.Context{"MinIO admin API": "KMSKeyStatusHandler"} // Context for a test key operation
// 1. Generate a new key using the KMS.
key, err := GlobalKMS.GenerateKey(ctx, keyID, kmsContext)
key, err := GlobalKMS.GenerateKey(ctx, &kms.GenerateKeyRequest{Name: keyID, AssociatedData: kmsContext})
if err != nil {
response.EncryptionErr = err.Error()
resp, err := json.Marshal(response)
@@ -367,7 +239,11 @@ func (a kmsAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Reque
}
// 2. Verify that we can indeed decrypt the (encrypted) key
decryptedKey, err := GlobalKMS.DecryptKey(key.KeyID, key.Ciphertext, kmsContext)
decryptedKey, err := GlobalKMS.Decrypt(ctx, &kms.DecryptRequest{
Name: key.KeyID,
Ciphertext: key.Ciphertext,
AssociatedData: kmsContext,
})
if err != nil {
response.DecryptionErr = err.Error()
resp, err := json.Marshal(response)
@@ -398,296 +274,3 @@ func (a kmsAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Reque
}
writeSuccessResponseJSON(w, resp)
}
// KMSDescribePolicyHandler - GET /minio/kms/v1/policy/describe?policy=<policy>
func (a kmsAPIHandlers) KMSDescribePolicyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSDescribePolicy")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSDescribePolicyAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.PolicyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
policy, err := manager.DescribePolicy(ctx, r.Form.Get("policy"))
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
p, err := json.Marshal(policy)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
writeSuccessResponseJSON(w, p)
}
// KMSAssignPolicyHandler - POST /minio/kms/v1/policy/assign?policy=<policy>
func (a kmsAPIHandlers) KMSAssignPolicyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSAssignPolicy")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSAssignPolicyAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
// KMSDeletePolicyHandler - DELETE /minio/kms/v1/policy/delete?policy=<policy>
func (a kmsAPIHandlers) KMSDeletePolicyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSDeletePolicy")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSDeletePolicyAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
// KMSListPoliciesHandler - GET /minio/kms/v1/policy/list?pattern=<pattern>
func (a kmsAPIHandlers) KMSListPoliciesHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSListPolicies")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSListPoliciesAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.PolicyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
policies, err := manager.ListPolicies(ctx)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
pattern := r.Form.Get("pattern")
if !strings.Contains(pattern, "*") {
pattern += "*"
}
var values []kes.PolicyInfo
for name, err := policies.SeekTo(ctx, pattern); err != io.EOF; name, err = policies.Next(ctx) {
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
values = append(values, kes.PolicyInfo{
Name: name,
})
}
if res, err := json.Marshal(values); err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
} else {
writeSuccessResponseJSON(w, res)
}
}
// KMSGetPolicyHandler - GET /minio/kms/v1/policy/get?policy=<policy>
func (a kmsAPIHandlers) KMSGetPolicyHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSGetPolicy")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSGetPolicyAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.PolicyManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
policy, err := manager.GetPolicy(ctx, r.Form.Get("policy"))
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
if p, err := json.Marshal(policy); err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
} else {
writeSuccessResponseJSON(w, p)
}
}
// KMSDescribeIdentityHandler - GET /minio/kms/v1/identity/describe?identity=<identity>
func (a kmsAPIHandlers) KMSDescribeIdentityHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSDescribeIdentity")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSDescribeIdentityAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.IdentityManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
identity, err := manager.DescribeIdentity(ctx, r.Form.Get("identity"))
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
i, err := json.Marshal(identity)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
writeSuccessResponseJSON(w, i)
}
type describeSelfIdentityResponse struct {
Policy *kes.Policy `json:"policy"`
PolicyName string `json:"policyName"`
Identity string `json:"identity"`
IsAdmin bool `json:"isAdmin"`
CreatedAt time.Time `json:"createdAt"`
CreatedBy string `json:"createdBy"`
}
// KMSDescribeSelfIdentityHandler - GET /minio/kms/v1/identity/describe-self
func (a kmsAPIHandlers) KMSDescribeSelfIdentityHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSDescribeSelfIdentity")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSDescribeSelfIdentityAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.IdentityManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
identity, policy, err := manager.DescribeSelfIdentity(ctx)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
res := &describeSelfIdentityResponse{
Policy: policy,
PolicyName: identity.Policy,
Identity: identity.Identity.String(),
IsAdmin: identity.IsAdmin,
CreatedAt: identity.CreatedAt,
CreatedBy: identity.CreatedBy.String(),
}
i, err := json.Marshal(res)
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
writeSuccessResponseJSON(w, i)
}
// KMSDeleteIdentityHandler - DELETE /minio/kms/v1/identity/delete?identity=<identity>
func (a kmsAPIHandlers) KMSDeleteIdentityHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSDeleteIdentity")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSDeleteIdentityAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
// KMSListIdentitiesHandler - GET /minio/kms/v1/identity/list?pattern=<pattern>
func (a kmsAPIHandlers) KMSListIdentitiesHandler(w http.ResponseWriter, r *http.Request) {
ctx := newContext(r, w, "KMSListIdentities")
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
objectAPI, _ := validateAdminReq(ctx, w, r, policy.KMSListIdentitiesAction)
if objectAPI == nil {
return
}
if GlobalKMS == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL)
return
}
manager, ok := GlobalKMS.(kms.IdentityManager)
if !ok {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
return
}
identities, err := manager.ListIdentities(ctx)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
pattern := r.Form.Get("pattern")
if !strings.Contains(pattern, "*") {
pattern += "*"
}
var values []kes.IdentityInfo
for name, err := identities.SeekTo(ctx, pattern); err != io.EOF; name, err = identities.Next(ctx) {
if err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
return
}
values = append(values, kes.IdentityInfo{
Identity: name,
})
}
if res, err := json.Marshal(values); err != nil {
writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL)
} else {
writeSuccessResponseJSON(w, res)
}
}

View File

@@ -57,23 +57,8 @@ func registerKMSRouter(router *mux.Router) {
kmsRouter.Methods(http.MethodGet).Path(version + "/version").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSVersionHandler)))
// KMS Key APIs
kmsRouter.Methods(http.MethodPost).Path(version+"/key/create").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSCreateKeyHandler))).Queries("key-id", "{key-id:.*}")
kmsRouter.Methods(http.MethodPost).Path(version+"/key/import").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSImportKeyHandler))).Queries("key-id", "{key-id:.*}")
kmsRouter.Methods(http.MethodDelete).Path(version+"/key/delete").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSDeleteKeyHandler))).Queries("key-id", "{key-id:.*}")
kmsRouter.Methods(http.MethodGet).Path(version+"/key/list").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSListKeysHandler))).Queries("pattern", "{pattern:.*}")
kmsRouter.Methods(http.MethodGet).Path(version + "/key/status").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSKeyStatusHandler)))
// KMS Policy APIs
kmsRouter.Methods(http.MethodPost).Path(version+"/policy/assign").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSAssignPolicyHandler))).Queries("policy", "{policy:.*}")
kmsRouter.Methods(http.MethodGet).Path(version+"/policy/describe").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSDescribePolicyHandler))).Queries("policy", "{policy:.*}")
kmsRouter.Methods(http.MethodGet).Path(version+"/policy/get").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSGetPolicyHandler))).Queries("policy", "{policy:.*}")
kmsRouter.Methods(http.MethodDelete).Path(version+"/policy/delete").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSDeletePolicyHandler))).Queries("policy", "{policy:.*}")
kmsRouter.Methods(http.MethodGet).Path(version+"/policy/list").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSListPoliciesHandler))).Queries("pattern", "{pattern:.*}")
// KMS Identity APIs
kmsRouter.Methods(http.MethodGet).Path(version+"/identity/describe").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSDescribeIdentityHandler))).Queries("identity", "{identity:.*}")
kmsRouter.Methods(http.MethodGet).Path(version + "/identity/describe-self").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSDescribeSelfIdentityHandler)))
kmsRouter.Methods(http.MethodDelete).Path(version+"/identity/delete").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSDeleteIdentityHandler))).Queries("identity", "{identity:.*}")
kmsRouter.Methods(http.MethodGet).Path(version+"/identity/list").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSListIdentitiesHandler))).Queries("pattern", "{pattern:.*}")
}
// If none of the routes match add default error handler routes

View File

@@ -3970,7 +3970,7 @@ func getKMSMetrics(opts MetricsGroupOpts) *MetricsGroupV2 {
Help: "Number of KMS requests that succeeded",
Type: counterMetric,
},
Value: float64(metric.RequestOK),
Value: float64(metric.ReqOK),
})
metrics = append(metrics, MetricV2{
Description: MetricDescription{
@@ -3980,7 +3980,7 @@ func getKMSMetrics(opts MetricsGroupOpts) *MetricsGroupV2 {
Help: "Number of KMS requests that failed due to some error. (HTTP 4xx status code)",
Type: counterMetric,
},
Value: float64(metric.RequestErr),
Value: float64(metric.ReqErr),
})
metrics = append(metrics, MetricV2{
Description: MetricDescription{
@@ -3990,19 +3990,8 @@ func getKMSMetrics(opts MetricsGroupOpts) *MetricsGroupV2 {
Help: "Number of KMS requests that failed due to some internal failure. (HTTP 5xx status code)",
Type: counterMetric,
},
Value: float64(metric.RequestFail),
Value: float64(metric.ReqFail),
})
metrics = append(metrics, MetricV2{
Description: MetricDescription{
Namespace: clusterMetricNamespace,
Subsystem: kmsSubsystem,
Name: kmsUptime,
Help: "The time the KMS has been up and running in seconds.",
Type: counterMetric,
},
Value: metric.UpTime.Seconds(),
})
return metrics
})
return mg

View File

@@ -521,11 +521,11 @@ func enableCompression(t *testing.T, encrypt bool) {
globalCompressConfigMu.Unlock()
if encrypt {
globalAutoEncryption = encrypt
var err error
GlobalKMS, err = kms.Parse("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=")
KMS, err := kms.ParseSecretKey("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=")
if err != nil {
t.Fatal(err)
}
GlobalKMS = KMS
}
}
@@ -536,11 +536,11 @@ func enableEncryption(t *testing.T) {
globalCompressConfigMu.Unlock()
globalAutoEncryption = true
var err error
GlobalKMS, err = kms.Parse("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=")
KMS, err := kms.ParseSecretKey("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=")
if err != nil {
t.Fatal(err)
}
GlobalKMS = KMS
}
func resetCompressEncryption() {

View File

@@ -856,12 +856,7 @@ func (c *SiteReplicationSys) MakeBucketHook(ctx context.Context, bucket string,
if err := errors.Unwrap(makeBucketConcErr); err != nil {
return err
}
if err := errors.Unwrap(makeRemotesConcErr); err != nil {
return err
}
return nil
return errors.Unwrap(makeRemotesConcErr)
}
// DeleteBucketHook - called during a regular delete bucket call when cluster