miasma-aws 0.3.10 → 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 54f66c56014d6208b48fa49c6cbc575aa8a6f0d7
4
- data.tar.gz: 749ca6c300324d40a902c8a4dd973da0353d4ffe
2
+ SHA256:
3
+ metadata.gz: 136015ad26078a11d453df779c7116887ca4198d5f1c7901d5f3f20a9dcb1bf3
4
+ data.tar.gz: 149a662fb85e2dacd67427b92192732af6031a7ab23f893f351a093360403d30
5
5
  SHA512:
6
- metadata.gz: bc16ef05b273669558d5c6399ce8eaad2d56d5d60a0a585e7553250e710b6dd2d47e1b714ab77fe700881fd4dd53dbb08ad3023ebeb16e4ab383a6a209d55a58
7
- data.tar.gz: 83842317dd075fff71c66c121d011c490f457cb9a015040a9afca2d769b0dbb0615fc4568dcfa5af4aa24ceb354306ddf6bc2fdefee98f47e40d29b9493bcf00
6
+ metadata.gz: 300f29b1dacc60e70f6da191d32844a539e000e7fe9754dd07424b4b832dd1201ee2750768b40efd0aca6dbfe072fe94fcc0442b19492e98f6a777d5fd65eb17
7
+ data.tar.gz: e7b1c007d3d54b4147d83c3ac0975f2c26fe1593067e4c7d1a8a52ea697644f1351de7e6fc10583cecc8d651b59cb130804246ebd1a2e95fc81d317c7991787d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # v0.3.12
2
+ * [enhancement] Add support for defaulting to `AWS_` env vars
3
+ * [fix] Properly parse AWS configuration/credentials file
4
+
1
5
  # v0.3.10
2
6
  * [fix] Use custom attribute to store last stack event ID (#45)
3
7
 
data/lib/miasma-aws.rb CHANGED
@@ -1,2 +1,2 @@
1
- require 'miasma'
2
- require 'miasma-aws/version'
1
+ require "miasma"
2
+ require "miasma-aws/version"
@@ -1,12 +1,12 @@
1
- require 'miasma'
1
+ require "miasma"
2
2
 
3
3
  module Miasma
4
4
  module Contrib
5
5
  module Aws
6
6
  # AWS API helpers
7
7
  module Api
8
- autoload :Sts, 'miasma-aws/api/sts'
9
- autoload :Iam, 'miasma-aws/api/iam'
8
+ autoload :Sts, "miasma-aws/api/sts"
9
+ autoload :Iam, "miasma-aws/api/iam"
10
10
  end
11
11
  end
12
12
  end
@@ -1,4 +1,4 @@
1
- require 'miasma'
1
+ require "miasma"
2
2
 
3
3
  module Miasma
4
4
  module Contrib
@@ -8,9 +8,9 @@ module Miasma
8
8
  class Iam < Miasma::Types::Api
9
9
 
10
10
  # Service name of the API
11
- API_SERVICE = 'iam'.freeze
11
+ API_SERVICE = "iam".freeze
12
12
  # Supported version of the IAM API
13
- API_VERSION = '2010-05-08'.freeze
13
+ API_VERSION = "2010-05-08".freeze
14
14
 
15
15
  include Contrib::AwsApiCore::ApiCommon
16
16
  include Contrib::AwsApiCore::RequestUtils
@@ -20,29 +20,28 @@ module Miasma
20
20
  service_name = self.class::API_SERVICE.downcase
21
21
  self.aws_host = [
22
22
  service_name,
23
- api_endpoint
24
- ].join('.')
23
+ api_endpoint,
24
+ ].join(".")
25
25
  end
26
26
 
27
27
  # Fetch current user information
28
28
  def user_info
29
29
  result = request(
30
- :path => '/',
30
+ :path => "/",
31
31
  :params => {
32
- 'Action' => 'GetUser'
33
- }
34
- ).get(:body, 'GetUserResponse', 'GetUserResult', 'User')
32
+ "Action" => "GetUser",
33
+ },
34
+ ).get(:body, "GetUserResponse", "GetUserResult", "User")
35
35
  Smash.new(
36
- :user_id => result['UserId'],
37
- :path => result['Path'],
38
- :username => result['UserName'],
39
- :arn => result['Arn'],
40
- :created => result['CreateDate'],
41
- :password_last_used => result['PasswordLastUsed'],
42
- :account_id => result['Arn'].split(':')[4]
36
+ :user_id => result["UserId"],
37
+ :path => result["Path"],
38
+ :username => result["UserName"],
39
+ :arn => result["Arn"],
40
+ :created => result["CreateDate"],
41
+ :password_last_used => result["PasswordLastUsed"],
42
+ :account_id => result["Arn"].split(":")[4],
43
43
  )
44
44
  end
45
-
46
45
  end
47
46
  end
48
47
  end
@@ -1,4 +1,4 @@
1
- require 'miasma'
1
+ require "miasma"
2
2
 
3
3
  module Miasma
4
4
  module Contrib
@@ -8,9 +8,9 @@ module Miasma
8
8
  class Sts < Miasma::Types::Api
9
9
 
10
10
  # Service name of the API
11
- API_SERVICE = 'sts'.freeze
11
+ API_SERVICE = "sts".freeze
12
12
  # Supported version of the STS API
13
- API_VERSION = '2011-06-15'.freeze
13
+ API_VERSION = "2011-06-15".freeze
14
14
 
15
15
  include Contrib::AwsApiCore::ApiCommon
16
16
  include Contrib::AwsApiCore::RequestUtils
@@ -22,22 +22,22 @@ module Miasma
22
22
  # @option args [Integer] :duration life of session in seconds
23
23
  # @option args [String] :mfa_serial MFA device identification number
24
24
  # @return [Hash]
25
- def mfa_session(token_code, args={})
25
+ def mfa_session(token_code, args = {})
26
26
  req_params = Smash.new.tap do |params|
