yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/cloudtrail.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aws
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/aws/aws-sdk-go/aws/session"
    23  	"github.com/aws/aws-sdk-go/service/cloudtrail"
    24  
    25  	"yunion.io/x/jsonutils"
    26  	"yunion.io/x/log"
    27  	"yunion.io/x/pkg/errors"
    28  
    29  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    30  )
    31  
    32  type SEventResource struct {
    33  	// The name of the resource referenced by the event returned. These are user-created
    34  	// names whose values will depend on the environment. For example, the resource
    35  	// name might be "auto-scaling-test-group" for an Auto Scaling Group or "i-1234567"
    36  	// for an EC2 Instance.
    37  	ResourceName string `type:"string"`
    38  
    39  	// The type of a resource referenced by the event returned. When the resource
    40  	// type cannot be determined, null is returned. Some examples of resource types
    41  	// are: Instance for EC2, Trail for CloudTrail, DBInstance for RDS, and AccessKey
    42  	// for IAM. To learn more about how to look up and filter events by the resource
    43  	// types supported for a service, see Filtering CloudTrail Events (https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events-console.html#filtering-cloudtrail-events).
    44  	ResourceType string `type:"string"`
    45  }
    46  
    47  type SEvent struct {
    48  	// The AWS access key ID that was used to sign the request. If the request was
    49  	// made with temporary security credentials, this is the access key ID of the
    50  	// temporary credentials.
    51  	AccessKeyId string `type:"string"`
    52  
    53  	// A JSON string that contains a representation of the event returned.
    54  	CloudTrailEvent string `type:"string"`
    55  
    56  	// The CloudTrail ID of the event returned.
    57  	EventId string `type:"string"`
    58  
    59  	// The name of the event returned.
    60  	EventName string `type:"string"`
    61  
    62  	// The AWS service that the request was made to.
    63  	EventSource string `type:"string"`
    64  
    65  	// The date and time of the event returned.
    66  	EventTime time.Time `type:"timestamp"`
    67  
    68  	// Information about whether the event is a write event or a read event.
    69  	ReadOnly string `type:"string"`
    70  
    71  	// A list of resources referenced by the event returned.
    72  	Resources []SEventResource `type:"list"`
    73  
    74  	// A user name or role name of the requester that called the API in the event
    75  	// returned.
    76  	Username string `type:"string"`
    77  }
    78  
    79  func (self *SEvent) GetName() string {
    80  	return self.EventName
    81  }
    82  
    83  func (self *SEvent) GetService() string {
    84  	return self.EventSource
    85  }
    86  
    87  func (self *SEvent) GetAction() string {
    88  	return self.EventName
    89  }
    90  
    91  func (self *SEvent) GetResourceType() string {
    92  	return self.EventSource
    93  }
    94  
    95  func (self *SEvent) GetRequestId() string {
    96  	return self.EventId
    97  }
    98  
    99  func (self *SEvent) GetRequest() jsonutils.JSONObject {
   100  	obj, _ := jsonutils.Parse([]byte(self.CloudTrailEvent))
   101  	return obj
   102  }
   103  
   104  func (self *SEvent) GetAccount() string {
   105  	return fmt.Sprintf("%s(%s)", self.AccessKeyId, self.Username)
   106  }
   107  
   108  func (self *SEvent) IsSuccess() bool {
   109  	return !strings.Contains(self.CloudTrailEvent, "errorMessage")
   110  }
   111  
   112  func (self *SEvent) GetCreatedAt() time.Time {
   113  	return self.EventTime
   114  }
   115  
   116  func (self *SRegion) getAwsCloudtrailSession() (*session.Session, error) {
   117  	session, err := self.getAwsSession()
   118  	if err != nil {
   119  		return nil, errors.Wrap(err, "client.getDefaultSession()")
   120  	}
   121  	session.ClientConfig(CLOUD_TRAIL_SERVICE_NAME)
   122  	return session, nil
   123  }
   124  
   125  func (self *SRegion) LookupEvents(start, end time.Time, withReadEvent bool) ([]SEvent, error) {
   126  	s, err := self.getAwsCloudtrailSession()
   127  	if err != nil {
   128  		return nil, errors.Wrapf(err, "getAwsCloudtrailSession")
   129  	}
   130  	client := cloudtrail.New(s)
   131  	input := &cloudtrail.LookupEventsInput{LookupAttributes: []*cloudtrail.LookupAttribute{}}
   132  	if !start.IsZero() {
   133  		input.SetStartTime(start)
   134  	}
   135  	if !end.IsZero() {
   136  		input.SetEndTime(end)
   137  	}
   138  	if !withReadEvent {
   139  		readonly := "ReadOnly"
   140  		val := "false"
   141  		input.LookupAttributes = append(input.LookupAttributes, &cloudtrail.LookupAttribute{
   142  			AttributeKey:   &readonly,
   143  			AttributeValue: &val,
   144  		})
   145  	}
   146  	events := []SEvent{}
   147  	nextToken := ""
   148  	for {
   149  		if len(nextToken) > 0 {
   150  			input.SetNextToken(nextToken)
   151  		}
   152  		var output *cloudtrail.LookupEventsOutput = nil
   153  		for {
   154  			output, err = client.LookupEvents(input)
   155  			if err != nil {
   156  				if strings.Contains(err.Error(), "ThrottlingException") {
   157  					log.Warningf("LookupEvents ThrottlingException, try after 3 seconds")
   158  					time.Sleep(time.Second * 3)
   159  					continue
   160  				}
   161  				return nil, errors.Wrapf(err, "LookupEvents(%s, %s)", start, end)
   162  			}
   163  			break
   164  		}
   165  		for i := range output.Events {
   166  			err := FillZero(output.Events[i])
   167  			if err != nil {
   168  				return nil, errors.Wrapf(err, "FillZero")
   169  			}
   170  			event := SEvent{}
   171  			err = jsonutils.Update(&event, jsonutils.Marshal(output.Events[i]))
   172  			if err != nil {
   173  				return nil, errors.Wrapf(err, "jsonutils.Update")
   174  			}
   175  			if strings.Contains(event.CloudTrailEvent, "awsRegion") && !strings.Contains(event.CloudTrailEvent, fmt.Sprintf(`"awsRegion":"%s"`, self.RegionId)) {
   176  				continue
   177  			}
   178  			events = append(events, event)
   179  		}
   180  		nextToken = ""
   181  		if output.NextToken != nil {
   182  			nextToken = *output.NextToken
   183  		}
   184  		if len(nextToken) == 0 {
   185  			break
   186  		}
   187  	}
   188  	return events, nil
   189  }
   190  
   191  func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) {
   192  	events, err := self.LookupEvents(start, end, withReadEvent)
   193  	if err != nil {
   194  		return nil, errors.Wrapf(err, "LookupEvents(%s, %s)", start, end)
   195  	}
   196  	ret := []cloudprovider.ICloudEvent{}
   197  	for i := range events {
   198  		ret = append(ret, &events[i])
   199  	}
   200  	return ret, nil
   201  }