diff --git a/cmd/kms-handlers.go b/cmd/kms-handlers.go index 39fe31fdd..ce5017c1f 100644 --- a/cmd/kms-handlers.go +++ b/cmd/kms-handlers.go @@ -22,7 +22,6 @@ import ( "encoding/json" "net/http" - "github.com/minio/kms-go/kes" "github.com/minio/madmin-go/v3" "github.com/minio/minio/internal/auth" "github.com/minio/minio/internal/kms" @@ -197,7 +196,7 @@ func (a kmsAPIHandlers) KMSListKeysHandler(w http.ResponseWriter, r *http.Reques writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL) return } - allKeyNames, _, err := GlobalKMS.ListKeyNames(ctx, &kms.ListRequest{ + allKeys, _, err := GlobalKMS.ListKeys(ctx, &kms.ListRequest{ Prefix: r.Form.Get("pattern"), }) if err != nil { @@ -213,21 +212,17 @@ func (a kmsAPIHandlers) KMSListKeysHandler(w http.ResponseWriter, r *http.Reques } // Now we have all the key names, for each of them, check whether the policy grants permission for - // the user to list it. - keyNames := []string{} - for _, name := range allKeyNames { - if checkKMSActionAllowed(r, owner, cred, policy.KMSListKeysAction, name) { - keyNames = append(keyNames, name) + // the user to list it. Filter in place to leave only allowed keys. + n := 0 + for _, k := range allKeys { + if checkKMSActionAllowed(r, owner, cred, policy.KMSListKeysAction, k.Name) { + allKeys[n] = k + n++ } } + allKeys = allKeys[:n] - values := make([]kes.KeyInfo, 0, len(keyNames)) - for _, name := range keyNames { - values = append(values, kes.KeyInfo{ - Name: name, - }) - } - if res, err := json.Marshal(values); err != nil { + if res, err := json.Marshal(allKeys); err != nil { writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL) } else { writeSuccessResponseJSON(w, res) diff --git a/cmd/kms-handlers_test.go b/cmd/kms-handlers_test.go index e01da7da0..c8034afcd 100644 --- a/cmd/kms-handlers_test.go +++ b/cmd/kms-handlers_test.go @@ -658,13 +658,24 @@ func execKMSTest(t *testing.T, test kmsTestCase, adminTestBed *adminErasureTestB // Check returned key list is correct if test.wantKeyNames != nil { - gotKeyNames := keyNamesFromListKeysResp(t, rec.Body.Bytes()) - if len(test.wantKeyNames) != len(gotKeyNames) { - t.Fatalf("want keys len: %d, got len: %d", len(test.wantKeyNames), len(gotKeyNames)) + keys := []madmin.KMSKeyInfo{} + err := json.Unmarshal(rec.Body.Bytes(), &keys) + if err != nil { + t.Fatal(err) } - for i, wantKeyName := range test.wantKeyNames { - if gotKeyNames[i] != wantKeyName { - t.Fatalf("want key name %s, in position %d, got %s", wantKeyName, i, gotKeyNames[i]) + if len(keys) != len(test.wantKeyNames) { + t.Fatalf("want %d keys, got %d", len(test.wantKeyNames), len(keys)) + } + + for i, want := range keys { + if want.CreatedBy != kms.StubCreatedBy { + t.Fatalf("want key created by %s, got %s", kms.StubCreatedBy, want.CreatedBy) + } + if want.CreatedAt != kms.StubCreatedAt { + t.Fatalf("want key created at %s, got %s", kms.StubCreatedAt, want.CreatedAt) + } + if test.wantKeyNames[i] != want.Name { + t.Fatalf("want key name %s, got %s", test.wantKeyNames[i], want.Name) } } } @@ -835,17 +846,3 @@ func setupKMSUser(t *testing.T, accessKey, secretKey, p string) { } } } - -func keyNamesFromListKeysResp(t *testing.T, b []byte) []string { - var keyInfos []madmin.KMSKeyInfo - err := json.Unmarshal(b, &keyInfos) - if err != nil { - t.Fatalf("cannot unmarshal '%s', err: %v", b, err) - } - - var gotKeyNames []string - for _, keyInfo := range keyInfos { - gotKeyNames = append(gotKeyNames, keyInfo.Name) - } - return gotKeyNames -} diff --git a/go.mod b/go.mod index e47d39e61..5461bda23 100644 --- a/go.mod +++ b/go.mod @@ -44,14 +44,14 @@ require ( github.com/lithammer/shortuuid/v4 v4.0.0 github.com/miekg/dns v1.1.61 github.com/minio/cli v1.24.2 - github.com/minio/console v1.7.0 + github.com/minio/console v1.7.1-0.20240817215248-0b07cb38850f github.com/minio/csvparser v1.0.0 github.com/minio/dnscache v0.1.1 github.com/minio/dperf v0.5.3 github.com/minio/highwayhash v1.0.3 github.com/minio/kms-go/kes v0.3.0 github.com/minio/kms-go/kms v0.4.0 - github.com/minio/madmin-go/v3 v3.0.61 + github.com/minio/madmin-go/v3 v3.0.63 github.com/minio/minio-go/v7 v7.0.75 github.com/minio/mux v1.9.0 github.com/minio/pkg/v3 v3.0.11 @@ -71,7 +71,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/pkg/sftp v1.13.6 github.com/pkg/xattr v0.4.10 - github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_golang v1.20.0 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.55.0 github.com/prometheus/procfs v0.15.1 @@ -199,7 +199,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/minio/colorjson v1.0.8 // indirect github.com/minio/filepath v1.0.0 // indirect - github.com/minio/mc v0.0.0-20240812085227-32b7b7219356 // indirect + github.com/minio/mc v0.0.0-20240815155011-479171e7be9c // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/pkg/v2 v2.0.19 // indirect github.com/minio/websocket v1.6.0 // indirect @@ -253,8 +253,8 @@ require ( golang.org/x/text v0.17.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/genproto v0.0.0-20240808171019-573a1156607a // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index f51248fd1..c72aa291c 100644 --- a/go.sum +++ b/go.sum @@ -409,8 +409,8 @@ github.com/minio/cli v1.24.2 h1:J+fCUh9mhPLjN3Lj/YhklXvxj8mnyE/D6FpFduXJ2jg= github.com/minio/cli v1.24.2/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY= github.com/minio/colorjson v1.0.8 h1:AS6gEQ1dTRYHmC4xuoodPDRILHP/9Wz5wYUGDQfPLpg= github.com/minio/colorjson v1.0.8/go.mod h1:wrs39G/4kqNlGjwqHvPlAnXuc2tlPszo6JKdSBCLN8w= -github.com/minio/console v1.7.0 h1:0G1Z3To1dvnV6KxP/IgZ4h8GNzEQ3FU5M3FHBKjB9hE= -github.com/minio/console v1.7.0/go.mod h1:yFhhM3Y3uT4N1WtphcYr3QAd7WYLU8CEuTcIiDpksWs= +github.com/minio/console v1.7.1-0.20240817215248-0b07cb38850f h1:+nfGhuHtHRwQgHK/C2t44knNMyJ3upwouwIR+hUz7Ts= +github.com/minio/console v1.7.1-0.20240817215248-0b07cb38850f/go.mod h1:XOmAKeIFM3RbWMc6n7neBUzXboF8Xd6HkZw4FH2QrWo= github.com/minio/csvparser v1.0.0 h1:xJEHcYK8ZAjeW4hNV9Zu30u+/2o4UyPnYgyjWp8b7ZU= github.com/minio/csvparser v1.0.0/go.mod h1:lKXskSLzPgC5WQyzP7maKH7Sl1cqvANXo9YCto8zbtM= github.com/minio/dnscache v0.1.1 h1:AMYLqomzskpORiUA1ciN9k7bZT1oB3YZN4cEIi88W5o= @@ -426,10 +426,10 @@ github.com/minio/kms-go/kes v0.3.0 h1:SU8VGVM/Hk9w1OiSby3OatkcojooUqIdDHl6dtM6Nk github.com/minio/kms-go/kes v0.3.0/go.mod h1:w6DeVT878qEOU3nUrYVy1WOT5H1Ig9hbDIh698NYJKY= github.com/minio/kms-go/kms v0.4.0 h1:cLPZceEp+05xHotVBaeFJrgL7JcXM4lBy6PU0idkE7I= github.com/minio/kms-go/kms v0.4.0/go.mod h1:q12CehiIy2qgBnDKq6Q7wmPi2PHSyRVug5DKp0HAVeE= -github.com/minio/madmin-go/v3 v3.0.61 h1:JB85GXfvc7DuOES6tpZXNX//Rv6DLlWXv9hDpFpN8sw= -github.com/minio/madmin-go/v3 v3.0.61/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw= -github.com/minio/mc v0.0.0-20240812085227-32b7b7219356 h1:qz2SKs+PIWRg/qEecVn0mr7JQfw/f/hXGynQ++tGK6A= -github.com/minio/mc v0.0.0-20240812085227-32b7b7219356/go.mod h1:7aetD0/ltOoc1SHcPJ7lZepzs9eEyHRa9s/NjhH+Do4= +github.com/minio/madmin-go/v3 v3.0.63 h1:ERJRxEI/FFRh8MDi4Z+3DKe4sONkQ0g+OkNzRpk7qxk= +github.com/minio/madmin-go/v3 v3.0.63/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw= +github.com/minio/mc v0.0.0-20240815155011-479171e7be9c h1:0tzuJ1nV6oZstqKQ/CwK1dzxNJ/cE38ym4SPi2HsWoY= +github.com/minio/mc v0.0.0-20240815155011-479171e7be9c/go.mod h1:Cr4x7eiMJfOTWwg40Rk3EaOI7i+DUyOAtqLO7x+heiA= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= @@ -533,8 +533,8 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI= +github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -838,10 +838,10 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240808171019-573a1156607a h1:3JVv3Ujh+kGiajpSqHWnbWPuu0nQqMZ3hASNDDF9974= google.golang.org/genproto v0.0.0-20240808171019-573a1156607a/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc= -google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a h1:KyUe15n7B1YCu+kMmPtlXxgkLQbp+Dw0tCRZf9Sd+CE= -google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a h1:EKiZZXueP9/T68B8Nl0GAx9cjbQnCId0yP3qPMgaaHs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= diff --git a/internal/kms/conn.go b/internal/kms/conn.go index ecdc30201..c63fcb6cb 100644 --- a/internal/kms/conn.go +++ b/internal/kms/conn.go @@ -48,7 +48,7 @@ type conn interface { // CreateKey creates a new key at the KMS with the given key ID. CreateKey(context.Context, *CreateKeyRequest) error - ListKeyNames(context.Context, *ListRequest) ([]string, string, error) + ListKeys(context.Context, *ListRequest) ([]madmin.KMSKeyInfo, string, error) // GenerateKey generates a new data encryption key using the // key referenced by the key ID. diff --git a/internal/kms/kes.go b/internal/kms/kes.go index b9df696cf..8bd387c27 100644 --- a/internal/kms/kes.go +++ b/internal/kms/kes.go @@ -126,8 +126,16 @@ func (c *kesConn) Status(ctx context.Context) (map[string]madmin.ItemState, erro return status, nil } -func (c *kesConn) ListKeyNames(ctx context.Context, req *ListRequest) ([]string, string, error) { - return c.client.ListKeys(ctx, req.Prefix, req.Limit) +func (c *kesConn) ListKeys(ctx context.Context, req *ListRequest) ([]madmin.KMSKeyInfo, string, error) { + names, continueAt, err := c.client.ListKeys(ctx, req.Prefix, req.Limit) + if err != nil { + return nil, "", err + } + keyInfos := make([]madmin.KMSKeyInfo, len(names)) + for i := range names { + keyInfos[i].Name = names[i] + } + return keyInfos, continueAt, nil } // CreateKey tries to create a new key at the KMS with the diff --git a/internal/kms/kms.go b/internal/kms/kms.go index 05ba0741a..bae60d69b 100644 --- a/internal/kms/kms.go +++ b/internal/kms/kms.go @@ -213,13 +213,13 @@ func (k *KMS) CreateKey(ctx context.Context, req *CreateKeyRequest) error { return err } -// ListKeyNames returns a list of key names and a potential +// ListKeys returns a list of keys with metadata and a potential // next name from where to continue a subsequent listing. -func (k *KMS) ListKeyNames(ctx context.Context, req *ListRequest) ([]string, string, error) { +func (k *KMS) ListKeys(ctx context.Context, req *ListRequest) ([]madmin.KMSKeyInfo, string, error) { if req.Prefix == "*" { req.Prefix = "" } - return k.conn.ListKeyNames(ctx, req) + return k.conn.ListKeys(ctx, req) } // GenerateKey generates a new data key using the master key req.Name. @@ -320,7 +320,7 @@ func (c *kmsConn) Status(ctx context.Context) (map[string]madmin.ItemState, erro return stat, nil } -func (c *kmsConn) ListKeyNames(ctx context.Context, req *ListRequest) ([]string, string, error) { +func (c *kmsConn) ListKeys(ctx context.Context, req *ListRequest) ([]madmin.KMSKeyInfo, string, error) { resp, err := c.client.ListKeys(ctx, &kms.ListRequest{ Enclave: c.enclave, Prefix: req.Prefix, @@ -331,11 +331,13 @@ func (c *kmsConn) ListKeyNames(ctx context.Context, req *ListRequest) ([]string, return nil, "", errListingKeysFailed(err) } - names := make([]string, 0, len(resp.Items)) - for _, item := range resp.Items { - names = append(names, item.Name) + keyInfos := make([]madmin.KMSKeyInfo, len(resp.Items)) + for i, v := range resp.Items { + keyInfos[i].Name = v.Name + keyInfos[i].CreatedAt = v.CreatedAt + keyInfos[i].CreatedBy = string(v.CreatedBy) } - return names, resp.ContinueAt, nil + return keyInfos, resp.ContinueAt, nil } func (c *kmsConn) CreateKey(ctx context.Context, req *CreateKeyRequest) error { diff --git a/internal/kms/secret-key.go b/internal/kms/secret-key.go index f0bb0a930..ebe85928a 100644 --- a/internal/kms/secret-key.go +++ b/internal/kms/secret-key.go @@ -95,12 +95,12 @@ func (secretKey) Status(context.Context) (map[string]madmin.ItemState, error) { }, nil } -// ListKeyNames returns a list of key names. The builtin KMS consists of just a single key. -func (s secretKey) ListKeyNames(ctx context.Context, req *ListRequest) ([]string, string, error) { +// ListKeys returns a list of keys with metadata. The builtin KMS consists of just a single key. +func (s secretKey) ListKeys(ctx context.Context, req *ListRequest) ([]madmin.KMSKeyInfo, string, error) { if strings.HasPrefix(s.keyID, req.Prefix) && strings.HasPrefix(s.keyID, req.ContinueAt) { - return []string{s.keyID}, "", nil + return []madmin.KMSKeyInfo{{Name: s.keyID}}, "", nil } - return []string{}, "", nil + return []madmin.KMSKeyInfo{}, "", nil } // CreateKey returns ErrKeyExists unless req.Name is equal to the secretKey name. diff --git a/internal/kms/stub.go b/internal/kms/stub.go index 545af6c63..2df1e9d8b 100644 --- a/internal/kms/stub.go +++ b/internal/kms/stub.go @@ -22,11 +22,19 @@ import ( "net/http" "slices" "sync/atomic" + "time" "github.com/minio/madmin-go/v3" "github.com/minio/pkg/v3/wildcard" ) +var ( + // StubCreatedAt is a constant timestamp for testing + StubCreatedAt = time.Date(2024, time.January, 1, 15, 0, 0, 0, time.UTC) + // StubCreatedBy is a constant created identity for testing + StubCreatedBy = "MinIO" +) + // NewStub returns a stub of KMS for testing func NewStub(defaultKeyName string) *KMS { return &KMS{ @@ -64,15 +72,15 @@ func (s StubKMS) Status(context.Context) (map[string]madmin.ItemState, error) { }, nil } -// ListKeyNames returns a list of key names. -func (s StubKMS) ListKeyNames(ctx context.Context, req *ListRequest) ([]string, string, error) { - matches := []string{} +// ListKeys returns a list of keys with metadata. +func (s StubKMS) ListKeys(ctx context.Context, req *ListRequest) ([]madmin.KMSKeyInfo, string, error) { + matches := []madmin.KMSKeyInfo{} if req.Prefix == "" { req.Prefix = "*" } for _, keyName := range s.KeyNames { if wildcard.MatchAsPatternPrefix(req.Prefix, keyName) { - matches = append(matches, keyName) + matches = append(matches, madmin.KMSKeyInfo{Name: keyName, CreatedAt: StubCreatedAt, CreatedBy: StubCreatedBy}) } }