| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 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 <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-01-27 05:21:51 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-09-24 04:34:28 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2020-05-20 09:34:02 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2019-08-13 11:32:34 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 13:21:17 +08:00
										 |  |  | 	internalAudit "github.com/minio/minio/internal/logger/message/audit" | 
					
						
							|  |  |  | 	"github.com/minio/pkg/logger/message/audit" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 	"github.com/klauspost/compress/gzhttp" | 
					
						
							| 
									
										
										
										
											2022-12-07 05:46:50 +08:00
										 |  |  | 	"github.com/minio/madmin-go/v2" | 
					
						
							| 
									
										
										
										
											2022-02-24 05:36:01 +08:00
										 |  |  | 	xhttp "github.com/minio/minio/internal/http" | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | const contextAuditKey = contextKeyType("audit-entry") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetAuditEntry sets Audit info in the context.
 | 
					
						
							|  |  |  | func SetAuditEntry(ctx context.Context, audit *audit.Entry) context.Context { | 
					
						
							|  |  |  | 	if ctx == nil { | 
					
						
							|  |  |  | 		LogIf(context.Background(), fmt.Errorf("context is nil")) | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2020-04-30 13:17:36 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 	return context.WithValue(ctx, contextAuditKey, audit) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-30 13:17:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | // GetAuditEntry returns Audit entry if set.
 | 
					
						
							|  |  |  | func GetAuditEntry(ctx context.Context) *audit.Entry { | 
					
						
							|  |  |  | 	if ctx != nil { | 
					
						
							|  |  |  | 		r, ok := ctx.Value(contextAuditKey).(*audit.Entry) | 
					
						
							|  |  |  | 		if ok { | 
					
						
							|  |  |  | 			return r | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-02 05:02:44 +08:00
										 |  |  | 		r = &audit.Entry{ | 
					
						
							| 
									
										
										
										
											2023-02-22 13:21:17 +08:00
										 |  |  | 			Version:      internalAudit.Version, | 
					
						
							| 
									
										
										
										
											2022-02-24 05:36:01 +08:00
										 |  |  | 			DeploymentID: xhttp.GlobalDeploymentID, | 
					
						
							| 
									
										
										
										
											2021-12-24 07:33:54 +08:00
										 |  |  | 			Time:         time.Now().UTC(), | 
					
						
							| 
									
										
										
										
											2021-07-02 05:02:44 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 		return r | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-13 11:32:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | // AuditLog - logs audit logs to all audit targets.
 | 
					
						
							|  |  |  | func AuditLog(ctx context.Context, w http.ResponseWriter, r *http.Request, reqClaims map[string]interface{}, filterKeys ...string) { | 
					
						
							| 
									
										
										
										
											2022-05-12 22:20:58 +08:00
										 |  |  | 	auditTgts := AuditTargets() | 
					
						
							|  |  |  | 	if len(auditTgts) == 0 { | 
					
						
							| 
									
										
										
										
											2021-01-27 05:21:51 +08:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2020-02-12 11:38:02 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-13 11:32:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 	var entry audit.Entry | 
					
						
							|  |  |  | 	if w != nil && r != nil { | 
					
						
							|  |  |  | 		reqInfo := GetReqInfo(ctx) | 
					
						
							|  |  |  | 		if reqInfo == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-01 01:48:50 +08:00
										 |  |  | 		reqInfo.RLock() | 
					
						
							|  |  |  | 		defer reqInfo.RUnlock() | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 13:21:17 +08:00
										 |  |  | 		entry = internalAudit.ToEntry(w, r, reqClaims, xhttp.GlobalDeploymentID) | 
					
						
							| 
									
										
										
										
											2021-07-02 05:02:44 +08:00
										 |  |  | 		// indicates all requests for this API call are inbound
 | 
					
						
							|  |  |  | 		entry.Trigger = "incoming" | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for _, filterKey := range filterKeys { | 
					
						
							|  |  |  | 			delete(entry.ReqClaims, filterKey) | 
					
						
							|  |  |  | 			delete(entry.ReqQuery, filterKey) | 
					
						
							|  |  |  | 			delete(entry.ReqHeader, filterKey) | 
					
						
							|  |  |  | 			delete(entry.RespHeader, filterKey) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			statusCode      int | 
					
						
							|  |  |  | 			timeToResponse  time.Duration | 
					
						
							|  |  |  | 			timeToFirstByte time.Duration | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 			outputBytes     int64 = -1 // -1: unknown output bytes
 | 
					
						
							| 
									
										
										
										
											2022-09-02 03:51:04 +08:00
										 |  |  | 			headerBytes     int64 | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 02:20:27 +08:00
										 |  |  | 		var st *xhttp.ResponseRecorder | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 		switch v := w.(type) { | 
					
						
							| 
									
										
										
										
											2022-11-29 02:20:27 +08:00
										 |  |  | 		case *xhttp.ResponseRecorder: | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 			st = v | 
					
						
							|  |  |  | 		case *gzhttp.GzipResponseWriter: | 
					
						
							|  |  |  | 			// the writer may be obscured by gzip response writer
 | 
					
						
							| 
									
										
										
										
											2022-11-29 02:20:27 +08:00
										 |  |  | 			if rw, ok := v.ResponseWriter.(*xhttp.ResponseRecorder); ok { | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 				st = rw | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-12-31 02:20:19 +08:00
										 |  |  | 		case *gzhttp.NoGzipResponseWriter: | 
					
						
							|  |  |  | 			// the writer may be obscured by no-gzip response writer
 | 
					
						
							|  |  |  | 			if rw, ok := v.ResponseWriter.(*xhttp.ResponseRecorder); ok { | 
					
						
							|  |  |  | 				st = rw | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if st != nil { | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 			statusCode = st.StatusCode | 
					
						
							|  |  |  | 			timeToResponse = time.Now().UTC().Sub(st.StartTime) | 
					
						
							|  |  |  | 			timeToFirstByte = st.TimeToFirstByte | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 			outputBytes = int64(st.Size()) | 
					
						
							| 
									
										
										
										
											2022-09-02 03:51:04 +08:00
										 |  |  | 			headerBytes = int64(st.HeaderSize()) | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 03:05:26 +08:00
										 |  |  | 		entry.AccessKey = reqInfo.Cred.AccessKey | 
					
						
							|  |  |  | 		entry.ParentUser = reqInfo.Cred.ParentUser | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 		entry.API.Name = reqInfo.API | 
					
						
							|  |  |  | 		entry.API.Bucket = reqInfo.BucketName | 
					
						
							|  |  |  | 		entry.API.Object = reqInfo.ObjectName | 
					
						
							| 
									
										
										
										
											2022-01-03 17:28:52 +08:00
										 |  |  | 		entry.API.Objects = make([]audit.ObjectVersion, 0, len(reqInfo.Objects)) | 
					
						
							|  |  |  | 		for _, ov := range reqInfo.Objects { | 
					
						
							|  |  |  | 			entry.API.Objects = append(entry.API.Objects, audit.ObjectVersion{ | 
					
						
							|  |  |  | 				ObjectName: ov.ObjectName, | 
					
						
							|  |  |  | 				VersionID:  ov.VersionID, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 		entry.API.Status = http.StatusText(statusCode) | 
					
						
							|  |  |  | 		entry.API.StatusCode = statusCode | 
					
						
							| 
									
										
										
										
											2021-10-08 10:03:46 +08:00
										 |  |  | 		entry.API.InputBytes = r.ContentLength | 
					
						
							| 
									
										
										
										
											2021-10-28 00:29:42 +08:00
										 |  |  | 		entry.API.OutputBytes = outputBytes | 
					
						
							| 
									
										
										
										
											2022-09-02 03:51:04 +08:00
										 |  |  | 		entry.API.HeaderBytes = headerBytes | 
					
						
							| 
									
										
										
										
											2021-04-24 00:51:12 +08:00
										 |  |  | 		entry.API.TimeToResponse = strconv.FormatInt(timeToResponse.Nanoseconds(), 10) + "ns" | 
					
						
							|  |  |  | 		entry.Tags = reqInfo.GetTagsMap() | 
					
						
							|  |  |  | 		// ttfb will be recorded only for GET requests, Ignore such cases where ttfb will be empty.
 | 
					
						
							|  |  |  | 		if timeToFirstByte != 0 { | 
					
						
							|  |  |  | 			entry.API.TimeToFirstByte = strconv.FormatInt(timeToFirstByte.Nanoseconds(), 10) + "ns" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		auditEntry := GetAuditEntry(ctx) | 
					
						
							|  |  |  | 		if auditEntry != nil { | 
					
						
							|  |  |  | 			entry = *auditEntry | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-20 09:34:02 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-30 13:17:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 	// Send audit logs only to http targets.
 | 
					
						
							| 
									
										
										
										
											2022-05-12 22:20:58 +08:00
										 |  |  | 	for _, t := range auditTgts { | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 		if err := t.Send(entry); err != nil { | 
					
						
							|  |  |  | 			LogAlwaysIf(context.Background(), fmt.Errorf("event(%v) was not sent to Audit target (%v): %v", entry, t, err), madmin.LogKindAll) | 
					
						
							| 
									
										
										
										
											2021-12-21 05:16:53 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-20 06:47:03 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |