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 }