diff --git a/CREDITS b/CREDITS index d4e4f7deb..840059469 100644 --- a/CREDITS +++ b/CREDITS @@ -18064,8 +18064,8 @@ https://github.com/minio/highwayhash ================================================================ -github.com/minio/kes-go -https://github.com/minio/kes-go +github.com/minio/kms-go +https://github.com/minio/kms-go ---------------------------------------------------------------- GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 diff --git a/cmd/admin-bucket-handlers.go b/cmd/admin-bucket-handlers.go index 811555055..a96cef411 100644 --- a/cmd/admin-bucket-handlers.go +++ b/cmd/admin-bucket-handlers.go @@ -31,7 +31,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/klauspost/compress/zip" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/madmin-go/v3" "github.com/minio/minio-go/v7/pkg/tags" "github.com/minio/minio/internal/bucket/lifecycle" diff --git a/cmd/admin-handler-utils.go b/cmd/admin-handler-utils.go index 4c4aa707e..3466c2973 100644 --- a/cmd/admin-handler-utils.go +++ b/cmd/admin-handler-utils.go @@ -23,7 +23,7 @@ import ( "fmt" "net/http" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/madmin-go/v3" "github.com/minio/minio/internal/auth" "github.com/minio/minio/internal/config" diff --git a/cmd/bucket-encryption-handlers.go b/cmd/bucket-encryption-handlers.go index 0a94978d2..7b5c0cad8 100644 --- a/cmd/bucket-encryption-handlers.go +++ b/cmd/bucket-encryption-handlers.go @@ -25,7 +25,7 @@ import ( "io" "net/http" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/madmin-go/v3" "github.com/minio/minio/internal/kms" "github.com/minio/minio/internal/logger" diff --git a/cmd/common-main.go b/cmd/common-main.go index 8d775e2f7..2a06e02b3 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -27,7 +27,6 @@ import ( "encoding/pem" "errors" "fmt" - "math/rand" "net" "net/url" "os" @@ -50,7 +49,7 @@ 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/kes-go" + "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" @@ -83,8 +82,6 @@ func init() { } } - rand.Seed(time.Now().UTC().UnixNano()) - logger.Init(GOPATH, GOROOT) logger.RegisterError(config.FmtError) @@ -900,7 +897,6 @@ func handleKMSConfig() { } kmsConf = kms.Config{ Endpoints: endpoints, - Enclave: env.Get(kms.EnvKESEnclave, ""), DefaultKeyID: env.Get(kms.EnvKESKeyName, ""), APIKey: key, RootCAs: rootCAs, @@ -946,7 +942,6 @@ func handleKMSConfig() { kmsConf = kms.Config{ Endpoints: endpoints, - Enclave: env.Get(kms.EnvKESEnclave, ""), DefaultKeyID: env.Get(kms.EnvKESKeyName, ""), Certificate: certificate, ReloadCertEvents: reloadCertEvents, diff --git a/cmd/config-current.go b/cmd/config-current.go index 9cedb00a1..03774f439 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -18,13 +18,17 @@ package cmd import ( + "bytes" "context" "errors" "fmt" "strings" "sync" + "github.com/minio/kms-go/kes" + "github.com/minio/minio/internal/auth" "github.com/minio/minio/internal/config/browser" + "github.com/minio/minio/internal/kms" "github.com/minio/madmin-go/v3" "github.com/minio/minio/internal/config" @@ -569,6 +573,7 @@ func applyDynamicConfigForSubSys(ctx context.Context, objAPI ObjectLayer, s conf } globalAPIConfig.init(apiConfig, setDriveCounts) + autoGenerateRootCredentials() // Generate the KMS root credentials here since we don't know whether API root access is disabled until now. // Initialize remote instance transport once. getRemoteInstanceTransportOnce.Do(func() { @@ -720,6 +725,55 @@ func applyDynamicConfigForSubSys(ctx context.Context, objAPI ObjectLayer, s conf return nil } +// autoGenerateRootCredentials generates root credentials deterministically if +// a KMS is configured, no manual credentials have been specified and if root +// access is disabled. +func autoGenerateRootCredentials() { + if GlobalKMS == nil { + return + } + if globalAPIConfig.permitRootAccess() || !globalActiveCred.Equal(auth.DefaultCredentials) { + return + } + + if manager, ok := GlobalKMS.(kms.KeyManager); ok { + stat, err := GlobalKMS.Stat(GlobalContext) + if err != nil { + logger.LogIf(GlobalContext, err, "Unable to generate root credentials using KMS") + return + } + + 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 := 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") + } + + logger.Info("Automatically generated root access key and secret key with the KMS") + globalActiveCred = auth.Credentials{ + AccessKey: accessKey, + SecretKey: secretKey, + } + } +} + // applyDynamicConfig will apply dynamic config values. // Dynamic systems should be in config.SubSystemsDynamic as well. func applyDynamicConfig(ctx context.Context, objAPI ObjectLayer, s config.Config) error { diff --git a/cmd/encryption-v1.go b/cmd/encryption-v1.go index 14b4b8103..c112724c8 100644 --- a/cmd/encryption-v1.go +++ b/cmd/encryption-v1.go @@ -34,7 +34,7 @@ import ( "strconv" "strings" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/minio/internal/crypto" "github.com/minio/minio/internal/etag" "github.com/minio/minio/internal/fips" diff --git a/cmd/kms-handlers.go b/cmd/kms-handlers.go index aee3c3e87..e496b484a 100644 --- a/cmd/kms-handlers.go +++ b/cmd/kms-handlers.go @@ -25,7 +25,7 @@ import ( "strings" "time" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/madmin-go/v3" "github.com/minio/minio/internal/kms" "github.com/minio/minio/internal/logger" @@ -431,10 +431,6 @@ func (a kmsAPIHandlers) KMSDescribePolicyHandler(w http.ResponseWriter, r *http. writeSuccessResponseJSON(w, p) } -type assignPolicyRequest struct { - Identity string -} - // KMSAssignPolicyHandler - POST /minio/kms/v1/policy/assign?policy= func (a kmsAPIHandlers) KMSAssignPolicyHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "KMSAssignPolicy") @@ -449,22 +445,8 @@ func (a kmsAPIHandlers) KMSAssignPolicyHandler(w http.ResponseWriter, r *http.Re 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 - } - var request assignPolicyRequest - if err := json.NewDecoder(r.Body).Decode(&request); err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - err := manager.AssignPolicy(ctx, r.Form.Get("policy"), request.Identity) - if err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - writeSuccessResponseHeadersOnly(w) + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return } // KMSDeletePolicyHandler - DELETE /minio/kms/v1/policy/delete?policy= @@ -481,17 +463,8 @@ func (a kmsAPIHandlers) KMSDeletePolicyHandler(w http.ResponseWriter, r *http.Re 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 - } - if err := manager.DeletePolicy(ctx, r.Form.Get("policy")); err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - writeSuccessResponseHeadersOnly(w) + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return } // KMSListPoliciesHandler - GET /minio/kms/v1/policy/list?pattern= @@ -668,17 +641,8 @@ func (a kmsAPIHandlers) KMSDeleteIdentityHandler(w http.ResponseWriter, r *http. 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 - } - - if err := manager.DeleteIdentity(ctx, r.Form.Get("policy")); err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - writeSuccessResponseHeadersOnly(w) + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return } // KMSListIdentitiesHandler - GET /minio/kms/v1/identity/list?pattern= diff --git a/cmd/metrics-v2.go b/cmd/metrics-v2.go index b6e8cf905..8ea678a7d 100644 --- a/cmd/metrics-v2.go +++ b/cmd/metrics-v2.go @@ -29,7 +29,7 @@ import ( "sync/atomic" "time" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/madmin-go/v3" "github.com/minio/minio/internal/bucket/lifecycle" "github.com/minio/minio/internal/cachevalue" diff --git a/cmd/server-startup-msg.go b/cmd/server-startup-msg.go index 6061fb0f4..bd3ab1a35 100644 --- a/cmd/server-startup-msg.go +++ b/cmd/server-startup-msg.go @@ -121,7 +121,7 @@ func printServerCommonMsg(apiEndpoints []string) { // Colorize the message and print. logger.Info(color.Blue("S3-API: ") + color.Bold(fmt.Sprintf("%s ", apiEndpointStr))) - if color.IsTerminal() && (!globalServerCtxt.Anonymous && !globalServerCtxt.JSON) { + if color.IsTerminal() && (!globalServerCtxt.Anonymous && !globalServerCtxt.JSON && globalAPIConfig.permitRootAccess()) { logger.Info(color.Blue("RootUser: ") + color.Bold("%s ", cred.AccessKey)) logger.Info(color.Blue("RootPass: ") + color.Bold("%s \n", cred.SecretKey)) if region != "" { @@ -132,7 +132,7 @@ func printServerCommonMsg(apiEndpoints []string) { if globalBrowserEnabled { consoleEndpointStr := strings.Join(stripStandardPorts(getConsoleEndpoints(), globalMinioConsoleHost), " ") logger.Info(color.Blue("Console: ") + color.Bold(fmt.Sprintf("%s ", consoleEndpointStr))) - if color.IsTerminal() && (!globalServerCtxt.Anonymous && !globalServerCtxt.JSON) { + if color.IsTerminal() && (!globalServerCtxt.Anonymous && !globalServerCtxt.JSON && globalAPIConfig.permitRootAccess()) { logger.Info(color.Blue("RootUser: ") + color.Bold("%s ", cred.AccessKey)) logger.Info(color.Blue("RootPass: ") + color.Bold("%s ", cred.SecretKey)) } @@ -187,7 +187,7 @@ func printCLIAccessMsg(endPoint string, alias string) { const mcQuickStartGuide = "https://min.io/docs/minio/linux/reference/minio-mc.html#quickstart" // Configure 'mc', following block prints platform specific information for minio client. - if color.IsTerminal() && !globalServerCtxt.Anonymous { + if color.IsTerminal() && (!globalServerCtxt.Anonymous && globalAPIConfig.permitRootAccess()) { logger.Info(color.Blue("\nCommand-line: ") + mcQuickStartGuide) mcMessage := fmt.Sprintf("$ mc alias set '%s' '%s' '%s' '%s'", alias, endPoint, cred.AccessKey, cred.SecretKey) diff --git a/go.mod b/go.mod index 3ab19b5e7..c1e290e5d 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/minio/dnscache v0.1.1 github.com/minio/dperf v0.5.3 github.com/minio/highwayhash v1.0.2 - github.com/minio/kes-go v0.2.1 + github.com/minio/kms-go/kes v0.3.0 github.com/minio/madmin-go/v3 v3.0.49 github.com/minio/minio-go/v7 v7.0.67 github.com/minio/mux v1.9.0 diff --git a/go.sum b/go.sum index 441806cf0..bacc8c0c4 100644 --- a/go.sum +++ b/go.sum @@ -444,10 +444,10 @@ github.com/minio/filepath v1.0.0 h1:fvkJu1+6X+ECRA6G3+JJETj4QeAYO9sV43I79H8ubDY= github.com/minio/filepath v1.0.0/go.mod h1:/nRZA2ldl5z6jT9/KQuvZcQlxZIMQoFFQPvEXx9T/Bw= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/kes-go v0.2.1 h1:KnqS+p6xoSFJZbQhmJaz/PbxeA6nQyRqT/ywrn5lU2o= -github.com/minio/kes-go v0.2.1/go.mod h1:76xf7l41Wrh+IifisABXK2S8uZWYgWV1IGBKC3GdOJk= github.com/minio/madmin-go/v3 v3.0.49 h1:Ag5eyYUf9K1MvW9hiErEJhGfqlf//pOtlhdoepb9AwY= github.com/minio/madmin-go/v3 v3.0.49/go.mod h1:ZDF7kf5fhmxLhbGTqyq5efs4ao0v4eWf7nOuef/ljJs= +github.com/minio/kms-go/kes v0.3.0 h1:SU8VGVM/Hk9w1OiSby3OatkcojooUqIdDHl6dtM6NkY= +github.com/minio/kms-go/kes v0.3.0/go.mod h1:w6DeVT878qEOU3nUrYVy1WOT5H1Ig9hbDIh698NYJKY= github.com/minio/mc v0.0.0-20240209221824-669cb0a9a475 h1:yfLzMougcV2xkVlWgwYwVRoT8pnXrcCV4oOQW+pI2EQ= github.com/minio/mc v0.0.0-20240209221824-669cb0a9a475/go.mod h1:MmDLdb7NWd/OYhcKcXKvwErq2GNa/Zq6xtTWuhdC4II= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= diff --git a/internal/auth/credentials.go b/internal/auth/credentials.go index 7e2383395..35e2dbb8d 100644 --- a/internal/auth/credentials.go +++ b/internal/auth/credentials.go @@ -24,6 +24,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "strconv" "strings" "time" @@ -211,39 +212,70 @@ func ExpToInt64(expI interface{}) (expAt int64, err error) { // GenerateCredentials - creates randomly generated credentials of maximum // allowed length. func GenerateCredentials() (accessKey, secretKey string, err error) { - readBytes := func(size int) (data []byte, err error) { - data = make([]byte, size) - var n int - if n, err = rand.Read(data); err != nil { - return nil, err - } else if n != size { - return nil, fmt.Errorf("Not enough data. Expected to read: %v bytes, got: %v bytes", size, n) - } - return data, nil - } - - // Generate access key. - keyBytes, err := readBytes(accessKeyMaxLen) + accessKey, err = GenerateAccessKey(accessKeyMaxLen, rand.Reader) if err != nil { return "", "", err } - for i := 0; i < accessKeyMaxLen; i++ { - keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen] - } - accessKey = string(keyBytes) - - // Generate secret key. - keyBytes, err = readBytes(secretKeyMaxLen) + secretKey, err = GenerateSecretKey(secretKeyMaxLen, rand.Reader) if err != nil { return "", "", err } - - secretKey = strings.ReplaceAll(string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen]), - "/", "+") - return accessKey, secretKey, nil } +// GenerateAccessKey returns a new access key generated randomly using +// the given io.Reader. If random is nil, crypto/rand.Reader is used. +// If length <= 0, the access key length is chosen automatically. +// +// GenerateAccessKey returns an error if length is too small for a valid +// access key. +func GenerateAccessKey(length int, random io.Reader) (string, error) { + if random == nil { + random = rand.Reader + } + if length <= 0 { + length = accessKeyMaxLen + } + if length < accessKeyMinLen { + return "", errors.New("auth: access key length is too short") + } + + key := make([]byte, length) + if _, err := io.ReadFull(random, key); err != nil { + return "", err + } + for i := range key { + key[i] = alphaNumericTable[key[i]%alphaNumericTableLen] + } + return string(key), nil +} + +// GenerateSecretKey returns a new secret key generated randomly using +// the given io.Reader. If random is nil, crypto/rand.Reader is used. +// If length <= 0, the secret key length is chosen automatically. +// +// GenerateSecretKey returns an error if length is too small for a valid +// secret key. +func GenerateSecretKey(length int, random io.Reader) (string, error) { + if random == nil { + random = rand.Reader + } + if length <= 0 { + length = secretKeyMaxLen + } + if length < secretKeyMinLen { + return "", errors.New("auth: secret key length is too short") + } + + key := make([]byte, base64.RawStdEncoding.DecodedLen(length)) + if _, err := io.ReadFull(random, key); err != nil { + return "", err + } + + s := base64.RawStdEncoding.EncodeToString(key) + return strings.ReplaceAll(s, "/", "+"), nil +} + // GetNewCredentialsWithMetadata generates and returns new credential with expiry. func GetNewCredentialsWithMetadata(m map[string]interface{}, tokenSecret string) (Credentials, error) { accessKey, secretKey, err := GenerateCredentials() diff --git a/internal/auth/credentials_test.go b/internal/auth/credentials_test.go index 41a04ad49..643cab319 100644 --- a/internal/auth/credentials_test.go +++ b/internal/auth/credentials_test.go @@ -148,11 +148,11 @@ func TestCreateCredentials(t *testing.T) { func TestCredentialsEqual(t *testing.T) { cred, err := GetNewCredentials() if err != nil { - t.Fatalf("Failed to get a new credential") + t.Fatalf("Failed to get a new credential: %v", err) } cred2, err := GetNewCredentials() if err != nil { - t.Fatalf("Failed to get a new credential") + t.Fatalf("Failed to get a new credential: %v", err) } testCases := []struct { cred Credentials diff --git a/internal/kms/config.go b/internal/kms/config.go index ace90efb1..f19352ac3 100644 --- a/internal/kms/config.go +++ b/internal/kms/config.go @@ -22,7 +22,6 @@ const ( EnvKMSSecretKey = "MINIO_KMS_SECRET_KEY" EnvKMSSecretKeyFile = "MINIO_KMS_SECRET_KEY_FILE" EnvKESEndpoint = "MINIO_KMS_KES_ENDPOINT" // One or multiple KES endpoints, separated by ',' - EnvKESEnclave = "MINIO_KMS_KES_ENCLAVE" // Optional "namespace" within a KES cluster - not required for stateless KES EnvKESKeyName = "MINIO_KMS_KES_KEY_NAME" // The default key name used for IAM data and when no key ID is specified on a bucket EnvKESAPIKey = "MINIO_KMS_KES_API_KEY" // Access credential for KES - API keys and private key / certificate are mutually exclusive EnvKESClientKey = "MINIO_KMS_KES_KEY_FILE" // Path to TLS private key for authenticating to KES with mTLS - usually prefer API keys diff --git a/internal/kms/identity-manager.go b/internal/kms/identity-manager.go index 4c0d7ab84..ad3a1e8ae 100644 --- a/internal/kms/identity-manager.go +++ b/internal/kms/identity-manager.go @@ -20,7 +20,7 @@ package kms import ( "context" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" ) // IdentityManager is the generic interface that handles KMS identity operations @@ -34,11 +34,6 @@ type IdentityManager interface { // It returns the identity and policy information for the client identity. DescribeSelfIdentity(ctx context.Context) (*kes.IdentityInfo, *kes.Policy, error) - // DeleteIdentity deletes an identity from KMS. - // The client certificate that corresponds to the identity is no longer authorized to perform any API operations. - // The admin identity cannot be deleted. - DeleteIdentity(ctx context.Context, identity string) error - // ListIdentities lists all identities. ListIdentities(ctx context.Context) (*kes.ListIter[kes.Identity], error) } diff --git a/internal/kms/kes.go b/internal/kms/kes.go index 6d83f4faf..8a9d94300 100644 --- a/internal/kms/kes.go +++ b/internal/kms/kes.go @@ -28,7 +28,7 @@ import ( "strings" "sync" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/pkg/v2/certs" "github.com/minio/pkg/v2/env" ) @@ -45,11 +45,6 @@ type Config struct { // HTTP endpoints. Endpoints []string - // Enclave is the KES server enclave. If empty, - // none resp. the default KES server enclave - // will be used. - Enclave string - // DefaultKeyID is the key ID used when // no explicit key ID is specified for // a cryptographic operation. @@ -106,7 +101,6 @@ func NewWithConfig(config Config) (KMS, error) { c := &kesClient{ client: client, - enclave: client.Enclave(config.Enclave), defaultKeyID: config.DefaultKeyID, } go func() { @@ -138,7 +132,6 @@ func NewWithConfig(config Config) (KMS, error) { c.lock.Lock() c.client = client - c.enclave = c.client.Enclave(config.Enclave) c.lock.Unlock() prevCertificate = certificate @@ -152,7 +145,6 @@ type kesClient struct { lock sync.RWMutex defaultKeyID string client *kes.Client - enclave *kes.Enclave } var ( // compiler checks @@ -235,7 +227,7 @@ func (c *kesClient) CreateKey(ctx context.Context, keyID string) error { c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.CreateKey(ctx, keyID) + return c.client.CreateKey(ctx, keyID) } // DeleteKey deletes a key at the KMS with the given key ID. @@ -246,7 +238,7 @@ func (c *kesClient) DeleteKey(ctx context.Context, keyID string) error { c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.DeleteKey(ctx, keyID) + return c.client.DeleteKey(ctx, keyID) } // ListKeys returns an iterator over all key names. @@ -255,7 +247,7 @@ func (c *kesClient) ListKeys(ctx context.Context) (*kes.ListIter[string], error) defer c.lock.RUnlock() return &kes.ListIter[string]{ - NextFunc: c.enclave.ListKeys, + NextFunc: c.client.ListKeys, }, nil } @@ -279,7 +271,7 @@ func (c *kesClient) GenerateKey(ctx context.Context, keyID string, cryptoCtx Con return DEK{}, err } - dek, err := c.enclave.GenerateKey(ctx, keyID, ctxBytes) + dek, err := c.client.GenerateKey(ctx, keyID, ctxBytes) if err != nil { return DEK{}, err } @@ -295,7 +287,7 @@ func (c *kesClient) ImportKey(ctx context.Context, keyID string, bytes []byte) e c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.ImportKey(ctx, keyID, &kes.ImportKeyRequest{ + return c.client.ImportKey(ctx, keyID, &kes.ImportKeyRequest{ Key: bytes, }) } @@ -310,7 +302,7 @@ func (c *kesClient) EncryptKey(keyID string, plaintext []byte, ctx Context) ([]b if err != nil { return nil, err } - return c.enclave.Encrypt(context.Background(), keyID, plaintext, ctxBytes) + return c.client.Encrypt(context.Background(), keyID, plaintext, ctxBytes) } // DecryptKey decrypts the ciphertext with the key at the KES @@ -324,7 +316,7 @@ func (c *kesClient) DecryptKey(keyID string, ciphertext []byte, ctx Context) ([] if err != nil { return nil, err } - return c.enclave.Decrypt(context.Background(), keyID, ciphertext, ctxBytes) + return c.client.Decrypt(context.Background(), keyID, ciphertext, ctxBytes) } func (c *kesClient) DecryptAll(ctx context.Context, keyID string, ciphertexts [][]byte, contexts []Context) ([][]byte, error) { @@ -337,7 +329,7 @@ func (c *kesClient) DecryptAll(ctx context.Context, keyID string, ciphertexts [] if err != nil { return nil, err } - plaintext, err := c.enclave.Decrypt(ctx, keyID, ciphertexts[i], ctxBytes) + plaintext, err := c.client.Decrypt(ctx, keyID, ciphertexts[i], ctxBytes) if err != nil { return nil, err } @@ -346,34 +338,22 @@ func (c *kesClient) DecryptAll(ctx context.Context, keyID string, ciphertexts [] return plaintexts, nil } +// HMAC generates the HMAC checksum of the given msg using the key +// with the given keyID at the KMS. +func (c *kesClient) HMAC(ctx context.Context, keyID string, msg []byte) ([]byte, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + return c.client.HMAC(context.Background(), keyID, msg) +} + // DescribePolicy describes a policy by returning its metadata. // e.g. who created the policy at which point in time. func (c *kesClient) DescribePolicy(ctx context.Context, policy string) (*kes.PolicyInfo, error) { c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.DescribePolicy(ctx, policy) -} - -// AssignPolicy assigns a policy to an identity. -// An identity can have at most one policy while the same policy can be assigned to multiple identities. -// The assigned policy defines which API calls this identity can perform. -// It's not possible to assign a policy to the admin identity. -// Further, an identity cannot assign a policy to itself. -func (c *kesClient) AssignPolicy(ctx context.Context, policy, identity string) error { - c.lock.RLock() - defer c.lock.RUnlock() - - return c.enclave.AssignPolicy(ctx, policy, kes.Identity(identity)) -} - -// DeletePolicy deletes a policy from KMS. -// All identities that have been assigned to this policy will lose all authorization privileges. -func (c *kesClient) DeletePolicy(ctx context.Context, policy string) error { - c.lock.RLock() - defer c.lock.RUnlock() - - return c.enclave.DeletePolicy(ctx, policy) + return c.client.DescribePolicy(ctx, policy) } // ListPolicies returns an iterator over all policy names. @@ -382,7 +362,7 @@ func (c *kesClient) ListPolicies(ctx context.Context) (*kes.ListIter[string], er defer c.lock.RUnlock() return &kes.ListIter[string]{ - NextFunc: c.enclave.ListPolicies, + NextFunc: c.client.ListPolicies, }, nil } @@ -391,7 +371,7 @@ func (c *kesClient) GetPolicy(ctx context.Context, policy string) (*kes.Policy, c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.GetPolicy(ctx, policy) + return c.client.GetPolicy(ctx, policy) } // DescribeIdentity describes an identity by returning its metadata. @@ -400,7 +380,7 @@ func (c *kesClient) DescribeIdentity(ctx context.Context, identity string) (*kes c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.DescribeIdentity(ctx, kes.Identity(identity)) + return c.client.DescribeIdentity(ctx, kes.Identity(identity)) } // DescribeSelfIdentity describes the identity issuing the request. @@ -410,17 +390,7 @@ func (c *kesClient) DescribeSelfIdentity(ctx context.Context) (*kes.IdentityInfo c.lock.RLock() defer c.lock.RUnlock() - return c.enclave.DescribeSelf(ctx) -} - -// DeleteIdentity deletes an identity from KMS. -// The client certificate that corresponds to the identity is no longer authorized to perform any API operations. -// The admin identity cannot be deleted. -func (c *kesClient) DeleteIdentity(ctx context.Context, identity string) error { - c.lock.RLock() - defer c.lock.RUnlock() - - return c.enclave.DeleteIdentity(ctx, kes.Identity(identity)) + return c.client.DescribeSelf(ctx) } // ListPolicies returns an iterator over all identities. @@ -429,7 +399,7 @@ func (c *kesClient) ListIdentities(ctx context.Context) (*kes.ListIter[kes.Ident defer c.lock.RUnlock() return &kes.ListIter[kes.Identity]{ - NextFunc: c.enclave.ListIdentities, + NextFunc: c.client.ListIdentities, }, nil } diff --git a/internal/kms/key-manager.go b/internal/kms/key-manager.go index dcbc65e2e..414272d50 100644 --- a/internal/kms/key-manager.go +++ b/internal/kms/key-manager.go @@ -20,7 +20,7 @@ package kms import ( "context" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" ) // KeyManager is the generic interface that handles KMS key operations @@ -43,4 +43,8 @@ type KeyManager interface { // EncryptKey Encrypts and authenticates a (small) plaintext with the cryptographic key // The plaintext must not exceed 1 MB EncryptKey(keyID string, plaintext []byte, context Context) ([]byte, error) + + // HMAC computes the HMAC of the given msg and key with the given + // key ID. + HMAC(ctx context.Context, keyID string, msg []byte) ([]byte, error) } diff --git a/internal/kms/kms.go b/internal/kms/kms.go index f2b9ec24b..04bfee7ba 100644 --- a/internal/kms/kms.go +++ b/internal/kms/kms.go @@ -23,7 +23,7 @@ import ( "encoding/json" jsoniter "github.com/json-iterator/go" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" ) // KMS is the generic interface that abstracts over diff --git a/internal/kms/policy-manager.go b/internal/kms/policy-manager.go index bf519f8c6..0428065d6 100644 --- a/internal/kms/policy-manager.go +++ b/internal/kms/policy-manager.go @@ -20,7 +20,7 @@ package kms import ( "context" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" ) // PolicyManager is the generic interface that handles KMS policy] operations @@ -29,20 +29,9 @@ type PolicyManager interface { // e.g. who created the policy at which point in time. DescribePolicy(ctx context.Context, policy string) (*kes.PolicyInfo, error) - // AssignPolicy assigns a policy to an identity. - // An identity can have at most one policy while the same policy can be assigned to multiple identities. - // The assigned policy defines which API calls this identity can perform. - // It's not possible to assign a policy to the admin identity. - // Further, an identity cannot assign a policy to itself. - AssignPolicy(ctx context.Context, policy, identity string) error - // GetPolicy gets a policy from KMS. GetPolicy(ctx context.Context, policy string) (*kes.Policy, error) // ListPolicies lists all policies. ListPolicies(ctx context.Context) (*kes.ListIter[string], error) - - // DeletePolicy deletes a policy from KMS. - // All identities that have been assigned to this policy will lose all authorization privileges. - DeletePolicy(ctx context.Context, policy string) error } diff --git a/internal/kms/single-key.go b/internal/kms/single-key.go index bfb29b34d..ab77775fc 100644 --- a/internal/kms/single-key.go +++ b/internal/kms/single-key.go @@ -34,7 +34,7 @@ import ( "golang.org/x/crypto/chacha20" "golang.org/x/crypto/chacha20poly1305" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" "github.com/minio/minio/internal/hash/sha256" ) diff --git a/internal/kms/status-manager.go b/internal/kms/status-manager.go index 533eb77a6..d005b163f 100644 --- a/internal/kms/status-manager.go +++ b/internal/kms/status-manager.go @@ -20,7 +20,7 @@ package kms import ( "context" - "github.com/minio/kes-go" + "github.com/minio/kms-go/kes" ) // StatusManager is the generic interface that handles KMS status operations