1# Copyright (c) 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the 5# "Software"), to deal in the Software without restriction, including 6# without limitation the rights to use, copy, modify, merge, publish, dis- 7# tribute, sublicense, and/or sell copies of the Software, and to permit 8# persons to whom the Software is furnished to do so, subject to the fol- 9# lowing conditions: 10# 11# The above copyright notice and this permission notice shall be included 12# in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20# IN THE SOFTWARE. 21# 22 23import boto 24from boto.connection import AWSQueryConnection 25from boto.regioninfo import RegionInfo 26from boto.exception import JSONResponseError 27from boto.cloudtrail import exceptions 28from boto.compat import json 29 30 31class CloudTrailConnection(AWSQueryConnection): 32 """ 33 AWS CloudTrail 34 This is the CloudTrail API Reference. It provides descriptions of 35 actions, data types, common parameters, and common errors for 36 CloudTrail. 37 38 CloudTrail is a web service that records AWS API calls for your 39 AWS account and delivers log files to an Amazon S3 bucket. The 40 recorded information includes the identity of the user, the start 41 time of the AWS API call, the source IP address, the request 42 parameters, and the response elements returned by the service. 43 44 As an alternative to using the API, you can use one of the AWS 45 SDKs, which consist of libraries and sample code for various 46 programming languages and platforms (Java, Ruby, .NET, iOS, 47 Android, etc.). The SDKs provide a convenient way to create 48 programmatic access to AWSCloudTrail. For example, the SDKs take 49 care of cryptographically signing requests, managing errors, and 50 retrying requests automatically. For information about the AWS 51 SDKs, including how to download and install them, see the `Tools 52 for Amazon Web Services page`_. 53 54 See the CloudTrail User Guide for information about the data that 55 is included with each AWS API call listed in the log files. 56 """ 57 APIVersion = "2013-11-01" 58 DefaultRegionName = "us-east-1" 59 DefaultRegionEndpoint = "cloudtrail.us-east-1.amazonaws.com" 60 ServiceName = "CloudTrail" 61 TargetPrefix = "com.amazonaws.cloudtrail.v20131101.CloudTrail_20131101" 62 ResponseError = JSONResponseError 63 64 _faults = { 65 "InvalidMaxResultsException": exceptions.InvalidMaxResultsException, 66 "InvalidSnsTopicNameException": exceptions.InvalidSnsTopicNameException, 67 "InvalidS3BucketNameException": exceptions.InvalidS3BucketNameException, 68 "TrailAlreadyExistsException": exceptions.TrailAlreadyExistsException, 69 "InvalidTimeRangeException": exceptions.InvalidTimeRangeException, 70 "InvalidLookupAttributesException": exceptions.InvalidLookupAttributesException, 71 "InsufficientSnsTopicPolicyException": exceptions.InsufficientSnsTopicPolicyException, 72 "InvalidCloudWatchLogsLogGroupArnException": exceptions.InvalidCloudWatchLogsLogGroupArnException, 73 "InvalidCloudWatchLogsRoleArnException": exceptions.InvalidCloudWatchLogsRoleArnException, 74 "InvalidTrailNameException": exceptions.InvalidTrailNameException, 75 "CloudWatchLogsDeliveryUnavailableException": exceptions.CloudWatchLogsDeliveryUnavailableException, 76 "TrailNotFoundException": exceptions.TrailNotFoundException, 77 "S3BucketDoesNotExistException": exceptions.S3BucketDoesNotExistException, 78 "InvalidNextTokenException": exceptions.InvalidNextTokenException, 79 "InvalidS3PrefixException": exceptions.InvalidS3PrefixException, 80 "MaximumNumberOfTrailsExceededException": exceptions.MaximumNumberOfTrailsExceededException, 81 "InsufficientS3BucketPolicyException": exceptions.InsufficientS3BucketPolicyException, 82 } 83 84 85 def __init__(self, **kwargs): 86 region = kwargs.pop('region', None) 87 if not region: 88 region = RegionInfo(self, self.DefaultRegionName, 89 self.DefaultRegionEndpoint) 90 91 if 'host' not in kwargs or kwargs['host'] is None: 92 kwargs['host'] = region.endpoint 93 94 super(CloudTrailConnection, self).__init__(**kwargs) 95 self.region = region 96 97 def _required_auth_capability(self): 98 return ['hmac-v4'] 99 100 def create_trail(self, name, s3_bucket_name, s3_key_prefix=None, 101 sns_topic_name=None, include_global_service_events=None, 102 cloud_watch_logs_log_group_arn=None, 103 cloud_watch_logs_role_arn=None): 104 """ 105 From the command line, use `create-subscription`. 106 107 Creates a trail that specifies the settings for delivery of 108 log data to an Amazon S3 bucket. 109 110 :type name: string 111 :param name: Specifies the name of the trail. 112 113 :type s3_bucket_name: string 114 :param s3_bucket_name: Specifies the name of the Amazon S3 bucket 115 designated for publishing log files. 116 117 :type s3_key_prefix: string 118 :param s3_key_prefix: Specifies the Amazon S3 key prefix that precedes 119 the name of the bucket you have designated for log file delivery. 120 121 :type sns_topic_name: string 122 :param sns_topic_name: Specifies the name of the Amazon SNS topic 123 defined for notification of log file delivery. 124 125 :type include_global_service_events: boolean 126 :param include_global_service_events: Specifies whether the trail is 127 publishing events from global services such as IAM to the log 128 files. 129 130 :type cloud_watch_logs_log_group_arn: string 131 :param cloud_watch_logs_log_group_arn: Specifies a log group name using 132 an Amazon Resource Name (ARN), a unique identifier that represents 133 the log group to which CloudTrail logs will be delivered. Not 134 required unless you specify CloudWatchLogsRoleArn. 135 136 :type cloud_watch_logs_role_arn: string 137 :param cloud_watch_logs_role_arn: Specifies the role for the CloudWatch 138 Logs endpoint to assume to write to a users log group. 139 140 """ 141 params = {'Name': name, 'S3BucketName': s3_bucket_name, } 142 if s3_key_prefix is not None: 143 params['S3KeyPrefix'] = s3_key_prefix 144 if sns_topic_name is not None: 145 params['SnsTopicName'] = sns_topic_name 146 if include_global_service_events is not None: 147 params['IncludeGlobalServiceEvents'] = include_global_service_events 148 if cloud_watch_logs_log_group_arn is not None: 149 params['CloudWatchLogsLogGroupArn'] = cloud_watch_logs_log_group_arn 150 if cloud_watch_logs_role_arn is not None: 151 params['CloudWatchLogsRoleArn'] = cloud_watch_logs_role_arn 152 return self.make_request(action='CreateTrail', 153 body=json.dumps(params)) 154 155 def delete_trail(self, name): 156 """ 157 Deletes a trail. 158 159 :type name: string 160 :param name: The name of a trail to be deleted. 161 162 """ 163 params = {'Name': name, } 164 return self.make_request(action='DeleteTrail', 165 body=json.dumps(params)) 166 167 def describe_trails(self, trail_name_list=None): 168 """ 169 Retrieves settings for the trail associated with the current 170 region for your account. 171 172 :type trail_name_list: list 173 :param trail_name_list: The trail returned. 174 175 """ 176 params = {} 177 if trail_name_list is not None: 178 params['trailNameList'] = trail_name_list 179 return self.make_request(action='DescribeTrails', 180 body=json.dumps(params)) 181 182 def get_trail_status(self, name): 183 """ 184 Returns a JSON-formatted list of information about the 185 specified trail. Fields include information on delivery 186 errors, Amazon SNS and Amazon S3 errors, and start and stop 187 logging times for each trail. 188 189 :type name: string 190 :param name: The name of the trail for which you are requesting the 191 current status. 192 193 """ 194 params = {'Name': name, } 195 return self.make_request(action='GetTrailStatus', 196 body=json.dumps(params)) 197 198 def lookup_events(self, lookup_attributes=None, start_time=None, 199 end_time=None, max_results=None, next_token=None): 200 """ 201 Looks up API activity events captured by CloudTrail that 202 create, update, or delete resources in your account. Events 203 for a region can be looked up for the times in which you had 204 CloudTrail turned on in that region during the last seven 205 days. Lookup supports five different attributes: time range 206 (defined by a start time and end time), user name, event name, 207 resource type, and resource name. All attributes are optional. 208 The maximum number of attributes that can be specified in any 209 one lookup request are time range and one other attribute. The 210 default number of results returned is 10, with a maximum of 50 211 possible. The response includes a token that you can use to 212 get the next page of results. 213 The rate of lookup requests is limited to one per second per 214 account. If this limit is exceeded, a throttling error occurs. 215 Events that occurred during the selected time range will not 216 be available for lookup if CloudTrail logging was not enabled 217 when the events occurred. 218 219 :type lookup_attributes: list 220 :param lookup_attributes: Contains a list of lookup attributes. 221 Currently the list can contain only one item. 222 223 :type start_time: timestamp 224 :param start_time: Specifies that only events that occur after or at 225 the specified time are returned. If the specified start time is 226 after the specified end time, an error is returned. 227 228 :type end_time: timestamp 229 :param end_time: Specifies that only events that occur before or at the 230 specified time are returned. If the specified end time is before 231 the specified start time, an error is returned. 232 233 :type max_results: integer 234 :param max_results: The number of events to return. Possible values are 235 1 through 50. The default is 10. 236 237 :type next_token: string 238 :param next_token: The token to use to get the next page of results 239 after a previous API call. This token must be passed in with the 240 same parameters that were specified in the the original call. For 241 example, if the original call specified an AttributeKey of 242 'Username' with a value of 'root', the call with NextToken should 243 include those same parameters. 244 245 """ 246 params = {} 247 if lookup_attributes is not None: 248 params['LookupAttributes'] = lookup_attributes 249 if start_time is not None: 250 params['StartTime'] = start_time 251 if end_time is not None: 252 params['EndTime'] = end_time 253 if max_results is not None: 254 params['MaxResults'] = max_results 255 if next_token is not None: 256 params['NextToken'] = next_token 257 return self.make_request(action='LookupEvents', 258 body=json.dumps(params)) 259 260 def start_logging(self, name): 261 """ 262 Starts the recording of AWS API calls and log file delivery 263 for a trail. 264 265 :type name: string 266 :param name: The name of the trail for which CloudTrail logs AWS API 267 calls. 268 269 """ 270 params = {'Name': name, } 271 return self.make_request(action='StartLogging', 272 body=json.dumps(params)) 273 274 def stop_logging(self, name): 275 """ 276 Suspends the recording of AWS API calls and log file delivery 277 for the specified trail. Under most circumstances, there is no 278 need to use this action. You can update a trail without 279 stopping it first. This action is the only way to stop 280 recording. 281 282 :type name: string 283 :param name: Communicates to CloudTrail the name of the trail for which 284 to stop logging AWS API calls. 285 286 """ 287 params = {'Name': name, } 288 return self.make_request(action='StopLogging', 289 body=json.dumps(params)) 290 291 def update_trail(self, name, s3_bucket_name=None, s3_key_prefix=None, 292 sns_topic_name=None, include_global_service_events=None, 293 cloud_watch_logs_log_group_arn=None, 294 cloud_watch_logs_role_arn=None): 295 """ 296 From the command line, use `update-subscription`. 297 298 Updates the settings that specify delivery of log files. 299 Changes to a trail do not require stopping the CloudTrail 300 service. Use this action to designate an existing bucket for 301 log delivery. If the existing bucket has previously been a 302 target for CloudTrail log files, an IAM policy exists for the 303 bucket. 304 305 :type name: string 306 :param name: Specifies the name of the trail. 307 308 :type s3_bucket_name: string 309 :param s3_bucket_name: Specifies the name of the Amazon S3 bucket 310 designated for publishing log files. 311 312 :type s3_key_prefix: string 313 :param s3_key_prefix: Specifies the Amazon S3 key prefix that precedes 314 the name of the bucket you have designated for log file delivery. 315 316 :type sns_topic_name: string 317 :param sns_topic_name: Specifies the name of the Amazon SNS topic 318 defined for notification of log file delivery. 319 320 :type include_global_service_events: boolean 321 :param include_global_service_events: Specifies whether the trail is 322 publishing events from global services such as IAM to the log 323 files. 324 325 :type cloud_watch_logs_log_group_arn: string 326 :param cloud_watch_logs_log_group_arn: Specifies a log group name using 327 an Amazon Resource Name (ARN), a unique identifier that represents 328 the log group to which CloudTrail logs will be delivered. Not 329 required unless you specify CloudWatchLogsRoleArn. 330 331 :type cloud_watch_logs_role_arn: string 332 :param cloud_watch_logs_role_arn: Specifies the role for the CloudWatch 333 Logs endpoint to assume to write to a users log group. 334 335 """ 336 params = {'Name': name, } 337 if s3_bucket_name is not None: 338 params['S3BucketName'] = s3_bucket_name 339 if s3_key_prefix is not None: 340 params['S3KeyPrefix'] = s3_key_prefix 341 if sns_topic_name is not None: 342 params['SnsTopicName'] = sns_topic_name 343 if include_global_service_events is not None: 344 params['IncludeGlobalServiceEvents'] = include_global_service_events 345 if cloud_watch_logs_log_group_arn is not None: 346 params['CloudWatchLogsLogGroupArn'] = cloud_watch_logs_log_group_arn 347 if cloud_watch_logs_role_arn is not None: 348 params['CloudWatchLogsRoleArn'] = cloud_watch_logs_role_arn 349 return self.make_request(action='UpdateTrail', 350 body=json.dumps(params)) 351 352 def make_request(self, action, body): 353 headers = { 354 'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action), 355 'Host': self.region.endpoint, 356 'Content-Type': 'application/x-amz-json-1.1', 357 'Content-Length': str(len(body)), 358 } 359 http_request = self.build_base_http_request( 360 method='POST', path='/', auth_path='/', params={}, 361 headers=headers, data=body) 362 response = self._mexe(http_request, sender=None, 363 override_num_retries=10) 364 response_body = response.read().decode('utf-8') 365 boto.log.debug(response_body) 366 if response.status == 200: 367 if response_body: 368 return json.loads(response_body) 369 else: 370 json_body = json.loads(response_body) 371 fault_name = json_body.get('__type', None) 372 exception_class = self._faults.get(fault_name, self.ResponseError) 373 raise exception_class(response.status, response.reason, 374 body=json_body) 375