27
- params['Action'] = 'GetSessionToken'
28
- params['TokenCode'] = token_code.respond_to?(:call) ? token_code.call : token_code
29
- params['DurationSeconds'] = args[:duration] if args[:duration]
30
- params['SerialNumber'] = args[:mfa_serial].to_s.empty? ? default_mfa_serial : args[:mfa_serial]
27
+ params["Action"] = "GetSessionToken"
28
+ params["TokenCode"] = token_code.respond_to?(:call) ? token_code.call : token_code
29
+ params["DurationSeconds"] = args[:duration] if args[:duration]
30
+ params["SerialNumber"] = args[:mfa_serial].to_s.empty? ? default_mfa_serial : args[:mfa_serial]
31
31
  end
32
32
  result = request(
33
- :path => '/',
34
- :params => req_params
35
- ).get(:body, 'GetSessionTokenResponse', 'GetSessionTokenResult', 'Credentials')
33
+ :path => "/",
34
+ :params => req_params,
35
+ ).get(:body, "GetSessionTokenResponse", "GetSessionTokenResult", "Credentials")
36
36
  Smash.new(
37
- :aws_sts_session_token => result['SessionToken'],
38
- :aws_sts_session_secret_access_key => result['SecretAccessKey'],
39
- :aws_sts_session_access_key_id => result['AccessKeyId'],
40
- :aws_sts_session_token_expires => Time.parse(result['Expiration'])
37
+ :aws_sts_session_token => result["SessionToken"],
38
+ :aws_sts_session_secret_access_key => result["SecretAccessKey"],
39
+ :aws_sts_session_access_key_id => result["AccessKeyId"],
40
+ :aws_sts_session_token_expires => Time.parse(result["Expiration"]),
41
41
  )
42
42
  end
43
43
 
@@ -48,24 +48,24 @@ module Miasma
48
48
  # @option args [String] :external_id
49
49
  # @option args [String] :session_name
50
50
  # @return [Hash]
51
- def assume_role(role_arn, args={})
51
+ def assume_role(role_arn, args = {})
52
52
  req_params = Smash.new.tap do |params|
53
- params['Action'] = 'AssumeRole'
54
- params['RoleArn'] = role_arn
55
- params['RoleSessionName'] = args[:session_name] || SecureRandom.uuid.tr('-', '')
56
- params['ExternalId'] = args[:external_id] if args[:external_id]
53
+ params["Action"] = "AssumeRole"
54
+ params["RoleArn"] = role_arn
55
+ params["RoleSessionName"] = args[:session_name] || SecureRandom.uuid.tr("-", "")
56
+ params["ExternalId"] = args[:external_id] if args[:external_id]
57
57
  end
58
58
  result = request(
59
- :path => '/',
60
- :params => req_params
61
- ).get(:body, 'AssumeRoleResponse', 'AssumeRoleResult')
59
+ :path => "/",
60
+ :params => req_params,
61
+ ).get(:body, "AssumeRoleResponse", "AssumeRoleResult")
62
62
  Smash.new(
63
- :aws_sts_token => result.get('Credentials', 'SessionToken'),
64
- :aws_sts_secret_access_key => result.get('Credentials', 'SecretAccessKey'),
65
- :aws_sts_access_key_id => result.get('Credentials', 'AccessKeyId'),
66
- :aws_sts_token_expires => Time.parse(result.get('Credentials', 'Expiration')),
67
- :aws_sts_assumed_role_arn => result.get('AssumedRoleUser', 'Arn'),
68
- :aws_sts_assumed_role_id => result.get('AssumedRoleUser', 'AssumedRoleId')
63
+ :aws_sts_token => result.get("Credentials", "SessionToken"),
64
+ :aws_sts_secret_access_key => result.get("Credentials", "SecretAccessKey"),
65
+ :aws_sts_access_key_id => result.get("Credentials", "AccessKeyId"),
66
+ :aws_sts_token_expires => Time.parse(result.get("Credentials", "Expiration")),
67
+ :aws_sts_assumed_role_arn => result.get("AssumedRoleUser", "Arn"),
68
+ :aws_sts_assumed_role_id => result.get("AssumedRoleUser", "AssumedRoleId"),
69
69
  )
70
70
  end
71
71
 
@@ -80,7 +80,6 @@ module Miasma
80
80
  ).user_info
81
81
  "arn:aws:iam::#{user_data[:account_id]}:mfa/#{user_data[:username]}"
82
82
  end
83
-
84
83
  end
85
84
  end
86
85
  end
@@ -1,4 +1,4 @@
1
1
  module MiasmaAws
2
2
  # Current library version
3
- VERSION = Gem::Version.new('0.3.10')
3
+ VERSION = Gem::Version.new("0.3.12")
4
4
  end
@@ -1,16 +1,17 @@
1
- require 'miasma'
2
- require 'miasma/utils/smash'
1
+ require "miasma"
2
+ require "miasma/utils/smash"
3
3
 
4
- require 'time'
5
- require 'openssl'
4
+ require "time"
5
+ require "openssl"
6
6
 
7
7
  # Miasma
8
8
  module Miasma
9
9
  module Contrib
10
10
  # AWS API implementations
11
11
  module Aws
12
- autoload :Api, 'miasma-aws/api'
12
+ autoload :Api, "miasma-aws/api"
13
13
  end
14
+
14
15
  # Core API for AWS access
15
16
  class AwsApiCore
16
17
 
@@ -27,31 +28,30 @@ module Miasma
27
28
  # @return [Array]
28
29
  def all_result_pages(next_token, *result_key, &block)
29
30
  list = []
30
- options = next_token ? Smash.new('NextToken' => next_token) : Smash.new
31
+ options = next_token ? Smash.new("NextToken" => next_token) : Smash.new
31
32
  result = block.call(options)
32
33
  content = result.get(*result_key.dup)
