kms.ListKeys returns CreatedBy/CreatedAt when information is available (#20223)

This commit is contained in:
Mark Theunissen 2024-08-18 16:43:03 +10:00 committed by GitHub
parent 9e81ccd2d9
commit 6378ca10a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 81 additions and 71 deletions

View File

@ -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)

View File

@ -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
}

12
go.mod
View File

@ -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
)

24
go.sum
View File

@ -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=

View File

@ -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.

View File

@ -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

View File

@ -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 {

View File

@ -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.

View File

@ -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})
}
}