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.compat import json 25from boto.connection import AWSQueryConnection 26from boto.regioninfo import RegionInfo 27from boto.exception import JSONResponseError 28from boto.configservice import exceptions 29 30 31class ConfigServiceConnection(AWSQueryConnection): 32 """ 33 AWS Config 34 AWS Config provides a way to keep track of the configurations of 35 all the AWS resources associated with your AWS account. You can 36 use AWS Config to get the current and historical configurations of 37 each AWS resource and also to get information about the 38 relationship between the resources. An AWS resource can be an 39 Amazon Compute Cloud (Amazon EC2) instance, an Elastic Block Store 40 (EBS) volume, an Elastic network Interface (ENI), or a security 41 group. For a complete list of resources currently supported by AWS 42 Config, see `Supported AWS Resources`_. 43 44 You can access and manage AWS Config through the AWS Management 45 Console, the AWS Command Line Interface (AWS CLI), the AWS Config 46 API, or the AWS SDKs for AWS Config 47 48 This reference guide contains documentation for the AWS Config API 49 and the AWS CLI commands that you can use to manage AWS Config. 50 51 The AWS Config API uses the Signature Version 4 protocol for 52 signing requests. For more information about how to sign a request 53 with this protocol, see `Signature Version 4 Signing Process`_. 54 55 For detailed information about AWS Config features and their 56 associated actions or commands, as well as how to work with AWS 57 Management Console, see `What Is AWS Config?`_ in the AWS Config 58 Developer Guide . 59 """ 60 APIVersion = "2014-11-12" 61 DefaultRegionName = "us-east-1" 62 DefaultRegionEndpoint = "config.us-east-1.amazonaws.com" 63 ServiceName = "ConfigService" 64 TargetPrefix = "StarlingDoveService" 65 ResponseError = JSONResponseError 66 67 _faults = { 68 "InvalidLimitException": exceptions.InvalidLimitException, 69 "NoSuchBucketException": exceptions.NoSuchBucketException, 70 "InvalidSNSTopicARNException": exceptions.InvalidSNSTopicARNException, 71 "ResourceNotDiscoveredException": exceptions.ResourceNotDiscoveredException, 72 "MaxNumberOfDeliveryChannelsExceededException": exceptions.MaxNumberOfDeliveryChannelsExceededException, 73 "LastDeliveryChannelDeleteFailedException": exceptions.LastDeliveryChannelDeleteFailedException, 74 "InsufficientDeliveryPolicyException": exceptions.InsufficientDeliveryPolicyException, 75 "InvalidRoleException": exceptions.InvalidRoleException, 76 "InvalidTimeRangeException": exceptions.InvalidTimeRangeException, 77 "NoSuchDeliveryChannelException": exceptions.NoSuchDeliveryChannelException, 78 "NoSuchConfigurationRecorderException": exceptions.NoSuchConfigurationRecorderException, 79 "InvalidS3KeyPrefixException": exceptions.InvalidS3KeyPrefixException, 80 "InvalidDeliveryChannelNameException": exceptions.InvalidDeliveryChannelNameException, 81 "NoRunningConfigurationRecorderException": exceptions.NoRunningConfigurationRecorderException, 82 "ValidationException": exceptions.ValidationException, 83 "NoAvailableConfigurationRecorderException": exceptions.NoAvailableConfigurationRecorderException, 84 "InvalidNextTokenException": exceptions.InvalidNextTokenException, 85 "InvalidConfigurationRecorderNameException": exceptions.InvalidConfigurationRecorderNameException, 86 "NoAvailableDeliveryChannelException": exceptions.NoAvailableDeliveryChannelException, 87 "MaxNumberOfConfigurationRecordersExceededException": exceptions.MaxNumberOfConfigurationRecordersExceededException, 88 } 89 90 91 def __init__(self, **kwargs): 92 region = kwargs.pop('region', None) 93 if not region: 94 region = RegionInfo(self, self.DefaultRegionName, 95 self.DefaultRegionEndpoint) 96 97 if 'host' not in kwargs or kwargs['host'] is None: 98 kwargs['host'] = region.endpoint 99 100 super(ConfigServiceConnection, self).__init__(**kwargs) 101 self.region = region 102 103 def _required_auth_capability(self): 104 return ['hmac-v4'] 105 106 def delete_delivery_channel(self, delivery_channel_name): 107 """ 108 Deletes the specified delivery channel. 109 110 The delivery channel cannot be deleted if it is the only 111 delivery channel and the configuration recorder is still 112 running. To delete the delivery channel, stop the running 113 configuration recorder using the StopConfigurationRecorder 114 action. 115 116 :type delivery_channel_name: string 117 :param delivery_channel_name: The name of the delivery channel to 118 delete. 119 120 """ 121 params = {'DeliveryChannelName': delivery_channel_name, } 122 return self.make_request(action='DeleteDeliveryChannel', 123 body=json.dumps(params)) 124 125 def deliver_config_snapshot(self, delivery_channel_name): 126 """ 127 Schedules delivery of a configuration snapshot to the Amazon 128 S3 bucket in the specified delivery channel. After the 129 delivery has started, AWS Config sends following notifications 130 using an Amazon SNS topic that you have specified. 131 132 133 + Notification of starting the delivery. 134 + Notification of delivery completed, if the delivery was 135 successfully completed. 136 + Notification of delivery failure, if the delivery failed to 137 complete. 138 139 :type delivery_channel_name: string 140 :param delivery_channel_name: The name of the delivery channel through 141 which the snapshot is delivered. 142 143 """ 144 params = {'deliveryChannelName': delivery_channel_name, } 145 return self.make_request(action='DeliverConfigSnapshot', 146 body=json.dumps(params)) 147 148 def describe_configuration_recorder_status(self, 149 configuration_recorder_names=None): 150 """ 151 Returns the current status of the specified configuration 152 recorder. If a configuration recorder is not specified, this 153 action returns the status of all configuration recorder 154 associated with the account. 155 156 :type configuration_recorder_names: list 157 :param configuration_recorder_names: The name(s) of the configuration 158 recorder. If the name is not specified, the action returns the 159 current status of all the configuration recorders associated with 160 the account. 161 162 """ 163 params = {} 164 if configuration_recorder_names is not None: 165 params['ConfigurationRecorderNames'] = configuration_recorder_names 166 return self.make_request(action='DescribeConfigurationRecorderStatus', 167 body=json.dumps(params)) 168 169 def describe_configuration_recorders(self, 170 configuration_recorder_names=None): 171 """ 172 Returns the name of one or more specified configuration 173 recorders. If the recorder name is not specified, this action 174 returns the names of all the configuration recorders 175 associated with the account. 176 177 :type configuration_recorder_names: list 178 :param configuration_recorder_names: A list of configuration recorder 179 names. 180 181 """ 182 params = {} 183 if configuration_recorder_names is not None: 184 params['ConfigurationRecorderNames'] = configuration_recorder_names 185 return self.make_request(action='DescribeConfigurationRecorders', 186 body=json.dumps(params)) 187 188 def describe_delivery_channel_status(self, delivery_channel_names=None): 189 """ 190 Returns the current status of the specified delivery channel. 191 If a delivery channel is not specified, this action returns 192 the current status of all delivery channels associated with 193 the account. 194 195 :type delivery_channel_names: list 196 :param delivery_channel_names: A list of delivery channel names. 197 198 """ 199 params = {} 200 if delivery_channel_names is not None: 201 params['DeliveryChannelNames'] = delivery_channel_names 202 return self.make_request(action='DescribeDeliveryChannelStatus', 203 body=json.dumps(params)) 204 205 def describe_delivery_channels(self, delivery_channel_names=None): 206 """ 207 Returns details about the specified delivery channel. If a 208 delivery channel is not specified, this action returns the 209 details of all delivery channels associated with the account. 210 211 :type delivery_channel_names: list 212 :param delivery_channel_names: A list of delivery channel names. 213 214 """ 215 params = {} 216 if delivery_channel_names is not None: 217 params['DeliveryChannelNames'] = delivery_channel_names 218 return self.make_request(action='DescribeDeliveryChannels', 219 body=json.dumps(params)) 220 221 def get_resource_config_history(self, resource_type, resource_id, 222 later_time=None, earlier_time=None, 223 chronological_order=None, limit=None, 224 next_token=None): 225 """ 226 Returns a list of configuration items for the specified 227 resource. The list contains details about each state of the 228 resource during the specified time interval. You can specify a 229 `limit` on the number of results returned on the page. If a 230 limit is specified, a `nextToken` is returned as part of the 231 result that you can use to continue this request. 232 233 :type resource_type: string 234 :param resource_type: The resource type. 235 236 :type resource_id: string 237 :param resource_id: The ID of the resource (for example., `sg-xxxxxx`). 238 239 :type later_time: timestamp 240 :param later_time: The time stamp that indicates a later time. If not 241 specified, current time is taken. 242 243 :type earlier_time: timestamp 244 :param earlier_time: The time stamp that indicates an earlier time. If 245 not specified, the action returns paginated results that contain 246 configuration items that start from when the first configuration 247 item was recorded. 248 249 :type chronological_order: string 250 :param chronological_order: The chronological order for configuration 251 items listed. By default the results are listed in reverse 252 chronological order. 253 254 :type limit: integer 255 :param limit: The maximum number of configuration items returned in 256 each page. The default is 10. You cannot specify a limit greater 257 than 100. 258 259 :type next_token: string 260 :param next_token: An optional parameter used for pagination of the 261 results. 262 263 """ 264 params = { 265 'resourceType': resource_type, 266 'resourceId': resource_id, 267 } 268 if later_time is not None: 269 params['laterTime'] = later_time 270 if earlier_time is not None: 271 params['earlierTime'] = earlier_time 272 if chronological_order is not None: 273 params['chronologicalOrder'] = chronological_order 274 if limit is not None: 275 params['limit'] = limit 276 if next_token is not None: 277 params['nextToken'] = next_token 278 return self.make_request(action='GetResourceConfigHistory', 279 body=json.dumps(params)) 280 281 def put_configuration_recorder(self, configuration_recorder): 282 """ 283 Creates a new configuration recorder to record the resource 284 configurations. 285 286 You can use this action to change the role ( `roleARN`) of an 287 existing recorder. To change the role, call the action on the 288 existing configuration recorder and specify a role. 289 290 :type configuration_recorder: dict 291 :param configuration_recorder: The configuration recorder object that 292 records each configuration change made to the resources. 293 294 """ 295 params = {'ConfigurationRecorder': configuration_recorder, } 296 return self.make_request(action='PutConfigurationRecorder', 297 body=json.dumps(params)) 298 299 def put_delivery_channel(self, delivery_channel): 300 """ 301 Creates a new delivery channel object to deliver the 302 configuration information to an Amazon S3 bucket, and to an 303 Amazon SNS topic. 304 305 You can use this action to change the Amazon S3 bucket or an 306 Amazon SNS topic of the existing delivery channel. To change 307 the Amazon S3 bucket or an Amazon SNS topic, call this action 308 and specify the changed values for the S3 bucket and the SNS 309 topic. If you specify a different value for either the S3 310 bucket or the SNS topic, this action will keep the existing 311 value for the parameter that is not changed. 312 313 :type delivery_channel: dict 314 :param delivery_channel: The configuration delivery channel object that 315 delivers the configuration information to an Amazon S3 bucket, and 316 to an Amazon SNS topic. 317 318 """ 319 params = {'DeliveryChannel': delivery_channel, } 320 return self.make_request(action='PutDeliveryChannel', 321 body=json.dumps(params)) 322 323 def start_configuration_recorder(self, configuration_recorder_name): 324 """ 325 Starts recording configurations of all the resources 326 associated with the account. 327 328 You must have created at least one delivery channel to 329 successfully start the configuration recorder. 330 331 :type configuration_recorder_name: string 332 :param configuration_recorder_name: The name of the recorder object 333 that records each configuration change made to the resources. 334 335 """ 336 params = { 337 'ConfigurationRecorderName': configuration_recorder_name, 338 } 339 return self.make_request(action='StartConfigurationRecorder', 340 body=json.dumps(params)) 341 342 def stop_configuration_recorder(self, configuration_recorder_name): 343 """ 344 Stops recording configurations of all the resources associated 345 with the account. 346 347 :type configuration_recorder_name: string 348 :param configuration_recorder_name: The name of the recorder object 349 that records each configuration change made to the resources. 350 351 """ 352 params = { 353 'ConfigurationRecorderName': configuration_recorder_name, 354 } 355 return self.make_request(action='StopConfigurationRecorder', 356 body=json.dumps(params)) 357 358 def make_request(self, action, body): 359 headers = { 360 'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action), 361 'Host': self.region.endpoint, 362 'Content-Type': 'application/x-amz-json-1.1', 363 'Content-Length': str(len(body)), 364 } 365 http_request = self.build_base_http_request( 366 method='POST', path='/', auth_path='/', params={}, 367 headers=headers, data=body) 368 response = self._mexe(http_request, sender=None, 369 override_num_retries=10) 370 response_body = response.read().decode('utf-8') 371 boto.log.debug(response_body) 372 if response.status == 200: 373 if response_body: 374 return json.loads(response_body) 375 else: 376 json_body = json.loads(response_body) 377 fault_name = json_body.get('__type', None) 378 exception_class = self._faults.get(fault_name, self.ResponseError) 379 raise exception_class(response.status, response.reason, 380 body=json_body) 381 382