33
- if(content.is_a?(Array))
34
+ if content.is_a?(Array)
34
35
  list += content
35
36
  else
36
37
  list << content
37
38
  end
38
39
  set = result.get(*result_key.slice(0, 3))
39
- if(set.is_a?(Hash) && set['NextToken'])
40
+ if set.is_a?(Hash) && set["NextToken"]
40
41
  [content].flatten.compact.each do |item|
41
- if(item.is_a?(Hash))
42
- item['NextToken'] = set['NextToken']
42
+ if item.is_a?(Hash)
43
+ item["NextToken"] = set["NextToken"]
43
44
  end
44
45
  end
45
- list += all_result_pages(set['NextToken'], *result_key, &block)
46
+ list += all_result_pages(set["NextToken"], *result_key, &block)
46
47
  end
47
48
  list.compact
48
49
  end
49
-
50
50
  end
51
51
 
52
52
  # @return [String] current time ISO8601 format
53
53
  def self.time_iso8601
54
- Time.now.utc.strftime('%Y%m%dT%H%M%SZ')
54
+ Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
55
55
  end
56
56
 
57
57
  # HMAC helper class
@@ -93,7 +93,7 @@ module Miasma
93
93
  # @param data [String]
94
94
  # @param key_override [Object]
95
95
  # @return [Object] signature
96
- def sign(data, key_override=nil)
96
+ def sign(data, key_override = nil)
97
97
  result = OpenSSL::HMAC.digest(digest, key_override || key, data)
98
98
  digest.reset
99
99
  result
@@ -104,12 +104,11 @@ module Miasma
104
104
  # @param data [String]
105
105
  # @param key_override [Object]
106
106
  # @return [String] hex encoded signature
107
- def hex_sign(data, key_override=nil)
107
+ def hex_sign(data, key_override = nil)
108
108
  result = OpenSSL::HMAC.hexdigest(digest, key_override || key, data)
109
109
  digest.reset
110
110
  result
111
111
  end
112
-
113
112
  end
114
113
 
115
114
  # Base signature class
@@ -117,7 +116,7 @@ module Miasma
117
116
 
118
117
  # Create new instance
119
118
  def initialize(*args)
120
- raise NotImplementedError.new 'This class should not be used directly!'
119
+ raise NotImplementedError.new "This class should not be used directly!"
121
120
  end
122
121
 
123
122
  # Generate the signature
@@ -126,7 +125,7 @@ module Miasma
126
125
  # @param path [String] request path
127
126
  # @param opts [Hash] request options
128
127
  # @return [String] signature
129
- def generate(http_method, path, opts={})
128
+ def generate(http_method, path, opts = {})
130
129
  raise NotImplementedError
131
130
  end
132
131
 
@@ -136,10 +135,9 @@ module Miasma
136
135
  # @return [String] escaped string
137
136
  def safe_escape(string)
138
137
  string.to_s.gsub(/([^a-zA-Z0-9_.\-~])/) do |match|
139
- '%' << match.unpack('H2' * match.bytesize).join('%').upcase
138
+ "%" << match.unpack("H2" * match.bytesize).join("%").upcase
140
139
  end
141
140
  end
142
-
143
141
  end
144
142
 
145
143
  # AWS signature version 4
@@ -162,7 +160,7 @@ module Miasma
162
160
  # @param service [String]
163
161
  # @return [self]
164
162
  def initialize(access_key, secret_key, region, service)
165
- @hmac = Hmac.new('sha256', secret_key)
163
+ @hmac = Hmac.new("sha256", secret_key)
166
164
  @access_key = access_key
167
165
  @region = region
168
166
  @service = service
@@ -177,7 +175,7 @@ module Miasma
177
175
  def generate(http_method, path, opts)
178
176
  signature = generate_signature(http_method, path, opts)
179
177
  "#{algorithm} Credential=#{access_key}/#{credential_scope}, " \
180
- "SignedHeaders=#{signed_headers(opts[:headers])}, Signature=#{signature}"
178
+ "SignedHeaders=#{signed_headers(opts[:headers])}, Signature=#{signature}"
181
179
  end
182
180
 
183
181
  # Generate URL with signed params
@@ -189,17 +187,17 @@ module Miasma
189
187
  def generate_url(http_method, path, opts)
190
188
  opts[:params].merge!(
191
189
  Smash.new(
192
- 'X-Amz-SignedHeaders' => signed_headers(opts[:headers]),
193
- 'X-Amz-Algorithm' => algorithm,
194
- 'X-Amz-Credential' => "#{access_key}/#{credential_scope}"
190
+ "X-Amz-SignedHeaders" => signed_headers(opts[:headers]),
191
+ "X-Amz-Algorithm" => algorithm,
192
+ "X-Amz-Credential" => "#{access_key}/#{credential_scope}",
195
193
  )
196
194
  )
197
195
  signature = generate_signature(
198
196
  http_method, path,
199
- opts.merge(:body => 'UNSIGNED-PAYLOAD')
197
+ opts.merge(:body => "UNSIGNED-PAYLOAD")
200
198
  )
201
- params = opts[:params].merge('X-Amz-Signature' => signature)
202
- "https://#{opts[:headers]['Host']}/#{path}?#{canonical_query(params)}"
199
+ params = opts[:params].merge("X-Amz-Signature" => signature)
200
+ "https://#{opts[:headers]["Host"]}/#{path}?#{canonical_query(params)}"
203
201
  end
204
202
 
205
203
  # Generate the signature
@@ -211,11 +209,11 @@ module Miasma
211
209
  def generate_signature(http_method, path, opts)
212
210
  to_sign = [
213
211
  algorithm,
214
- opts.to_smash.fetch(:headers, 'X-Amz-Date', AwsApiCore.time_iso8601),
212
+ opts.to_smash.fetch(:headers, "X-Amz-Date", AwsApiCore.time_iso8601),
215
213
  credential_scope,
216
214
  hashed_canonical_request(
217
215
  can_req = build_canonical_request(http_method, path, opts)
218
- )
216
+ ),
219
217
  ].join("\n")
