diff --git a/cmd/kms-handlers.go b/cmd/kms-handlers.go index 73ea2e5d8..75ee38c09 100644 --- a/cmd/kms-handlers.go +++ b/cmd/kms-handlers.go @@ -67,6 +67,105 @@ func (a kmsAPIHandlers) KMSStatusHandler(w http.ResponseWriter, r *http.Request) writeSuccessResponseJSON(w, resp) } +// KMSMetricsHandler - POST /minio/kms/v1/metrics +func (a kmsAPIHandlers) KMSMetricsHandler(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "KMSMetrics") + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.KMSMetricsAction) + if objectAPI == nil { + return + } + + if GlobalKMS == nil { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL) + return + } + + metrics, err := GlobalKMS.Metrics(ctx) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + if res, err := json.Marshal(metrics); err != nil { + writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL) + } else { + writeSuccessResponseJSON(w, res) + } +} + +// KMSAPIsHandler - POST /minio/kms/v1/apis +func (a kmsAPIHandlers) KMSAPIsHandler(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "KMSAPIs") + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.KMSAPIAction) + if objectAPI == nil { + return + } + + if GlobalKMS == nil { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL) + return + } + + manager, ok := GlobalKMS.(kms.StatusManager) + if !ok { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + apis, err := manager.APIs(ctx) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + if res, err := json.Marshal(apis); err != nil { + writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL) + } else { + writeSuccessResponseJSON(w, res) + } +} + +type versionResponse struct { + Version string `json:"version"` +} + +// KMSVersionHandler - POST /minio/kms/v1/version +func (a kmsAPIHandlers) KMSVersionHandler(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "KMSVersion") + defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) + + objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.KMSVersionAction) + if objectAPI == nil { + return + } + + if GlobalKMS == nil { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrKMSNotConfigured), r.URL) + return + } + + manager, ok := GlobalKMS.(kms.StatusManager) + if !ok { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) + return + } + + version, err := manager.Version(ctx) + if err != nil { + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + res := &versionResponse{Version: version} + v, err := json.Marshal(res) + if err != nil { + writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInternalError), err.Error(), r.URL) + return + } + writeSuccessResponseJSON(w, v) +} + // KMSCreateKeyHandler - POST /minio/kms/v1/key/create?key-id= func (a kmsAPIHandlers) KMSCreateKeyHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "KMSCreateKey") diff --git a/cmd/kms-router.go b/cmd/kms-router.go index fc4f06438..037bbad9c 100644 --- a/cmd/kms-router.go +++ b/cmd/kms-router.go @@ -52,6 +52,9 @@ func registerKMSRouter(router *mux.Router) { for _, version := range KMSVersions { // KMS Status APIs kmsRouter.Methods(http.MethodGet).Path(version + "/status").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSStatusHandler))) + kmsRouter.Methods(http.MethodGet).Path(version + "/metrics").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSMetricsHandler))) + kmsRouter.Methods(http.MethodGet).Path(version + "/apis").HandlerFunc(gz(httpTraceAll(kmsAPI.KMSAPIsHandler))) + 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:.*}") diff --git a/go.mod b/go.mod index e422dbd7f..4afe4ed26 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/minio/kes v0.21.0 github.com/minio/madmin-go v1.6.2 github.com/minio/minio-go/v7 v7.0.40-0.20220928095841-8848d8affe8a - github.com/minio/pkg v1.5.0 + github.com/minio/pkg v1.5.1 github.com/minio/selfupdate v0.5.0 github.com/minio/sha256-simd v1.0.0 github.com/minio/simdjson-go v0.4.2 diff --git a/go.sum b/go.sum index d49dff360..9a56bb383 100644 --- a/go.sum +++ b/go.sum @@ -662,8 +662,8 @@ github.com/minio/minio-go/v7 v7.0.23/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2 github.com/minio/minio-go/v7 v7.0.40-0.20220928095841-8848d8affe8a h1:COFh7S3tOKmJNYtKKFAuHQFH7MAaXxg4aAluXC9KQgc= github.com/minio/minio-go/v7 v7.0.40-0.20220928095841-8848d8affe8a/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw= github.com/minio/pkg v1.1.20/go.mod h1:Xo7LQshlxGa9shKwJ7NzQbgW4s8T/Wc1cOStR/eUiMY= -github.com/minio/pkg v1.5.0 h1:517jxphvCLSNE8vbctMY4avaRDZXiGT7lX+cXPXFb98= -github.com/minio/pkg v1.5.0/go.mod h1:koF2J2Ep/zpd//k+3UYdh6ySZKjqzy9C6RCZRX7uRY8= +github.com/minio/pkg v1.5.1 h1:XwuoZMqC+VXYGRFFALO5JGacQxut6iUTJP76UGPzsek= +github.com/minio/pkg v1.5.1/go.mod h1:koF2J2Ep/zpd//k+3UYdh6ySZKjqzy9C6RCZRX7uRY8= github.com/minio/selfupdate v0.5.0 h1:0UH1HlL49+2XByhovKl5FpYTjKfvrQ2sgL1zEXK6mfI= github.com/minio/selfupdate v0.5.0/go.mod h1:mcDkzMgq8PRcpCRJo/NlPY7U45O5dfYl2Y0Rg7IustY= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= diff --git a/internal/kms/kes.go b/internal/kms/kes.go index 4695c4ef8..ce1f0a162 100644 --- a/internal/kms/kes.go +++ b/internal/kms/kes.go @@ -139,6 +139,7 @@ func (c *kesClient) Stat(ctx context.Context) (Status, error) { }, nil } +// Metrics retrieves server metrics in the Prometheus exposition format. func (c *kesClient) Metrics(ctx context.Context) (kes.Metric, error) { c.lock.RLock() defer c.lock.RUnlock() @@ -146,6 +147,22 @@ func (c *kesClient) Metrics(ctx context.Context) (kes.Metric, error) { return c.client.Metrics(ctx) } +// Version retrieves version information +func (c *kesClient) Version(ctx context.Context) (string, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + return c.client.Version(ctx) +} + +// APIs retrieves a list of supported API endpoints +func (c *kesClient) APIs(ctx context.Context) ([]kes.API, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + return c.client.APIs(ctx) +} + // CreateKey tries to create a new key at the KMS with the // given key ID. // diff --git a/internal/kms/status-manager.go b/internal/kms/status-manager.go new file mode 100644 index 000000000..45bc57f26 --- /dev/null +++ b/internal/kms/status-manager.go @@ -0,0 +1,32 @@ +// Copyright (c) 2015-2022 MinIO, Inc. +// +// This file is part of MinIO Object Storage stack +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package kms + +import ( + "context" + + "github.com/minio/kes" +) + +// StatusManager is the generic interface that handles KMS status operations +type StatusManager interface { + // Version retrieves version information + Version(ctx context.Context) (string, error) + // APIs retrieves a list of supported API endpoints + APIs(ctx context.Context) ([]kes.API, error) +}