miasma-aws 0.3.10 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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