220
218
  signature = sign_request(to_sign)
221
219
  end
@@ -226,13 +224,13 @@ module Miasma
226
224
  # @return [String] signature
227
225
  def sign_request(request)
228
226
  key = hmac.sign(
229
- 'aws4_request',
227
+ "aws4_request",
230
228
  hmac.sign(
231
229
  service,
232
230
  hmac.sign(
233
231
  region,
234
232
  hmac.sign(
235
- Time.now.utc.strftime('%Y%m%d'),
233
+ Time.now.utc.strftime("%Y%m%d"),
236
234
  "AWS4#{hmac.key}"
237
235
  )
238
236
  )
@@ -243,17 +241,17 @@ module Miasma
243
241
 
244
242
  # @return [String] signature algorithm
245
243
  def algorithm
246
- 'AWS4-HMAC-SHA256'
244
+ "AWS4-HMAC-SHA256"
247
245
  end
248
246
 
249
247
  # @return [String] credential scope for request
250
248
  def credential_scope
251
249
  [
252
- Time.now.utc.strftime('%Y%m%d'),
250
+ Time.now.utc.strftime("%Y%m%d"),
253
251
  region,
254
252
  service,
255
- 'aws4_request'
256
- ].join('/')
253
+ "aws4_request",
254
+ ].join("/")
257
255
  end
258
256
 
259
257
  # Generate the hash of the canonical request
@@ -271,7 +269,7 @@ module Miasma
271
269
  # @param opts [Hash] request options
272
270
  # @return [String] canonical request string
273
271
  def build_canonical_request(http_method, path, opts)
274
- unless(path.start_with?('/'))
272
+ unless path.start_with?("/")
275
273
  path = "/#{path}"
276
274
  end
277
275
  [
@@ -280,7 +278,7 @@ module Miasma
280
278
  canonical_query(opts[:params]),
281
279
  canonical_headers(opts[:headers]),
282
280
  signed_headers(opts[:headers]),
283
- canonical_payload(opts)
281
+ canonical_payload(opts),
284
282
  ].join("\n")
285
283
  end
286
284
 
@@ -293,7 +291,7 @@ module Miasma
293
291
  params = Hash[params.sort_by(&:first)]
294
292
  query = params.map do |key, value|
295
293
  "#{safe_escape(key)}=#{safe_escape(value)}"
296
- end.join('&')
294
+ end.join("&")
297
295
  end
298
296
 
299
297
  # Build the canonical header string used for signing
@@ -304,7 +302,7 @@ module Miasma
304
302
  headers ||= {}
305
303
  headers = Hash[headers.sort_by(&:first)]
306
304
  headers.map do |key, value|
307
- [key.downcase, value.chomp].join(':')
305
+ [key.downcase, value.chomp].join(":")
308
306
  end.join("\n") << "\n"
309
307
  end
310
308
 
@@ -315,7 +313,7 @@ module Miasma
315
313
  def signed_headers(headers)
316
314
  headers ||= {}
317
315
  headers.sort_by(&:first).map(&:first).
318
- map(&:downcase).join(';')
316
+ map(&:downcase).join(";")
319
317
  end
320
318
 
321
319
  # Build the canonical payload string used for signing
@@ -323,76 +321,75 @@ module Miasma
323
321
  # @param options [Hash] request options
324
322
  # @return [String] body checksum
325
323
  def canonical_payload(options)
326
- body = options.fetch(:body, '')
327
- if(options[:json])
324
+ body = options.fetch(:body, "")
325
+ if options[:json]
328
326
  body = MultiJson.dump(options[:json])
329
- elsif(options[:form])
327
+ elsif options[:form]
330
328
  body = URI.encode_www_form(options[:form])
331
329
  end
332
- if(body == 'UNSIGNED-PAYLOAD')
330
+ if body == "UNSIGNED-PAYLOAD"
333
331
  body
334
332
  else
335
333
  hmac.hexdigest_of(body)
336
334
  end
337
335
  end
338
-
339
336
  end
340
337
 
341
338
  # Common API setup
342
339
  module ApiCommon
343
-
344
340
  def self.included(klass)
345
341
  klass.class_eval do
346
- attribute :aws_profile_name, [FalseClass, String], :default => 'default'
342
+ attribute :aws_profile_name, [FalseClass, String], :default => ENV.fetch("AWS_PROFILE", "default")
347
343
  attribute :aws_sts_token, String
348
344
  attribute :aws_sts_role_arn, String
349
345
  attribute :aws_sts_external_id, String
350
346
  attribute :aws_sts_role_session_name, String
351
347
  attribute :aws_sts_region, String
352
348
  attribute :aws_sts_host, String
353
- attribute :aws_sts_session_token, String
349
+ attribute :aws_sts_session_token, String, :default => ENV["AWS_SESSION_TOKEN"]
354
350
  attribute :aws_sts_session_token_code, [String, Proc, Method]
355
351
  attribute :aws_sts_mfa_serial_number, [String]
356
- attribute :aws_credentials_file, String, :required => true,
357
- :default => File.join(Dir.home, '.aws/credentials')
358
- attribute :aws_config_file, String, :required => true,
359
- :default => File.join(Dir.home, '.aws/config')
360
- attribute :aws_access_key_id, String, :required => true
361
- attribute :aws_secret_access_key, String, :required => true
352
+ attribute :aws_credentials_file, String,
353
+ :required => true,
354
+ :default => ENV.fetch("AWS_SHARED_CREDENTIALS_FILE", File.join(Dir.home, ".aws/credentials"))
355
+ attribute :aws_config_file, String,
356
+ :required => true,
357
+ :default => ENV.fetch("AWS_CONFIG_FILE", File.join(Dir.home, ".aws/config"))
358
+ attribute :aws_access_key_id, String, :required => true, :default => ENV["AWS_ACCESS_KEY_ID"]
359
+ attribute :aws_secret_access_key, String, :required => true, :default => ENV["AWS_SECRET_ACCESS_KEY"]
362
360
  attribute :aws_iam_instance_profile, [TrueClass, FalseClass], :default => false
363
361
  attribute :aws_ecs_task_profile, [TrueClass, FalseClass], :default => false
364
- attribute :aws_region, String, :required => true
362
+ attribute :aws_region, String, :required => true, :default => ENV["AWS_DEFAULT_REGION"]
365
363
  attribute :aws_host, String
366
364
  attribute :aws_bucket_region, String
367
- attribute :api_endpoint, String, :required => true, :default => 'amazonaws.com'
365
+ attribute :api_endpoint, String, :required => true, :default => "amazonaws.com"
368
366
  attribute :euca_compat, Symbol, :allowed_values => [:path, :dns],
369
- :coerce => lambda{|v| v.is_a?(String) ? v.to_sym : v}
370
- attribute :euca_dns_map, Smash, :coerce => lambda{|v| v.to_smash},
371
- :default => Smash.new
367
+ :coerce => lambda { |v| v.is_a?(String) ? v.to_sym : v }
368
+ attribute :euca_dns_map, Smash, :coerce => lambda { |v| v.to_smash },
369
+ :default => Smash.new
372
370
  attribute :ssl_enabled, [TrueClass, FalseClass], :default => true
373
371
  end
374
372
 
375
373
  # AWS config file key remapping
376
374
  klass.const_set(:CONFIG_FILE_REMAP,
377
- Smash.new(
378
- 'region' => 'aws_region',
379
- 'role_arn' => 'aws_sts_role_arn',
380
- 'aws_security_token' => 'aws_sts_token',
381
- 'aws_session_token' => 'aws_sts_session_token'
382
- ).to_smash.freeze
383
- )
384
- klass.const_set(:INSTANCE_PROFILE_HOST, 'http://169.254.169.254'.freeze)
375
+ Smash.new(
376
+ "region" => "aws_region",
377
+ "role_arn" => "aws_sts_role_arn",
378
+ "aws_security_token" => "aws_sts_token",
379
+ "aws_session_token" => "aws_sts_session_token",
380
+ ).to_smash.freeze)
381
+ klass.const_set(:INSTANCE_PROFILE_HOST, "http://169.254.169.254".freeze)
385
382
  klass.const_set(
386
383
  :INSTANCE_PROFILE_PATH,
387
- 'latest/meta-data/iam/security-credentials'.freeze
384
+ "latest/meta-data/iam/security-credentials".freeze
388
385
  )
