mirror of https://github.com/minio/minio.git
Audit log claims from token (#6847)
This commit is contained in:
parent
d4265f9a13
commit
9e3fce441e
|
@ -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(w, r, "GetBucketACL")
|
defer logger.AuditLog(w, r, "GetBucketACL", mustGetClaimsFromToken(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(w, r, "GetObjectACL")
|
defer logger.AuditLog(w, r, "GetObjectACL", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
|
@ -19,10 +19,10 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -155,32 +155,56 @@ func getSessionToken(r *http.Request) (token string) {
|
||||||
return r.URL.Query().Get("X-Amz-Security-Token")
|
return r.URL.Query().Get("X-Amz-Security-Token")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch claims in the security token returned by the client and validate the token.
|
// Fetch claims in the security token returned by the client, doesn't return
|
||||||
func getClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]interface{}, APIErrorCode) {
|
// errors - upon errors the returned claims map will be empty.
|
||||||
|
func mustGetClaimsFromToken(r *http.Request) map[string]interface{} {
|
||||||
|
claims, _ := getClaimsFromToken(r)
|
||||||
|
return claims
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch claims in the security token returned by the client.
|
||||||
|
func getClaimsFromToken(r *http.Request) (map[string]interface{}, error) {
|
||||||
|
claims := make(map[string]interface{})
|
||||||
|
token := getSessionToken(r)
|
||||||
|
if token == "" {
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
stsTokenCallback := func(jwtToken *jwtgo.Token) (interface{}, error) {
|
stsTokenCallback := func(jwtToken *jwtgo.Token) (interface{}, error) {
|
||||||
if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok {
|
// JWT token for x-amz-security-token is signed with admin
|
||||||
return nil, fmt.Errorf("Unexpected signing method: %v", jwtToken.Header["alg"])
|
// secret key, temporary credentials become invalid if
|
||||||
}
|
// server admin credentials change. This is done to ensure
|
||||||
if err := jwtToken.Claims.Valid(); err != nil {
|
// that clients cannot decode the token using the temp
|
||||||
return nil, errAuthentication
|
// secret keys and generate an entirely new claim by essentially
|
||||||
}
|
// hijacking the policies. We need to make sure that this is
|
||||||
if claims, ok := jwtToken.Claims.(jwtgo.MapClaims); ok {
|
// based an admin credential such that token cannot be decoded
|
||||||
if _, ok = claims["accessKey"].(string); !ok {
|
// on the client side and is treated like an opaque value.
|
||||||
return nil, errInvalidAccessKeyID
|
return []byte(globalServerConfig.GetCredential().SecretKey), nil
|
||||||
}
|
}
|
||||||
// JWT token for x-amz-security-token is signed with admin
|
p := &jwtgo.Parser{
|
||||||
// secret key, temporary credentials become invalid if
|
ValidMethods: []string{
|
||||||
// server admin credentials change. This is done to ensure
|
jwtgo.SigningMethodHS256.Alg(),
|
||||||
// that clients cannot decode the token using the temp
|
jwtgo.SigningMethodHS512.Alg(),
|
||||||
// secret keys and generate an entirely new claim by essentially
|
},
|
||||||
// hijacking the policies. We need to make sure that this is
|
}
|
||||||
// based an admin credential such that token cannot be decoded
|
jtoken, err := p.ParseWithClaims(token, jwtgo.MapClaims(claims), stsTokenCallback)
|
||||||
// on the client side and is treated like an opaque value.
|
if err != nil {
|
||||||
return []byte(globalServerConfig.GetCredential().SecretKey), nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if !jtoken.Valid {
|
||||||
return nil, errAuthentication
|
return nil, errAuthentication
|
||||||
}
|
}
|
||||||
claims := make(map[string]interface{})
|
v, ok := claims["accessKey"]
|
||||||
|
if !ok {
|
||||||
|
return nil, errInvalidAccessKeyID
|
||||||
|
}
|
||||||
|
if _, ok = v.(string); !ok {
|
||||||
|
return nil, errInvalidAccessKeyID
|
||||||
|
}
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch claims in the security token returned by the client and validate the token.
|
||||||
|
func checkClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]interface{}, APIErrorCode) {
|
||||||
token := getSessionToken(r)
|
token := getSessionToken(r)
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return nil, ErrNone
|
return nil, ErrNone
|
||||||
|
@ -188,16 +212,12 @@ func getClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]inte
|
||||||
if token != "" && cred.AccessKey == "" {
|
if token != "" && cred.AccessKey == "" {
|
||||||
return nil, ErrNoAccessKey
|
return nil, ErrNoAccessKey
|
||||||
}
|
}
|
||||||
if token != cred.SessionToken {
|
if subtle.ConstantTimeCompare([]byte(token), []byte(cred.SessionToken)) != 1 {
|
||||||
return nil, ErrInvalidToken
|
return nil, ErrInvalidToken
|
||||||
}
|
}
|
||||||
p := &jwtgo.Parser{}
|
claims, err := getClaimsFromToken(r)
|
||||||
jtoken, err := p.ParseWithClaims(token, jwtgo.MapClaims(claims), stsTokenCallback)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, toAPIErrorCode(context.Background(), errAuthentication)
|
return nil, toAPIErrorCode(context.Background(), err)
|
||||||
}
|
|
||||||
if !jtoken.Valid {
|
|
||||||
return nil, toAPIErrorCode(context.Background(), errAuthentication)
|
|
||||||
}
|
}
|
||||||
return claims, ErrNone
|
return claims, ErrNone
|
||||||
}
|
}
|
||||||
|
@ -256,7 +276,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac
|
||||||
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := getClaimsFromToken(r, cred)
|
claims, s3Err := checkClaimsFromToken(r, cred)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
@ -421,7 +441,7 @@ func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, s3Err := getClaimsFromToken(r, cred)
|
claims, s3Err := checkClaimsFromToken(r, cred)
|
||||||
if s3Err != ErrNone {
|
if s3Err != ErrNone {
|
||||||
return s3Err
|
return s3Err
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(w, r, "ListObjectsV2")
|
defer logger.AuditLog(w, r, "ListObjectsV2", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -141,7 +141,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(w, r, "ListObjectsV1")
|
defer logger.AuditLog(w, r, "ListObjectsV1", mustGetClaimsFromToken(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(w, r, "GetBucketLocation")
|
defer logger.AuditLog(w, r, "GetBucketLocation", mustGetClaimsFromToken(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(w, r, "ListMultipartUploads")
|
defer logger.AuditLog(w, r, "ListMultipartUploads", mustGetClaimsFromToken(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(w, r, "ListBuckets")
|
defer logger.AuditLog(w, r, "ListBuckets", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -250,7 +250,7 @@ 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(w, r, "DeleteMultipleObjects")
|
defer logger.AuditLog(w, r, "DeleteMultipleObjects", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -397,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(w, r, "PutBucket")
|
defer logger.AuditLog(w, r, "PutBucket", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -475,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(w, r, "PostPolicyBucket")
|
defer logger.AuditLog(w, r, "PostPolicyBucket", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -703,7 +703,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(w, r, "HeadBucket")
|
defer logger.AuditLog(w, r, "HeadBucket", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -735,7 +735,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(w, r, "DeleteBucket")
|
defer logger.AuditLog(w, r, "DeleteBucket", mustGetClaimsFromToken(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(w, r, "GetBucketNotification")
|
defer logger.AuditLog(w, r, "GetBucketNotification", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucketName := vars["bucket"]
|
bucketName := vars["bucket"]
|
||||||
|
@ -102,7 +102,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(w, r, "PutBucketNotification")
|
defer logger.AuditLog(w, r, "PutBucketNotification", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -164,7 +164,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(w, r, "ListenBucketNotification")
|
defer logger.AuditLog(w, r, "ListenBucketNotification", mustGetClaimsFromToken(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(w, r, "PutBucketPolicy")
|
defer logger.AuditLog(w, r, "PutBucketPolicy", mustGetClaimsFromToken(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(w, r, "DeleteBucketPolicy")
|
defer logger.AuditLog(w, r, "DeleteBucketPolicy", mustGetClaimsFromToken(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(w, r, "GetBucketPolicy")
|
defer logger.AuditLog(w, r, "GetBucketPolicy", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
|
|
|
@ -55,7 +55,7 @@ func AddAuditTarget(t Target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuditLog - logs audit logs to all audit targets.
|
// AuditLog - logs audit logs to all audit targets.
|
||||||
func AuditLog(w http.ResponseWriter, r *http.Request, api string) {
|
func AuditLog(w http.ResponseWriter, r *http.Request, api string, reqClaims map[string]interface{}) {
|
||||||
var statusCode int
|
var statusCode int
|
||||||
lrw, ok := w.(*ResponseWriter)
|
lrw, ok := w.(*ResponseWriter)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -63,6 +63,6 @@ func AuditLog(w http.ResponseWriter, r *http.Request, api string) {
|
||||||
}
|
}
|
||||||
// Send audit logs only to http targets.
|
// Send audit logs only to http targets.
|
||||||
for _, t := range AuditTargets {
|
for _, t := range AuditTargets {
|
||||||
t.Send(audit.ToEntry(w, r, api, statusCode))
|
_ = t.Send(audit.ToEntry(w, r, api, statusCode, reqClaims))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,16 +40,17 @@ type Entry struct {
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
StatusCode int `json:"statusCode,omitempty"`
|
StatusCode int `json:"statusCode,omitempty"`
|
||||||
} `json:"api"`
|
} `json:"api"`
|
||||||
RemoteHost string `json:"remotehost,omitempty"`
|
RemoteHost string `json:"remotehost,omitempty"`
|
||||||
RequestID string `json:"requestID,omitempty"`
|
RequestID string `json:"requestID,omitempty"`
|
||||||
UserAgent string `json:"userAgent,omitempty"`
|
UserAgent string `json:"userAgent,omitempty"`
|
||||||
ReqQuery map[string]string `json:"requestQuery,omitempty"`
|
ReqClaims map[string]interface{} `json:"requestClaims,omitempty"`
|
||||||
ReqHeader map[string]string `json:"requestHeader,omitempty"`
|
ReqQuery map[string]string `json:"requestQuery,omitempty"`
|
||||||
RespHeader map[string]string `json:"responseHeader,omitempty"`
|
ReqHeader map[string]string `json:"requestHeader,omitempty"`
|
||||||
|
RespHeader map[string]string `json:"responseHeader,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToEntry - constructs an audit entry object.
|
// ToEntry - constructs an audit entry object.
|
||||||
func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int) Entry {
|
func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int, reqClaims map[string]interface{}) Entry {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
object := vars["object"]
|
object := vars["object"]
|
||||||
|
@ -77,6 +78,7 @@ func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int)
|
||||||
Time: time.Now().UTC().Format(time.RFC3339Nano),
|
Time: time.Now().UTC().Format(time.RFC3339Nano),
|
||||||
ReqQuery: reqQuery,
|
ReqQuery: reqQuery,
|
||||||
ReqHeader: reqHeader,
|
ReqHeader: reqHeader,
|
||||||
|
ReqClaims: reqClaims,
|
||||||
RespHeader: respHeader,
|
RespHeader: respHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(w, r, "SelectObject")
|
defer logger.AuditLog(w, r, "SelectObject", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
// Fetch object stat info.
|
// Fetch object stat info.
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
|
@ -305,7 +305,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(w, r, "GetObject")
|
defer logger.AuditLog(w, r, "GetObject", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -473,7 +473,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(w, r, "HeadObject")
|
defer logger.AuditLog(w, r, "HeadObject", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -656,7 +656,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(w, r, "CopyObject")
|
defer logger.AuditLog(w, r, "CopyObject", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -1028,7 +1028,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(w, r, "PutObject")
|
defer logger.AuditLog(w, r, "PutObject", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -1291,7 +1291,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(w, r, "NewMultipartUpload")
|
defer logger.AuditLog(w, r, "NewMultipartUpload", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -1388,7 +1388,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(w, r, "CopyObjectPart")
|
defer logger.AuditLog(w, r, "CopyObjectPart", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -1632,7 +1632,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(w, r, "PutObjectPart")
|
defer logger.AuditLog(w, r, "PutObjectPart", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -1883,7 +1883,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(w, r, "AbortMultipartUpload")
|
defer logger.AuditLog(w, r, "AbortMultipartUpload", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -1929,7 +1929,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(w, r, "ListObjectParts")
|
defer logger.AuditLog(w, r, "ListObjectParts", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -2008,7 +2008,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(w, r, "CompleteMultipartUpload")
|
defer logger.AuditLog(w, r, "CompleteMultipartUpload", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
@ -2187,7 +2187,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(w, r, "DeleteObject")
|
defer logger.AuditLog(w, r, "DeleteObject", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
|
@ -127,6 +127,8 @@ type ClientGrantsResult struct {
|
||||||
func (sts *stsAPIHandlers) AssumeRoleWithClientGrants(w http.ResponseWriter, r *http.Request) {
|
func (sts *stsAPIHandlers) AssumeRoleWithClientGrants(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "AssumeRoleWithClientGrants")
|
ctx := newContext(r, w, "AssumeRoleWithClientGrants")
|
||||||
|
|
||||||
|
defer logger.AuditLog(w, r, "AssumeRoleWithClientGrants", nil)
|
||||||
|
|
||||||
if globalIAMValidators == nil {
|
if globalIAMValidators == nil {
|
||||||
writeSTSErrorResponse(w, ErrSTSNotInitialized)
|
writeSTSErrorResponse(w, ErrSTSNotInitialized)
|
||||||
return
|
return
|
||||||
|
|
|
@ -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(w, r, "WebUpload")
|
defer logger.AuditLog(w, r, "WebUpload", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -845,7 +845,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
||||||
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(w, r, "WebDownload")
|
defer logger.AuditLog(w, r, "WebDownload", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
|
@ -1027,7 +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(w, r, "WebDownloadZip")
|
defer logger.AuditLog(w, r, "WebDownloadZip", mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
|
|
|
@ -77,27 +77,45 @@ Setting this environment variable automatically enables audit logging to the HTT
|
||||||
{
|
{
|
||||||
"version": "1",
|
"version": "1",
|
||||||
"deploymentid": "1b3002bf-5005-4d9b-853e-64a05008ebb2",
|
"deploymentid": "1b3002bf-5005-4d9b-853e-64a05008ebb2",
|
||||||
"time": "2018-11-02T21:57:58.231480177Z",
|
"time": "2018-11-21T23:16:06.828154172Z",
|
||||||
"api": {
|
"api": {
|
||||||
"name": "ListBuckets",
|
"name": "PutObject",
|
||||||
"args": {}
|
"bucket": "my-bucketname",
|
||||||
|
"object": "my-objectname",
|
||||||
|
"status": "OK",
|
||||||
|
"statusCode": 200
|
||||||
},
|
},
|
||||||
"remotehost": "127.0.0.1",
|
"remotehost": "127.0.0.1",
|
||||||
"requestID": "15636D7C53428FD4",
|
"requestID": "156946C6C1E7842C",
|
||||||
"userAgent": "Minio (linux; amd64) minio-go/v6.0.8 mc/2018-11-02T21:13:30Z",
|
"userAgent": "Minio (linux; amd64) minio-go/v6.0.6",
|
||||||
|
"requestClaims": {
|
||||||
|
"accessKey": "A1YABB5YPX3ZPL4227XJ",
|
||||||
|
"aud": "PoEgXP6uVO45IsENRngDXj5Au5Ya",
|
||||||
|
"azp": "PoEgXP6uVO45IsENRngDXj5Au5Ya",
|
||||||
|
"exp": 1542845766,
|
||||||
|
"iat": 1542842166,
|
||||||
|
"iss": "https://localhost:9443/oauth2/token",
|
||||||
|
"jti": "33527fcc-254f-43d2-a558-4942554b8ff8"
|
||||||
|
},
|
||||||
"requestHeader": {
|
"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",
|
"Authorization": "AWS4-HMAC-SHA256 Credential=A1YABB5YPX3ZPL4227XJ/20181121/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length;x-amz-security-token,Signature=689d9b8f67b5625ea2f0b8cbb3f777d8839a91d50aa81e6a5555f5a6360c1714",
|
||||||
"User-Agent": "Minio (linux; amd64) minio-go/v6.0.8 mc/2018-11-02T21:13:30Z",
|
"Content-Length": "184",
|
||||||
"X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
"Content-Type": "application/octet-stream",
|
||||||
"X-Amz-Date": "20181102T215758Z"
|
"User-Agent": "Minio (linux; amd64) minio-go/v6.0.6",
|
||||||
|
"X-Amz-Content-Sha256": "STREAMING-AWS4-HMAC-SHA256-PAYLOAD",
|
||||||
|
"X-Amz-Date": "20181121T231606Z",
|
||||||
|
"X-Amz-Decoded-Content-Length": "12",
|
||||||
|
"X-Amz-Security-Token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJBMVlBQkI1WVBYM1pQTDQyMjdYSiIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTQyODQ1NzY2LCJpYXQiOjE1NDI4NDIxNjYsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiMzM1MjdmY2MtMjU0Zi00M2QyLWE1NTgtNDk0MjU1NGI4ZmY4In0.KEuAq2cQ3H7dfIB5DVuvcgBXT38mr0gthrIbVRSZcA2OWo8QiH1-DWXj9xYbndgr1p2tiEUsQ49cuszQGEVGMQ"
|
||||||
},
|
},
|
||||||
"responseHeader": {
|
"responseHeader": {
|
||||||
"Accept-Ranges": "bytes",
|
"Accept-Ranges": "bytes",
|
||||||
"Content-Security-Policy": "block-all-mixed-content",
|
"Content-Security-Policy": "block-all-mixed-content",
|
||||||
"Content-Type": "application/xml",
|
"Content-Type": "application/xml",
|
||||||
"Server": "Minio/DEVELOPMENT.2018-11-02T21-57-15Z (linux; amd64)",
|
"Etag": "",
|
||||||
|
"Server": "Minio/DEVELOPMENT.2018-11-21T23-15-06Z (linux; amd64)",
|
||||||
"Vary": "Origin",
|
"Vary": "Origin",
|
||||||
"X-Amz-Request-Id": "15636D7C53428FD4",
|
"X-Amz-Request-Id": "156946C6C1E7842C",
|
||||||
|
"X-Minio-Deployment-Id": "1b3002bf-5005-4d9b-853e-64a05008ebb2",
|
||||||
"X-Xss-Protection": "1; mode=block"
|
"X-Xss-Protection": "1; mode=block"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue