mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Support audit logs with additional fields (#6738)
This PR adds support - Request query params - Request headers - Response headers AuditLogEntry is exported and versioned as well starting with this PR.
This commit is contained in:
parent
3f19ea98bb
commit
bef0318c36
@ -57,7 +57,7 @@ type accessControlPolicy struct {
|
|||||||
func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketACL")
|
ctx := newContext(r, w, "GetBucketACL")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -106,7 +106,7 @@ func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.
|
|||||||
func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetObjectACL")
|
ctx := newContext(r, w, "GetObjectACL")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -59,7 +59,7 @@ func validateListObjectsArgs(prefix, marker, delimiter string, maxKeys int) APIE
|
|||||||
func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListObjectsV2")
|
ctx := newContext(r, w, "ListObjectsV2")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -140,7 +140,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
|||||||
func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListObjectsV1")
|
ctx := newContext(r, w, "ListObjectsV1")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -89,7 +89,7 @@ func initFederatorBackend(objLayer ObjectLayer) {
|
|||||||
func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketLocation")
|
ctx := newContext(r, w, "GetBucketLocation")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -139,7 +139,7 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *
|
|||||||
func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListMultipartUploads")
|
ctx := newContext(r, w, "ListMultipartUploads")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -192,7 +192,7 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListBuckets")
|
ctx := newContext(r, w, "ListBuckets")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -250,6 +250,8 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
|
|||||||
func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteMultipleObjects")
|
ctx := newContext(r, w, "DeleteMultipleObjects")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
@ -380,10 +382,11 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
Object: ObjectInfo{
|
Object: ObjectInfo{
|
||||||
Name: dobj.ObjectName,
|
Name: dobj.ObjectName,
|
||||||
},
|
},
|
||||||
ReqParams: extractReqParams(r),
|
ReqParams: extractReqParams(r),
|
||||||
UserAgent: r.UserAgent(),
|
RespElements: extractRespElements(w),
|
||||||
Host: host,
|
UserAgent: r.UserAgent(),
|
||||||
Port: port,
|
Host: host,
|
||||||
|
Port: port,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,7 +397,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutBucket")
|
ctx := newContext(r, w, "PutBucket")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -472,7 +475,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PostPolicyBucket")
|
ctx := newContext(r, w, "PostPolicyBucket")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -654,13 +657,14 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
defer sendEvent(eventArgs{
|
defer sendEvent(eventArgs{
|
||||||
EventName: event.ObjectCreatedPost,
|
EventName: event.ObjectCreatedPost,
|
||||||
BucketName: objInfo.Bucket,
|
BucketName: objInfo.Bucket,
|
||||||
Object: objInfo,
|
Object: objInfo,
|
||||||
ReqParams: extractReqParams(r),
|
ReqParams: extractReqParams(r),
|
||||||
UserAgent: r.UserAgent(),
|
RespElements: extractRespElements(w),
|
||||||
Host: host,
|
UserAgent: r.UserAgent(),
|
||||||
Port: port,
|
Host: host,
|
||||||
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
if successRedirect != "" {
|
if successRedirect != "" {
|
||||||
@ -685,12 +689,6 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
default:
|
default:
|
||||||
writeSuccessNoContent(w)
|
writeSuccessNoContent(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadBucketHandler - HEAD Bucket
|
// HeadBucketHandler - HEAD Bucket
|
||||||
@ -702,7 +700,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
|||||||
func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "HeadBucket")
|
ctx := newContext(r, w, "HeadBucket")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -734,7 +732,7 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re
|
|||||||
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteBucket")
|
ctx := newContext(r, w, "DeleteBucket")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -44,7 +44,7 @@ var errNoSuchNotifications = errors.New("The specified bucket does not have buck
|
|||||||
func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketNotification")
|
ctx := newContext(r, w, "GetBucketNotification")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucketName := vars["bucket"]
|
bucketName := vars["bucket"]
|
||||||
@ -98,7 +98,7 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutBucketNotification")
|
ctx := newContext(r, w, "PutBucketNotification")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -160,7 +160,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListenBucketNotification")
|
ctx := newContext(r, w, "ListenBucketNotification")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
// Validate if bucket exists.
|
// Validate if bucket exists.
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
|
@ -40,7 +40,7 @@ const (
|
|||||||
func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutBucketPolicy")
|
ctx := newContext(r, w, "PutBucketPolicy")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
@ -103,7 +103,7 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
|||||||
func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteBucketPolicy")
|
ctx := newContext(r, w, "DeleteBucketPolicy")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
@ -141,7 +141,7 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r
|
|||||||
func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketPolicy")
|
ctx := newContext(r, w, "GetBucketPolicy")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
|
@ -51,10 +51,23 @@ func checkUpdate(mode string) {
|
|||||||
|
|
||||||
// Load logger targets based on user's configuration
|
// Load logger targets based on user's configuration
|
||||||
func loadLoggers() {
|
func loadLoggers() {
|
||||||
if endpoint, ok := os.LookupEnv("MINIO_LOGGER_HTTP_ENDPOINT"); ok {
|
auditEndpoint, ok := os.LookupEnv("MINIO_AUDIT_LOGGER_HTTP_ENDPOINT")
|
||||||
// Enable http logging through ENV, this is specifically added gateway audit logging.
|
if ok {
|
||||||
logger.AddTarget(logger.NewHTTP(endpoint, NewCustomHTTPTransport()))
|
// Enable audit HTTP logging through ENV.
|
||||||
return
|
logger.AddAuditTarget(logger.NewHTTP(auditEndpoint, NewCustomHTTPTransport()))
|
||||||
|
}
|
||||||
|
|
||||||
|
loggerEndpoint, ok := os.LookupEnv("MINIO_LOGGER_HTTP_ENDPOINT")
|
||||||
|
if ok {
|
||||||
|
// Enable HTTP logging through ENV.
|
||||||
|
logger.AddTarget(logger.NewHTTP(loggerEndpoint, NewCustomHTTPTransport()))
|
||||||
|
} else {
|
||||||
|
for _, l := range globalServerConfig.Logger.HTTP {
|
||||||
|
if l.Enabled {
|
||||||
|
// Enable http logging
|
||||||
|
logger.AddTarget(logger.NewHTTP(l.Endpoint, NewCustomHTTPTransport()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalServerConfig.Logger.Console.Enabled {
|
if globalServerConfig.Logger.Console.Enabled {
|
||||||
@ -62,12 +75,6 @@ func loadLoggers() {
|
|||||||
logger.AddTarget(logger.NewConsole())
|
logger.AddTarget(logger.NewConsole())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, l := range globalServerConfig.Logger.HTTP {
|
|
||||||
if l.Enabled {
|
|
||||||
// Enable http logging
|
|
||||||
logger.AddTarget(logger.NewHTTP(l.Endpoint, NewCustomHTTPTransport()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCommonCmdArgs(ctx *cli.Context) {
|
func handleCommonCmdArgs(ctx *cli.Context) {
|
||||||
|
@ -249,9 +249,6 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
|
|||||||
logger.FatalIf(err, "Unable to initialize disk caching")
|
logger.FatalIf(err, "Unable to initialize disk caching")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load logger subsystem
|
|
||||||
loadLoggers()
|
|
||||||
|
|
||||||
// Re-enable logging
|
// Re-enable logging
|
||||||
logger.Disable = false
|
logger.Disable = false
|
||||||
|
|
||||||
|
@ -176,14 +176,26 @@ func getRedirectPostRawQuery(objInfo ObjectInfo) string {
|
|||||||
return redirectValues.Encode()
|
return redirectValues.Encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns access key in the request Authorization header.
|
||||||
|
func getReqAccessKey(r *http.Request, region string) (accessKey string) {
|
||||||
|
accessKey, _, _ = getReqAccessKeyV4(r, region)
|
||||||
|
if accessKey == "" {
|
||||||
|
accessKey, _, _ = getReqAccessKeyV2(r)
|
||||||
|
}
|
||||||
|
return accessKey
|
||||||
|
}
|
||||||
|
|
||||||
// Extract request params to be sent with event notifiation.
|
// Extract request params to be sent with event notifiation.
|
||||||
func extractReqParams(r *http.Request) map[string]string {
|
func extractReqParams(r *http.Request) map[string]string {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
region := globalServerConfig.GetRegion()
|
||||||
// Success.
|
// Success.
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
|
"region": region,
|
||||||
|
"accessKey": getReqAccessKey(r, region),
|
||||||
"sourceIPAddress": handlers.GetSourceIP(r),
|
"sourceIPAddress": handlers.GetSourceIP(r),
|
||||||
// Add more fields here.
|
// Add more fields here.
|
||||||
}
|
}
|
||||||
@ -193,6 +205,7 @@ func extractReqParams(r *http.Request) map[string]string {
|
|||||||
func extractRespElements(w http.ResponseWriter) map[string]string {
|
func extractRespElements(w http.ResponseWriter) map[string]string {
|
||||||
|
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
|
"requestId": w.Header().Get(responseRequestIDKey),
|
||||||
"content-length": w.Header().Get("Content-Length"),
|
"content-length": w.Header().Get("Content-Length"),
|
||||||
// Add more fields here.
|
// Add more fields here.
|
||||||
}
|
}
|
||||||
|
97
cmd/logger/audit-logger.go
Normal file
97
cmd/logger/audit-logger.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Represents the current version of audit log structure.
|
||||||
|
const auditLogVersion = "1"
|
||||||
|
|
||||||
|
// AuditEntry - audit entry logs.
|
||||||
|
type AuditEntry struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
DeploymentID string `json:"deploymentid,omitempty"`
|
||||||
|
Time string `json:"time"`
|
||||||
|
API *api `json:"api,omitempty"`
|
||||||
|
RemoteHost string `json:"remotehost,omitempty"`
|
||||||
|
RequestID string `json:"requestID,omitempty"`
|
||||||
|
UserAgent string `json:"userAgent,omitempty"`
|
||||||
|
ReqQuery map[string]string `json:"requestQuery,omitempty"`
|
||||||
|
ReqHeader map[string]string `json:"requestHeader,omitempty"`
|
||||||
|
RespHeader map[string]string `json:"responseHeader,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditTargets is the list of enabled audit loggers
|
||||||
|
var AuditTargets = []LoggingTarget{}
|
||||||
|
|
||||||
|
// AddAuditTarget adds a new audit logger target to the
|
||||||
|
// list of enabled loggers
|
||||||
|
func AddAuditTarget(t LoggingTarget) {
|
||||||
|
AuditTargets = append(AuditTargets, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditLog - logs audit logs to all targets.
|
||||||
|
func AuditLog(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if Disable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := GetReqInfo(ctx)
|
||||||
|
if req == nil {
|
||||||
|
req = &ReqInfo{API: "SYSTEM"}
|
||||||
|
}
|
||||||
|
|
||||||
|
reqQuery := make(map[string]string)
|
||||||
|
for k, v := range r.URL.Query() {
|
||||||
|
reqQuery[k] = strings.Join(v, ",")
|
||||||
|
}
|
||||||
|
reqHeader := make(map[string]string)
|
||||||
|
for k, v := range r.Header {
|
||||||
|
reqHeader[k] = strings.Join(v, ",")
|
||||||
|
}
|
||||||
|
respHeader := make(map[string]string)
|
||||||
|
for k, v := range w.Header() {
|
||||||
|
respHeader[k] = strings.Join(v, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send audit logs only to http targets.
|
||||||
|
for _, t := range AuditTargets {
|
||||||
|
t.send(AuditEntry{
|
||||||
|
Version: auditLogVersion,
|
||||||
|
DeploymentID: deploymentID,
|
||||||
|
RemoteHost: req.RemoteHost,
|
||||||
|
RequestID: req.RequestID,
|
||||||
|
UserAgent: req.UserAgent,
|
||||||
|
Time: time.Now().UTC().Format(time.RFC3339Nano),
|
||||||
|
API: &api{
|
||||||
|
Name: req.API,
|
||||||
|
Args: &args{
|
||||||
|
Bucket: req.BucketName,
|
||||||
|
Object: req.ObjectName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReqQuery: reqQuery,
|
||||||
|
ReqHeader: reqHeader,
|
||||||
|
RespHeader: respHeader,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -117,9 +116,11 @@ type traceEntry struct {
|
|||||||
Source []string `json:"source,omitempty"`
|
Source []string `json:"source,omitempty"`
|
||||||
Variables map[string]string `json:"variables,omitempty"`
|
Variables map[string]string `json:"variables,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
Bucket string `json:"bucket,omitempty"`
|
Bucket string `json:"bucket,omitempty"`
|
||||||
Object string `json:"object,omitempty"`
|
Object string `json:"object,omitempty"`
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type api struct {
|
type api struct {
|
||||||
@ -342,55 +343,6 @@ func logIf(ctx context.Context, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type auditEntry struct {
|
|
||||||
DeploymentID string `json:"deploymentid,omitempty"`
|
|
||||||
Time string `json:"time"`
|
|
||||||
API *api `json:"api,omitempty"`
|
|
||||||
RemoteHost string `json:"remotehost,omitempty"`
|
|
||||||
RequestID string `json:"requestID,omitempty"`
|
|
||||||
UserAgent string `json:"userAgent,omitempty"`
|
|
||||||
Metadata map[string]string `json:"metadata,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuditLog - logs audit logs to all targets.
|
|
||||||
func AuditLog(ctx context.Context, r *http.Request) {
|
|
||||||
if Disable {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req := GetReqInfo(ctx)
|
|
||||||
if req == nil {
|
|
||||||
req = &ReqInfo{API: "SYSTEM"}
|
|
||||||
}
|
|
||||||
|
|
||||||
API := "SYSTEM"
|
|
||||||
if req.API != "" {
|
|
||||||
API = req.API
|
|
||||||
}
|
|
||||||
|
|
||||||
tags := make(map[string]string)
|
|
||||||
for _, entry := range req.GetTags() {
|
|
||||||
tags[entry.Key] = entry.Val
|
|
||||||
}
|
|
||||||
|
|
||||||
entry := auditEntry{
|
|
||||||
DeploymentID: deploymentID,
|
|
||||||
RemoteHost: req.RemoteHost,
|
|
||||||
RequestID: req.RequestID,
|
|
||||||
UserAgent: req.UserAgent,
|
|
||||||
Time: time.Now().UTC().Format(time.RFC3339Nano),
|
|
||||||
API: &api{Name: API, Args: &args{Bucket: req.BucketName, Object: req.ObjectName}},
|
|
||||||
Metadata: tags,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send audit logs only to http targets.
|
|
||||||
for _, t := range Targets {
|
|
||||||
if _, ok := t.(*HTTPTarget); ok {
|
|
||||||
t.send(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCritical is the value panic'd whenever CriticalIf is called.
|
// ErrCritical is the value panic'd whenever CriticalIf is called.
|
||||||
var ErrCritical struct{}
|
var ErrCritical struct{}
|
||||||
|
|
||||||
|
@ -494,12 +494,11 @@ func (args eventArgs) ToEvent() event.Event {
|
|||||||
return fmt.Sprintf("%s://%s:%s", getURLScheme(globalIsSSL), host, globalMinioPort)
|
return fmt.Sprintf("%s://%s:%s", getURLScheme(globalIsSSL), host, globalMinioPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
creds := globalServerConfig.GetCredential()
|
|
||||||
eventTime := UTCNow()
|
eventTime := UTCNow()
|
||||||
uniqueID := fmt.Sprintf("%X", eventTime.UnixNano())
|
uniqueID := fmt.Sprintf("%X", eventTime.UnixNano())
|
||||||
|
|
||||||
respElements := map[string]string{
|
respElements := map[string]string{
|
||||||
"x-amz-request-id": uniqueID,
|
"x-amz-request-id": args.RespElements["requestId"],
|
||||||
"x-minio-origin-endpoint": getOriginEndpoint(), // Minio specific custom elements.
|
"x-minio-origin-endpoint": getOriginEndpoint(), // Minio specific custom elements.
|
||||||
}
|
}
|
||||||
if args.RespElements["content-length"] != "" {
|
if args.RespElements["content-length"] != "" {
|
||||||
@ -508,10 +507,10 @@ func (args eventArgs) ToEvent() event.Event {
|
|||||||
newEvent := event.Event{
|
newEvent := event.Event{
|
||||||
EventVersion: "2.0",
|
EventVersion: "2.0",
|
||||||
EventSource: "minio:s3",
|
EventSource: "minio:s3",
|
||||||
AwsRegion: globalServerConfig.GetRegion(),
|
AwsRegion: args.ReqParams["region"],
|
||||||
EventTime: eventTime.Format(event.AMZTimeFormat),
|
EventTime: eventTime.Format(event.AMZTimeFormat),
|
||||||
EventName: args.EventName,
|
EventName: args.EventName,
|
||||||
UserIdentity: event.Identity{creds.AccessKey},
|
UserIdentity: event.Identity{args.ReqParams["accessKey"]},
|
||||||
RequestParameters: args.ReqParams,
|
RequestParameters: args.ReqParams,
|
||||||
ResponseElements: respElements,
|
ResponseElements: respElements,
|
||||||
S3: event.Metadata{
|
S3: event.Metadata{
|
||||||
@ -519,7 +518,7 @@ func (args eventArgs) ToEvent() event.Event {
|
|||||||
ConfigurationID: "Config",
|
ConfigurationID: "Config",
|
||||||
Bucket: event.Bucket{
|
Bucket: event.Bucket{
|
||||||
Name: args.BucketName,
|
Name: args.BucketName,
|
||||||
OwnerIdentity: event.Identity{creds.AccessKey},
|
OwnerIdentity: event.Identity{args.ReqParams["accessKey"]},
|
||||||
ARN: policy.ResourceARNPrefix + args.BucketName,
|
ARN: policy.ResourceARNPrefix + args.BucketName,
|
||||||
},
|
},
|
||||||
Object: event.Object{
|
Object: event.Object{
|
||||||
|
@ -79,7 +79,7 @@ func setHeadGetRespHeaders(w http.ResponseWriter, reqParams url.Values) {
|
|||||||
func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "SelectObject")
|
ctx := newContext(r, w, "SelectObject")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
// Fetch object stat info.
|
// Fetch object stat info.
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
@ -271,11 +271,23 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r
|
|||||||
// Executes the query on data-set
|
// Executes the query on data-set
|
||||||
s3select.Execute(w, s3s)
|
s3select.Execute(w, s3s)
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
// Get host and port from Request.RemoteAddr.
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
host, port, err := net.SplitHostPort(handlers.GetSourceIP(r))
|
||||||
|
if err != nil {
|
||||||
|
host, port = "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
// Notify object accessed via a GET request.
|
||||||
|
sendEvent(eventArgs{
|
||||||
|
EventName: event.ObjectAccessedGet,
|
||||||
|
BucketName: bucket,
|
||||||
|
Object: objInfo,
|
||||||
|
ReqParams: extractReqParams(r),
|
||||||
|
RespElements: extractRespElements(w),
|
||||||
|
UserAgent: r.UserAgent(),
|
||||||
|
Host: host,
|
||||||
|
Port: port,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObjectHandler - GET Object
|
// GetObjectHandler - GET Object
|
||||||
@ -285,7 +297,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r
|
|||||||
func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetObject")
|
ctx := newContext(r, w, "GetObject")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -443,12 +455,6 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadObjectHandler - HEAD Object
|
// HeadObjectHandler - HEAD Object
|
||||||
@ -457,7 +463,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "HeadObject")
|
ctx := newContext(r, w, "HeadObject")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -597,12 +603,6 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract metadata relevant for an CopyObject operation based on conditional
|
// Extract metadata relevant for an CopyObject operation based on conditional
|
||||||
@ -643,7 +643,7 @@ func getCpObjMetadataFromHeader(ctx context.Context, r *http.Request, userMeta m
|
|||||||
func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "CopyObject")
|
ctx := newContext(r, w, "CopyObject")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -984,20 +984,15 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
sendEvent(eventArgs{
|
sendEvent(eventArgs{
|
||||||
EventName: event.ObjectCreatedCopy,
|
EventName: event.ObjectCreatedCopy,
|
||||||
BucketName: dstBucket,
|
BucketName: dstBucket,
|
||||||
Object: objInfo,
|
Object: objInfo,
|
||||||
ReqParams: extractReqParams(r),
|
ReqParams: extractReqParams(r),
|
||||||
UserAgent: r.UserAgent(),
|
RespElements: extractRespElements(w),
|
||||||
Host: host,
|
UserAgent: r.UserAgent(),
|
||||||
Port: port,
|
Host: host,
|
||||||
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObjectHandler - PUT Object
|
// PutObjectHandler - PUT Object
|
||||||
@ -1011,7 +1006,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutObject")
|
ctx := newContext(r, w, "PutObject")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -1244,20 +1239,15 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
sendEvent(eventArgs{
|
sendEvent(eventArgs{
|
||||||
EventName: event.ObjectCreatedPut,
|
EventName: event.ObjectCreatedPut,
|
||||||
BucketName: bucket,
|
BucketName: bucket,
|
||||||
Object: objInfo,
|
Object: objInfo,
|
||||||
ReqParams: extractReqParams(r),
|
ReqParams: extractReqParams(r),
|
||||||
UserAgent: r.UserAgent(),
|
RespElements: extractRespElements(w),
|
||||||
Host: host,
|
UserAgent: r.UserAgent(),
|
||||||
Port: port,
|
Host: host,
|
||||||
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multipart objectAPIHandlers
|
/// Multipart objectAPIHandlers
|
||||||
@ -1271,7 +1261,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "NewMultipartUpload")
|
ctx := newContext(r, w, "NewMultipartUpload")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -1365,7 +1355,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
|||||||
func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "CopyObjectPart")
|
ctx := newContext(r, w, "CopyObjectPart")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -1597,7 +1587,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||||||
func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutObjectPart")
|
ctx := newContext(r, w, "PutObjectPart")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -1841,7 +1831,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "AbortMultipartUpload")
|
ctx := newContext(r, w, "AbortMultipartUpload")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -1879,6 +1869,7 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter,
|
|||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSuccessNoContent(w)
|
writeSuccessNoContent(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1886,7 +1877,7 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter,
|
|||||||
func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListObjectParts")
|
ctx := newContext(r, w, "ListObjectParts")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -1932,7 +1923,7 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht
|
|||||||
func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "CompleteMultipartUpload")
|
ctx := newContext(r, w, "CompleteMultipartUpload")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
@ -2036,20 +2027,15 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
sendEvent(eventArgs{
|
sendEvent(eventArgs{
|
||||||
EventName: event.ObjectCreatedCompleteMultipartUpload,
|
EventName: event.ObjectCreatedCompleteMultipartUpload,
|
||||||
BucketName: bucket,
|
BucketName: bucket,
|
||||||
Object: objInfo,
|
Object: objInfo,
|
||||||
ReqParams: extractReqParams(r),
|
ReqParams: extractReqParams(r),
|
||||||
UserAgent: r.UserAgent(),
|
RespElements: extractRespElements(w),
|
||||||
Host: host,
|
UserAgent: r.UserAgent(),
|
||||||
Port: port,
|
Host: host,
|
||||||
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete objectAPIHandlers
|
/// Delete objectAPIHandlers
|
||||||
@ -2058,7 +2044,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
|||||||
func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteObject")
|
ctx := newContext(r, w, "DeleteObject")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -707,7 +707,7 @@ func (web *webAPIHandlers) CreateURLToken(r *http.Request, args *WebGenericArgs,
|
|||||||
func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "WebUpload")
|
ctx := newContext(r, w, "WebUpload")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
@ -830,27 +830,22 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Notify object created event.
|
// Notify object created event.
|
||||||
sendEvent(eventArgs{
|
sendEvent(eventArgs{
|
||||||
EventName: event.ObjectCreatedPut,
|
EventName: event.ObjectCreatedPut,
|
||||||
BucketName: bucket,
|
BucketName: bucket,
|
||||||
Object: objInfo,
|
Object: objInfo,
|
||||||
ReqParams: extractReqParams(r),
|
ReqParams: extractReqParams(r),
|
||||||
UserAgent: r.UserAgent(),
|
RespElements: extractRespElements(w),
|
||||||
Host: host,
|
UserAgent: r.UserAgent(),
|
||||||
Port: port,
|
Host: host,
|
||||||
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download - file download handler.
|
// Download - file download handler.
|
||||||
func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "WebDownload")
|
ctx := newContext(r, w, "WebDownload")
|
||||||
|
|
||||||
defer logger.AuditLog(ctx, r)
|
defer logger.AuditLog(ctx, w, r)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
@ -1012,12 +1007,6 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
|||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
for k, v := range objInfo.UserDefined {
|
|
||||||
logger.GetReqInfo(ctx).SetTags(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadZipArgs - Argument for downloading a bunch of files as a zip file.
|
// DownloadZipArgs - Argument for downloading a bunch of files as a zip file.
|
||||||
@ -1038,8 +1027,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := newContext(r, w, "WebDownloadZip")
|
ctx := newContext(r, w, "WebDownloadZip")
|
||||||
|
defer logger.AuditLog(ctx, w, r)
|
||||||
defer logger.AuditLog(ctx, r)
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
|
108
docs/logging/README.md
Normal file
108
docs/logging/README.md
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# Minio Logging Quickstart Guide [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io)
|
||||||
|
This document explains how to configure Minio server to log to different logging targets.
|
||||||
|
|
||||||
|
## Log Targets
|
||||||
|
Minio supports currently two target types
|
||||||
|
|
||||||
|
- console
|
||||||
|
- http
|
||||||
|
|
||||||
|
### Console Target
|
||||||
|
Console target logs to `/dev/stderr` and is enabled by default. To turn-off console logging you would have to update your Minio server configuration using `mc admin config set` command.
|
||||||
|
|
||||||
|
Assuming `mc` is already [configured](https://docs.minio.io/docs/minio-client-quickstart-guide.html)
|
||||||
|
```
|
||||||
|
mc admin config get myminio/ > /tmp/config
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit the `/tmp/config` and toggle `console` field `enabled` from `true` to `false`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"logger": {
|
||||||
|
"console": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
Once changed, now you may set the changed config to server through following commands.
|
||||||
|
```
|
||||||
|
mc admin config set myminio/ < /tmp/config
|
||||||
|
mc admin restart myminio/
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP Target
|
||||||
|
HTTP target logs to a generic HTTP endpoint in JSON format and is not enabled by default. To enable HTTP target logging you would have to update your Minio server configuration using `mc admin config set` command.
|
||||||
|
|
||||||
|
Assuming `mc` is already [configured](https://docs.minio.io/docs/minio-client-quickstart-guide.html)
|
||||||
|
```
|
||||||
|
mc admin config get myminio/ > /tmp/config
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit the `/tmp/config` and toggle `http` field `enabled` from `false` to `true`.
|
||||||
|
```json
|
||||||
|
"logger": {
|
||||||
|
"console": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"1": {
|
||||||
|
"enabled": true,
|
||||||
|
"endpoint": "http://endpoint:port/path"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
NOTE: `http://endpoint:port/path` is a placeholder value to indicate the URL format, please change this accordingly as per your configuration.
|
||||||
|
|
||||||
|
Once changed, now you may set the changed config to server through following commands.
|
||||||
|
```
|
||||||
|
mc admin config set myminio/ < /tmp/config
|
||||||
|
mc admin restart myminio/
|
||||||
|
```
|
||||||
|
|
||||||
|
Minio also honors environment variable for HTTP target logging as shown below, this setting will override the endpoint settings in the Minio server config.
|
||||||
|
```
|
||||||
|
MINIO_LOGGER_HTTP_ENDPOINT=http://localhost:8080/minio/logs minio server /mnt/data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Audit Targets
|
||||||
|
For audit logging Minio supports only HTTP target type for now. Audit logging is currently only available through environment variable.
|
||||||
|
```
|
||||||
|
MINIO_AUDIT_LOGGER_HTTP_ENDPOINT=http://localhost:8080/minio/logs/audit minio server /mnt/data
|
||||||
|
```
|
||||||
|
|
||||||
|
Setting this environment variable automatically enables audit logging to the HTTP target. The audit logging is in JSON format as described below.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"deploymentid": "1b3002bf-5005-4d9b-853e-64a05008ebb2",
|
||||||
|
"time": "2018-11-02T21:57:58.231480177Z",
|
||||||
|
"api": {
|
||||||
|
"name": "ListBuckets",
|
||||||
|
"args": {}
|
||||||
|
},
|
||||||
|
"remotehost": "127.0.0.1",
|
||||||
|
"requestID": "15636D7C53428FD4",
|
||||||
|
"userAgent": "Minio (linux; amd64) minio-go/v6.0.8 mc/2018-11-02T21:13:30Z",
|
||||||
|
"requestHeader": {
|
||||||
|
"Authorization": "AWS4-HMAC-SHA256 Credential=minio/20181102/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=6db486b42a85b23bffba66d654ce60242a7e92fb27cd4a1756e68082c02cc204",
|
||||||
|
"User-Agent": "Minio (linux; amd64) minio-go/v6.0.8 mc/2018-11-02T21:13:30Z",
|
||||||
|
"X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
|
"X-Amz-Date": "20181102T215758Z"
|
||||||
|
},
|
||||||
|
"responseHeader": {
|
||||||
|
"Accept-Ranges": "bytes",
|
||||||
|
"Content-Security-Policy": "block-all-mixed-content",
|
||||||
|
"Content-Type": "application/xml",
|
||||||
|
"Server": "Minio/DEVELOPMENT.2018-11-02T21-57-15Z (linux; amd64)",
|
||||||
|
"Vary": "Origin",
|
||||||
|
"X-Amz-Request-Id": "15636D7C53428FD4",
|
||||||
|
"X-Xss-Protection": "1; mode=block"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Explore Further
|
||||||
|
* [Minio Quickstart Guide](https://docs.minio.io/docs/minio-quickstart-guide)
|
||||||
|
* [Configure Minio Server with TLS](https://docs.minio.io/docs/how-to-secure-access-to-minio-server-with-tls)
|
Loading…
Reference in New Issue
Block a user