389
386
  klass.const_set(
390
387
  :INSTANCE_PROFILE_AZ_PATH,
391
- 'latest/meta-data/placement/availability-zone'.freeze
388
+ "latest/meta-data/placement/availability-zone".freeze
392
389
  )
393
- klass.const_set(:ECS_TASK_PROFILE_HOST, 'http://169.254.170.2'.freeze)
390
+ klass.const_set(:ECS_TASK_PROFILE_HOST, "http://169.254.170.2".freeze)
394
391
  klass.const_set(
395
- :ECS_TASK_PROFILE_PATH, ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']
392
+ :ECS_TASK_PROFILE_PATH, ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
396
393
  )
397
394
  end
398
395
 
@@ -408,7 +405,7 @@ module Miasma
408
405
  Smash.new(
409
406
  :type => type,
410
407
  :provider => provider,
411
- :credentials => creds
408
+ :credentials => creds,
412
409
  )
413
410
  )
414
411
  end
@@ -420,20 +417,24 @@ module Miasma
420
417
  # @param creds [Hash]
421
418
  # @return [TrueClass]
422
419
  def custom_setup(creds)
423
- if(creds[:aws_profile_name])
424
- creds.replace(
425
- load_aws_file(
426
- aws_config_file,
427
- creds[:aws_profile_name]
428
- ).merge(
429
- load_aws_file(
430
- aws_credentials_file,
431
- creds[:aws_profile_name]
432
- )
433
- ).merge(creds)
434
- )
420
+ cred_file = load_aws_file(aws_credentials_file)
421
+ config_file = load_aws_file(aws_config_file)
422
+ file_creds = Smash.new.tap do |fc|
423
+ (config_file.keys + cred_file.keys).uniq.reverse.each do |k|
424
+ fc[k] = config_file.fetch(k, Smash.new).merge(
425
+ cred_file.fetch(k, Smash.new)
426
+ )
427
+ end
428
+ end
429
+ profile = creds[:aws_profile_name]
430
+ new_creds = Smash.new
431
+ while profile
432
+ new_creds = file_creds.fetch(profile, Smash.new).merge(new_creds)
433
+ profile = new_creds.delete(:source_profile)
435
434
  end
436
- if(creds[:aws_iam_instance_profile])
435
+ new_creds = file_creds.fetch(:default, Smash.new).merge(new_creds)
436
+ creds.replace(new_creds.merge(creds))
437
+ if creds[:aws_iam_instance_profile]
437
438
  self.class.const_get(:ECS_TASK_PROFILE_PATH).nil? ?
438
439
  load_instance_credentials!(creds) :
439
440
  load_ecs_credentials!(creds)
@@ -450,7 +451,7 @@ module Miasma
450
451
  skip = self.class.attributes.keys.map(&:to_s)
451
452
  creds.each do |k, v|
452
453
  k = k.to_s
453
- if(k.start_with?('aws_') && !skip.include?(k))
454
+ if k.start_with?("aws_") && !skip.include?(k)
454
455
  data[k] = v
455
456
  end
456
457
  end
@@ -465,17 +466,17 @@ module Miasma
465
466
  [
466
467
  self.class.const_get(:INSTANCE_PROFILE_HOST),
467
468
  self.class.const_get(:INSTANCE_PROFILE_PATH),
468
- ''
469
- ].join('/')
469
+ "",
470
+ ].join("/")
470
471
  ).body.to_s.strip
471
472
  data = HTTP.get(
472
473
  [
473
474
  self.class.const_get(:INSTANCE_PROFILE_HOST),
474
475
  self.class.const_get(:INSTANCE_PROFILE_PATH),
475
- role
476
- ].join('/')
476
+ role,
477
+ ].join("/")
477
478
  ).body
478
- unless(data.is_a?(Hash))
479
+ unless data.is_a?(Hash)
479
480
  begin
480
481
  data = MultiJson.load(data.to_s)
481
482
  rescue MultiJson::ParseError
@@ -483,7 +484,7 @@ module Miasma
483
484
  end
484
485
  end
485
486
  creds.merge!(extract_creds(data))
486
- unless(creds[:aws_region])
487
+ unless creds[:aws_region]
487
488
  creds[:aws_region] = get_region
488
489
  end
489
490
  true
@@ -501,10 +502,10 @@ module Miasma
501
502
  data = HTTP.get(
502
503
  [
503
504
  self.class.const_get(:ECS_TASK_PROFILE_HOST),
504
- self.class.const_get(:ECS_TASK_PROFILE_PATH)
505
+ self.class.const_get(:ECS_TASK_PROFILE_PATH),
505
506
  ].join
506
507
  ).body
507
- unless(data.is_a?(Hash))
508
+ unless data.is_a?(Hash)
508
509
  begin
509
510
  data = MultiJson.load(data.to_s)
510
511
  rescue MultiJson::ParseError
@@ -512,7 +513,7 @@ module Miasma
512
513
  end
513
514
  end
514
515
  creds.merge!(extract_creds(data))
515
- unless(creds[:aws_region])
516
+ unless creds[:aws_region]
516
517
  creds[:aws_region] = get_region
517
518
  end
518
519
  true
@@ -524,11 +525,11 @@ module Miasma
524
525
  # @return [Hash]
525
526
  def extract_creds(data)
526
527
  c = Smash.new
527
- c[:aws_access_key_id] = data['AccessKeyId']
528
- c[:aws_secret_access_key] = data['SecretAccessKey']
529
- c[:aws_sts_token] = data['Token']
530
- c[:aws_sts_token_expires] = Time.xmlschema(data['Expiration'])
531
- c[:aws_sts_role_arn] = data['RoleArn'] # used in ECS Role but not instance role
528
+ c[:aws_access_key_id] = data["AccessKeyId"]
529
+ c[:aws_secret_access_key] = data["SecretAccessKey"]
530
+ c[:aws_sts_token] = data["Token"]
531
+ c[:aws_sts_token_expires] = Time.xmlschema(data["Expiration"])
532
+ c[:aws_sts_role_arn] = data["RoleArn"] # used in ECS Role but not instance role
532
533
  c
533
534
  end
534
535
 
@@ -539,30 +540,30 @@ module Miasma
539
540
  az = HTTP.get(
540
541
  [
541
542
  self.class.const_get(:INSTANCE_PROFILE_HOST),
542
- self.class.const_get(:INSTANCE_PROFILE_AZ_PATH)
543
- ].join('/')
543
+ self.class.const_get(:INSTANCE_PROFILE_AZ_PATH),
544
+ ].join("/")
544
545
  ).body.to_s.strip
545
- az.sub!(/[a-zA-Z]+$/, '')
546
+ az.sub!(/[a-zA-Z]+$/, "")
546
547
  az
547
548
  end
548
549
 
549
550
  def sts_mfa_session!(creds)
550
- if(sts_mfa_session_update_required?(creds))
551
+ if sts_mfa_session_update_required?(creds)
551
552
  sts = Miasma::Contrib::Aws::Api::Sts.new(
552
553
  :aws_access_key_id => creds[:aws_access_key_id],
553
554
  :aws_secret_access_key => creds[:aws_secret_access_key],
554
- :aws_region => creds.fetch(:aws_sts_region, 'us-east-1'),
555
+ :aws_region => creds.fetch(:aws_sts_region, "us-east-1"),
555
556
  :aws_credentials_file => creds.fetch(
556
557
  :aws_credentials_file, aws_credentials_file
557
558
  ),
558
559
  :aws_config_file => creds.fetch(:aws_config_file, aws_config_file),
559
560
  :aws_profile_name => creds[:aws_profile_name],
560
- :aws_host => creds[:aws_sts_host]
561
+ :aws_host => creds[:aws_sts_host],
561
562
  )
562
563
  creds.merge!(
563
564
  sts.mfa_session(
564
565
  creds[:aws_sts_session_token_code],
565
- :mfa_serial => creds[:aws_sts_mfa_serial_number]
566
+ :mfa_serial => creds[:aws_sts_mfa_serial_number],
566
567
  )
567
568
  )
568
569
  end
@@ -574,22 +575,22 @@ module Miasma
574
575
  # @param creds [Hash]
575
576
  # @return [TrueClass]
576
577
  def sts_assume_role!(creds)
577
- if(sts_assume_role_update_required?(creds))
578
+ if sts_assume_role_update_required?(creds)
578
579
  sts = Miasma::Contrib::Aws::Api::Sts.new(
579
580
  :aws_access_key_id => get_credential(:access_key_id, creds),
580
581
  :aws_secret_access_key => get_credential(:secret_access_key, creds),
581
- :aws_region => creds.fetch(:aws_sts_region, 'us-east-1'),
582
+ :aws_region => creds.fetch(:aws_sts_region, "us-east-1"),
582
583
  :aws_credentials_file => creds.fetch(
583
584
  :aws_credentials_file, aws_credentials_file
584
585
  ),
585
586
  :aws_config_file => creds.fetch(:aws_config_file, aws_config_file),
586
587
  :aws_host => creds[:aws_sts_host],
587
- :aws_sts_token => creds[:aws_sts_session_token]
588
+ :aws_sts_token => creds[:aws_sts_session_token],
588
589
  )
589
590
  role_info = sts.assume_role(
590
591
  creds[:aws_sts_role_arn],
591
592
  :session_name => creds[:aws_sts_role_session_name],
592
- :external_id => creds[:aws_sts_external_id]
593
+ :external_id => creds[:aws_sts_external_id],
593
594
  )
594
595
  creds.merge!(role_info)
595
596
  end
@@ -599,38 +600,37 @@ module Miasma
599
600
  # Load configuration from the AWS configuration file
600
601
  #
601
602
  # @param file_path [String] path to configuration file
602
- # @param profile [String] name of profile to load
603
603
  # @return [Smash]
604
- def load_aws_file(file_path, profile)
605
- if(File.exist?(file_path))
606
- l_config = Smash.new.tap do |creds|
607
- key = nil
604
+ def load_aws_file(file_path)
605
+ if File.exist?(file_path)
606
+ Smash.new.tap do |creds|
607
+ key = :default
608
608
  File.readlines(file_path).each_with_index do |line, idx|
609
609
  line.strip!
610
- next if line.empty? || line.start_with?('#')
611
- if(line.start_with?('['))
612
- unless(line.end_with?(']'))
610
+ next if line.empty? || line.start_with?("#")
611
+ if line.start_with?("[")
612
+ unless line.end_with?("]")
613
613
  raise ArgumentError.new(
614
614
  "Failed to parse aws file! (#{file_path} line #{idx + 1})"
615
615
  )
616
616
  end
617
- key = line.tr('[]', '').strip.sub(/^profile /, '')
617
+ key = line.tr("[]", "").strip.sub(/^profile /, "")
618
618
  creds[key] = Smash.new
619
619
  else
620
- unless(key)
620
+ unless key
621
621
  raise ArgumentError.new(
622
622
  "Failed to parse aws file! (#{file_path} line #{idx + 1}) " \
623
- '- No section defined!'
623
+ "- No section defined!"
624
624
  )
625
625
  end
626
- line_args = line.split('=', 2).map(&:strip)
626
+ line_args = line.split("=", 2).map(&:strip)
627
627
  line_args.first.replace(
628
628
  self.class.const_get(:CONFIG_FILE_REMAP).fetch(
629
629
  line_args.first, line_args.first
630
630
  )
631
631
  )
632
- if(line_args.last.start_with?('"'))
633
- unless(line_args.last.end_with?('"'))
632
+ if line_args.last.start_with?('"')
633
+ unless line_args.last.end_with?('"')
634
634
  raise ArgumentError.new(
635
635
  "Failed to parse aws file! (#{file_path} line #{idx + 1})"
636
636
  )
@@ -647,17 +647,6 @@ module Miasma
647
647
  end
648
648
  end
649
649
  end
650
-
651
- l_profile = l_config.fetch(profile, Smash.new)
652
- l_source_profile = l_config.fetch(l_profile[:source_profile], Smash.new)
653
-
654
- l_creds = l_config.fetch(
655
- :default, Smash.new
656
- ).merge(
657
- l_source_profile
658
- ).merge(
659
- l_profile
660
- )
661
650
  else
662
651
  Smash.new
663
652
  end
@@ -665,33 +654,31 @@ module Miasma
665
654
 
666
655
  # Setup for API connections
667
656
  def connect
668
- unless(aws_host)
669
- if(euca_compat)
670
- service_name = (
671
- self.class.const_defined?(:EUCA_API_SERVICE) ?
657
+ unless aws_host
658
+ if euca_compat
659
+ service_name = (self.class.const_defined?(:EUCA_API_SERVICE) ?
672
660
  self.class::EUCA_API_SERVICE :
673
- self.class::API_SERVICE
674
- )
661
+ self.class::API_SERVICE)
675
662
  else
676
663
  service_name = self.class::API_SERVICE.downcase
677
664
  end
678
- if(euca_compat == :path)
665
+ if euca_compat == :path
679
666
  self.aws_host = [
680
667
  api_endpoint,
681
- 'services',
682
- service_name
683
- ].join('/')
684
- elsif(euca_compat == :dns && euca_dns_map[service_name])
668
+ "services",
669
+ service_name,
670
+ ].join("/")
671
+ elsif euca_compat == :dns && euca_dns_map[service_name]
685
672
  self.aws_host = [
686
673
  euca_dns_map[service_name],
687
- api_endpoint
688
- ].join('.')
674
+ api_endpoint,
675
+ ].join(".")
689
676
  else
690
677
  self.aws_host = [
691
678
  service_name,
692
679
  aws_region,
693
- api_endpoint
694
- ].join('.')
680
+ api_endpoint,
681
+ ].join(".")
695
682
  end
696
683
  end
697
684
  end
@@ -710,11 +697,11 @@ module Miasma
710
697
  #
711
698
  # @param key [String, Symbol] credential suffix
712
699
  # @return [Object]
713
- def get_credential(key, data_hash=nil)
700
+ def get_credential(key, data_hash = nil)
714
701
  data_hash = attributes if data_hash.nil?
715
- if(data_hash[:aws_sts_token])
702
+ if data_hash[:aws_sts_token]
716
703
  data_hash.fetch("aws_sts_#{key}", data_hash["aws_#{key}"])
717
- elsif(data_hash[:aws_sts_session_token])
704
+ elsif data_hash[:aws_sts_session_token]
718
705
  data_hash.fetch("aws_sts_session_#{key}", data_hash["aws_#{key}"])
719
706
  else
720
707
  data_hash["aws_#{key}"]
@@ -729,14 +716,14 @@ module Miasma
729
716
  # @return [HTTP] connection for requests (forces headers)
730
717
  def connection
731
718
  super.headers(
732
- 'Host' => aws_host,
733
- 'X-Amz-Date' => Contrib::AwsApiCore.time_iso8601
719
+ "Host" => aws_host,
720
+ "X-Amz-Date" => Contrib::AwsApiCore.time_iso8601,
734
721
  )
735
722
  end
736
723
 
737
724
  # @return [String] endpoint for request
738
725
  def endpoint
739
- "http#{'s' if ssl_enabled}://#{aws_host}"
726
+ "http#{"s" if ssl_enabled}://#{aws_host}"
740
727
  end
741
728
 
742
729
  # Override to inject signature
@@ -751,41 +738,41 @@ module Miasma
751
738
  options = options ? options.to_smash : Smash.new
752
739
  options[:headers] = Smash[connection.default_options.headers.to_a].
753
740
  merge(options.fetch(:headers, Smash.new))
754
- if(self.class::API_VERSION)
755
- if(options[:form])
756
- options.set(:form, 'Version', self.class::API_VERSION)
741
+ if self.class::API_VERSION
742
+ if options[:form]
743
+ options.set(:form, "Version", self.class::API_VERSION)
757
744
  else
758
745
  options[:params] = options.fetch(
759
746
  :params, Smash.new
760
747
  ).to_smash.deep_merge(
761
748
  Smash.new(
762
- 'Version' => self.class::API_VERSION
749
+ "Version" => self.class::API_VERSION,
763
750
  )
764
751
  )
765
752
  end
766
753
  end
767
- if(aws_sts_session_token || aws_sts_session_token_code)
768
- if(sts_mfa_session_update_required?)
754
+ if aws_sts_session_token || aws_sts_session_token_code
755
+ if sts_mfa_session_update_required?
769
756
  sts_mfa_session!(data)
770
757
  end
771
- options.set(:headers, 'X-Amz-Security-Token', aws_sts_session_token)
758
+ options.set(:headers, "X-Amz-Security-Token", aws_sts_session_token)
772
759
  end
773
- if(aws_sts_token || aws_sts_role_arn)
774
- if(sts_assume_role_update_required?)
760
+ if aws_sts_token || aws_sts_role_arn
761
+ if sts_assume_role_update_required?
775
762
  sts_assume_role!(data)
776
763
  end
777
- options.set(:headers, 'X-Amz-Security-Token', aws_sts_token)
764
+ options.set(:headers, "X-Amz-Security-Token", aws_sts_token)
778
765
  end
779
766
  signature = signer.generate(http_method, path, options)
780
767
  update_request(connection, options)
781
- options = Hash[options.map{|k, v| [k.to_sym, v] }]
768
+ options = Hash[options.map { |k, v| [k.to_sym, v] }]
782
769
  connection.auth(signature).send(http_method, dest, options)
783
770
  end
784
771
 
785
772
  # @return [TrueClass, FalseClass]
786
773
  # @note update check only applied if assuming role
787
- def sts_assume_role_update_required?(args={})
788
- if(args.fetch(:aws_sts_role_arn, attributes[:aws_sts_role_arn]))
774
+ def sts_assume_role_update_required?(args = {})
775
+ if args.fetch(:aws_sts_role_arn, attributes[:aws_sts_role_arn])
789
776
  expiry = args.fetch(:aws_sts_token_expires, attributes[:aws_sts_token_expires])
790
777
  expiry.nil? || expiry <= Time.now - 15
791
778
  else
@@ -795,9 +782,9 @@ module Miasma
795
782
 
796
783
  # @return [TrueClass, FalseClass]
797
784
  # @note update check only applied if assuming role
798
- def sts_mfa_session_update_required?(args={})
799
- if(args.fetch(:aws_sts_session_token_code,
800
- attributes[:aws_sts_session_token_code]))
785
+ def sts_mfa_session_update_required?(args = {})
786
+ if (args.fetch(:aws_sts_session_token_code,
787
+ attributes[:aws_sts_session_token_code]))
801
788
  expiry = args.fetch(
802
789
  :aws_sts_session_token_expires,
803
790
  attributes[:aws_sts_session_token_expires]
@@ -822,10 +809,10 @@ module Miasma
822
809
  # @param exception [Exception]
823
810
  # @return [TrueClass, FalseClass]
824
811
  def perform_request_retry(exception)
825
- if(exception.is_a?(Miasma::Error::ApiError))
826
- if([400, 500, 503].include?(exception.response.code))
827
- if(exception.response.code == 400)
828
- exception.response.body.to_s.downcase.include?('throttl')
812
+ if exception.is_a?(Miasma::Error::ApiError)
813
+ if [400, 500, 503].include?(exception.response.code)
814
+ if exception.response.code == 400
815
+ exception.response.body.to_s.downcase.include?("throttl")
829
816
  else
830
817
  true
831
818
  end
@@ -841,15 +828,13 @@ module Miasma
841
828
  def retryable_allowed?(*_)
842
829
  true
843
830
  end
844
-
845
831
  end
846
-
847
832
  end
848
833
  end
849
834
 
850
- Models::Compute.autoload :Aws, 'miasma/contrib/aws/compute'
851
- Models::LoadBalancer.autoload :Aws, 'miasma/contrib/aws/load_balancer'
852
- Models::AutoScale.autoload :Aws, 'miasma/contrib/aws/auto_scale'
853
- Models::Orchestration.autoload :Aws, 'miasma/contrib/aws/orchestration'
854
- Models::Storage.autoload :Aws, 'miasma/contrib/aws/storage'
835
+ Models::Compute.autoload :Aws, "miasma/contrib/aws/compute"
836
+ Models::LoadBalancer.autoload :Aws, "miasma/contrib/aws/load_balancer"
837
+ Models::AutoScale.autoload :Aws, "miasma/contrib/aws/auto_scale"
838
+ Models::Orchestration.autoload :Aws, "miasma/contrib/aws/orchestration"
839
+ Models::Storage.autoload :Aws, "miasma/contrib/aws/storage"
855
840
  end