miasma-aws 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +3 -0
- data/lib/miasma/contrib/aws/storage.rb +21 -0
- data/lib/miasma/contrib/aws.rb +79 -23
- data/lib/miasma-aws/api/iam.rb +49 -0
- data/lib/miasma-aws/api/sts.rb +41 -3
- data/lib/miasma-aws/api.rb +1 -0
- data/lib/miasma-aws/version.rb +1 -1
- data/miasma-aws.gemspec +1 -1
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9221ddb29c7683d78498567b552c6295078a97aa
|
4
|
+
data.tar.gz: e83a397c308eb038fdbaa14a0cc65da3b7da5441
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e5f23aba1e47e832362638e817d66d6763b0422453fc78a8ec3814afd43130aa0762b8326b7111657d85d4106daf4791dfd20b93f8e596ccb836f7fe9ed0ee7
|
7
|
+
data.tar.gz: eeafe49ac5867ae0f24960ad25e7cb8a173bf0e5054535b5ec40efedd4700da84fa19aa1ab3aa96656d0be37d3fa5bbe2a27481628e63a0479ef737a26055721
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# v0.3.0
|
2
|
+
* [feature] Add sts session token support (MFA #35)
|
3
|
+
* [enhancement] Load single bucket directly (remove bucket list permission requirement #33)
|
4
|
+
|
1
5
|
# v0.2.4
|
2
6
|
* [enhancement] Add aws credential file mappings for token value (#31)
|
3
7
|
* [fix] Support quoted values within aws credentials/configuration files (#31)
|
data/README.md
CHANGED
@@ -39,6 +39,9 @@ Miasma.api(
|
|
39
39
|
* `aws_sts_role_arn` - Assume role
|
40
40
|
* `aws_external_id` - Provide an external ID when assuming role
|
41
41
|
* `aws_sts_role_session_name` - Provide custom session name when assuming role
|
42
|
+
* `aws_sts_session_token` - MFA related session token
|
43
|
+
* `aws_sts_session_token_code` - Six digit code from MFA device
|
44
|
+
* `aws_sts_mfa_serial_number` - Serial number or ARN of MFA device
|
42
45
|
|
43
46
|
### S3 related attributes
|
44
47
|
|
@@ -92,6 +92,27 @@ module Miasma
|
|
92
92
|
bucket
|
93
93
|
end
|
94
94
|
|
95
|
+
# Directly fetch bucket
|
96
|
+
#
|
97
|
+
# @param ident [String] identifier
|
98
|
+
# @return [Models::Storage::Bucket, NilClass]
|
99
|
+
def bucket_get(ident)
|
100
|
+
bucket = Bucket.new(self,
|
101
|
+
:id => ident,
|
102
|
+
:name => ident
|
103
|
+
)
|
104
|
+
begin
|
105
|
+
bucket.reload
|
106
|
+
bucket
|
107
|
+
rescue Error::ApiError::RequestError => e
|
108
|
+
if(e.response.status == 404)
|
109
|
+
nil
|
110
|
+
else
|
111
|
+
raise
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
95
116
|
# Destroy bucket
|
96
117
|
#
|
97
118
|
# @param bucket [Models::Storage::Bucket]
|
data/lib/miasma/contrib/aws.rb
CHANGED
@@ -337,6 +337,9 @@ module Miasma
|
|
337
337
|
attribute :aws_sts_role_session_name, String
|
338
338
|
attribute :aws_sts_region, String
|
339
339
|
attribute :aws_sts_host, String
|
340
|
+
attribute :aws_sts_session_token, String
|
341
|
+
attribute :aws_sts_session_token_code, [String, Proc, Method]
|
342
|
+
attribute :aws_sts_mfa_serial_number, [String]
|
340
343
|
attribute :aws_credentials_file, String, :required => true, :default => File.join(Dir.home, '.aws/credentials')
|
341
344
|
attribute :aws_config_file, String, :required => true, :default => File.join(Dir.home, '.aws/config')
|
342
345
|
attribute :aws_access_key_id, String, :required => true
|
@@ -349,9 +352,6 @@ module Miasma
|
|
349
352
|
attribute :euca_compat, Symbol, :allowed_values => [:path, :dns], :coerce => lambda{|v| v.is_a?(String) ? v.to_sym : v}
|
350
353
|
attribute :euca_dns_map, Smash, :coerce => lambda{|v| v.to_smash}, :default => Smash.new
|
351
354
|
attribute :ssl_enabled, [TrueClass, FalseClass], :default => true
|
352
|
-
|
353
|
-
# @return [Contrib::AwsApiCore::SignatureV4]
|
354
|
-
attr_reader :signer
|
355
355
|
end
|
356
356
|
|
357
357
|
# AWS config file key remapping
|
@@ -360,7 +360,7 @@ module Miasma
|
|
360
360
|
'region' => 'aws_region',
|
361
361
|
'role_arn' => 'aws_sts_role_arn',
|
362
362
|
'aws_security_token' => 'aws_sts_token',
|
363
|
-
'aws_session_token' => '
|
363
|
+
'aws_session_token' => 'aws_sts_session_token'
|
364
364
|
)
|
365
365
|
)
|
366
366
|
klass.const_set(:INSTANCE_PROFILE_HOST, 'http://169.254.169.254')
|
@@ -405,9 +405,6 @@ module Miasma
|
|
405
405
|
).merge(creds)
|
406
406
|
)
|
407
407
|
end
|
408
|
-
if(creds[:aws_sts_role_arn])
|
409
|
-
sts_assume_role!(creds)
|
410
|
-
end
|
411
408
|
if(creds[:aws_iam_instance_profile])
|
412
409
|
load_instance_credentials!(creds)
|
413
410
|
end
|
@@ -472,24 +469,42 @@ module Miasma
|
|
472
469
|
true
|
473
470
|
end
|
474
471
|
|
472
|
+
def sts_mfa_session!(creds)
|
473
|
+
if(sts_mfa_session_update_required?(creds))
|
474
|
+
sts = Miasma::Contrib::Aws::Api::Sts.new(
|
475
|
+
:aws_access_key_id => creds[:aws_access_key_id],
|
476
|
+
:aws_secret_access_key => creds[:aws_secret_access_key],
|
477
|
+
:aws_region => creds.fetch(:aws_sts_region, 'us-east-1'),
|
478
|
+
:aws_credentials_file => creds.fetch(:aws_credentials_file, aws_credentials_file),
|
479
|
+
:aws_config_file => creds.fetch(:aws_config_file, aws_config_file),
|
480
|
+
:aws_profile_name => creds[:aws_profile_name],
|
481
|
+
:aws_host => creds[:aws_sts_host],
|
482
|
+
)
|
483
|
+
creds.merge!(
|
484
|
+
sts.mfa_session(
|
485
|
+
creds[:aws_sts_session_token_code],
|
486
|
+
:mfa_serial => creds[:aws_sts_mfa_serial_number]
|
487
|
+
)
|
488
|
+
)
|
489
|
+
end
|
490
|
+
true
|
491
|
+
end
|
492
|
+
|
475
493
|
# Assume requested role and replace key id and secret
|
476
494
|
#
|
477
495
|
# @param creds [Hash]
|
478
496
|
# @return [TrueClass]
|
479
497
|
def sts_assume_role!(creds)
|
480
|
-
|
481
|
-
creds[:aws_access_key_id_original] = creds[:aws_access_key_id]
|
482
|
-
creds[:aws_secret_access_key_original] = creds[:aws_secret_access_key]
|
483
|
-
end
|
484
|
-
if(sts_update_required?(creds))
|
498
|
+
if(sts_assume_role_update_required?(creds))
|
485
499
|
sts = Miasma::Contrib::Aws::Api::Sts.new(
|
486
|
-
:aws_access_key_id =>
|
487
|
-
:aws_secret_access_key =>
|
500
|
+
:aws_access_key_id => get_credential(:access_key_id, creds),
|
501
|
+
:aws_secret_access_key => get_credential(:secret_access_key, creds),
|
488
502
|
:aws_region => creds.fetch(:aws_sts_region, 'us-east-1'),
|
489
503
|
:aws_credentials_file => creds.fetch(:aws_credentials_file, aws_credentials_file),
|
490
504
|
:aws_config_file => creds.fetch(:aws_config_file, aws_config_file),
|
491
505
|
:aws_profile_name => creds[:aws_profile_name],
|
492
|
-
:aws_host => creds[:aws_sts_host]
|
506
|
+
:aws_host => creds[:aws_sts_host],
|
507
|
+
:aws_sts_token => creds[:aws_sts_session_token]
|
493
508
|
)
|
494
509
|
role_info = sts.assume_role(
|
495
510
|
creds[:aws_sts_role_arn],
|
@@ -590,11 +605,33 @@ module Miasma
|
|
590
605
|
].join('.')
|
591
606
|
end
|
592
607
|
end
|
593
|
-
|
594
|
-
|
608
|
+
end
|
609
|
+
|
610
|
+
# @return [Contrib::AwsApiCore::SignatureV4]
|
611
|
+
def signer
|
612
|
+
Contrib::AwsApiCore::SignatureV4.new(
|
613
|
+
get_credential(:access_key_id),
|
614
|
+
get_credential(:secret_access_key),
|
615
|
+
aws_region,
|
616
|
+
self.class::API_SERVICE
|
595
617
|
)
|
596
618
|
end
|
597
619
|
|
620
|
+
# Return correct credential value based on STS context
|
621
|
+
#
|
622
|
+
# @param key [String, Symbol] credential suffix
|
623
|
+
# @return [Object]
|
624
|
+
def get_credential(key, data_hash=nil)
|
625
|
+
data_hash = attributes if data_hash.nil?
|
626
|
+
if(data_hash[:aws_sts_token])
|
627
|
+
data_hash.fetch("aws_sts_#{key}", data_hash["aws_#{key}"])
|
628
|
+
elsif(data_hash[:aws_sts_session_token])
|
629
|
+
data_hash.fetch("aws_sts_session_#{key}", data_hash["aws_#{key}"])
|
630
|
+
else
|
631
|
+
data_hash["aws_#{key}"]
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
598
635
|
# @return [String] custom escape for aws compat
|
599
636
|
def uri_escape(string)
|
600
637
|
signer.safe_escape(string)
|
@@ -637,8 +674,16 @@ module Miasma
|
|
637
674
|
)
|
638
675
|
end
|
639
676
|
end
|
640
|
-
if(
|
641
|
-
|
677
|
+
if(aws_sts_session_token || aws_sts_session_token_code)
|
678
|
+
if(sts_mfa_session_update_required?)
|
679
|
+
sts_mfa_session!(data)
|
680
|
+
end
|
681
|
+
options.set(:headers, 'X-Amz-Security-Token', aws_sts_session_token)
|
682
|
+
end
|
683
|
+
if(aws_sts_token || aws_sts_role_arn)
|
684
|
+
if(sts_assume_role_update_required?)
|
685
|
+
sts_assume_role!(data)
|
686
|
+
end
|
642
687
|
options.set(:headers, 'X-Amz-Security-Token', aws_sts_token)
|
643
688
|
end
|
644
689
|
signature = signer.generate(http_method, path, options)
|
@@ -649,10 +694,21 @@ module Miasma
|
|
649
694
|
|
650
695
|
# @return [TrueClass, FalseClass]
|
651
696
|
# @note update check only applied if assuming role
|
652
|
-
def
|
653
|
-
if(args.fetch(:aws_sts_role_arn,
|
654
|
-
expiry = args.fetch(:aws_sts_token_expires,
|
655
|
-
expiry.nil? || expiry <= Time.now -
|
697
|
+
def sts_assume_role_update_required?(args={})
|
698
|
+
if(args.fetch(:aws_sts_role_arn, attributes[:aws_sts_role_arn]))
|
699
|
+
expiry = args.fetch(:aws_sts_token_expires, attributes[:aws_sts_token_expires])
|
700
|
+
expiry.nil? || expiry <= Time.now - 15
|
701
|
+
else
|
702
|
+
false
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
706
|
+
# @return [TrueClass, FalseClass]
|
707
|
+
# @note update check only applied if assuming role
|
708
|
+
def sts_mfa_session_update_required?(args={})
|
709
|
+
if(args.fetch(:aws_sts_session_token_code, attributes[:aws_sts_session_token_code]))
|
710
|
+
expiry = args.fetch(:aws_sts_session_token_expires, attributes[:aws_sts_session_token_expires])
|
711
|
+
expiry.nil? || expiry <= Time.now - 15
|
656
712
|
else
|
657
713
|
false
|
658
714
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'miasma'
|
2
|
+
|
3
|
+
module Miasma
|
4
|
+
module Contrib
|
5
|
+
module Aws
|
6
|
+
module Api
|
7
|
+
class Iam < Miasma::Types::Api
|
8
|
+
|
9
|
+
# Service name of the API
|
10
|
+
API_SERVICE = 'iam'
|
11
|
+
# Supported version of the IAM API
|
12
|
+
API_VERSION = '2010-05-08'
|
13
|
+
|
14
|
+
include Contrib::AwsApiCore::ApiCommon
|
15
|
+
include Contrib::AwsApiCore::RequestUtils
|
16
|
+
|
17
|
+
def connect
|
18
|
+
super
|
19
|
+
service_name = self.class::API_SERVICE.downcase
|
20
|
+
self.aws_host = [
|
21
|
+
service_name,
|
22
|
+
api_endpoint
|
23
|
+
].join('.')
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fetch current user information
|
27
|
+
def user_info
|
28
|
+
result = request(
|
29
|
+
:path => '/',
|
30
|
+
:params => {
|
31
|
+
'Action' => 'GetUser'
|
32
|
+
}
|
33
|
+
).get(:body, 'GetUserResponse', 'GetUserResult', 'User')
|
34
|
+
Smash.new(
|
35
|
+
:user_id => result['UserId'],
|
36
|
+
:path => result['Path'],
|
37
|
+
:username => result['UserName'],
|
38
|
+
:arn => result['Arn'],
|
39
|
+
:created => result['CreateDate'],
|
40
|
+
:password_last_used => result['PasswordLastUsed'],
|
41
|
+
:account_id => result['Arn'].split(':')[4]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/miasma-aws/api/sts.rb
CHANGED
@@ -8,12 +8,38 @@ module Miasma
|
|
8
8
|
|
9
9
|
# Service name of the API
|
10
10
|
API_SERVICE = 'sts'
|
11
|
-
# Supported version of the
|
11
|
+
# Supported version of the STS API
|
12
12
|
API_VERSION = '2011-06-15'
|
13
13
|
|
14
14
|
include Contrib::AwsApiCore::ApiCommon
|
15
15
|
include Contrib::AwsApiCore::RequestUtils
|
16
16
|
|
17
|
+
# Generate MFA session credentials
|
18
|
+
#
|
19
|
+
# @param token_code [String, Proc] Code from MFA device
|
20
|
+
# @param args [Hash]
|
21
|
+
# @option args [Integer] :duration life of session in seconds
|
22
|
+
# @option args [String] :mfa_serial MFA device identification number
|
23
|
+
# @return [Hash]
|
24
|
+
def mfa_session(token_code, args={})
|
25
|
+
req_params = Smash.new.tap do |params|
|
26
|
+
params['Action'] = 'GetSessionToken'
|
27
|
+
params['TokenCode'] = token_code.respond_to?(:call) ? token_code.call : token_code
|
28
|
+
params['DurationSeconds'] = args[:duration] if args[:duration]
|
29
|
+
params['SerialNumber'] = args[:mfa_serial].to_s.empty? ? default_mfa_serial : args[:mfa_serial]
|
30
|
+
end
|
31
|
+
result = request(
|
32
|
+
:path => '/',
|
33
|
+
:params => req_params
|
34
|
+
).get(:body, 'GetSessionTokenResponse', 'GetSessionTokenResult', 'Credentials')
|
35
|
+
Smash.new(
|
36
|
+
:aws_sts_session_token => result['SessionToken'],
|
37
|
+
:aws_sts_session_secret_access_key => result['SecretAccessKey'],
|
38
|
+
:aws_sts_session_access_key_id => result['AccessKeyId'],
|
39
|
+
:aws_sts_session_token_expires => Time.parse(result['Expiration'])
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
17
43
|
# Assume new role
|
18
44
|
#
|
19
45
|
# @param role_arn [String] IAM Role ARN
|
@@ -34,14 +60,26 @@ module Miasma
|
|
34
60
|
).get(:body, 'AssumeRoleResponse', 'AssumeRoleResult')
|
35
61
|
Smash.new(
|
36
62
|
:aws_sts_token => result.get('Credentials', 'SessionToken'),
|
37
|
-
:
|
38
|
-
:
|
63
|
+
:aws_sts_secret_access_key => result.get('Credentials', 'SecretAccessKey'),
|
64
|
+
:aws_sts_access_key_id => result.get('Credentials', 'AccessKeyId'),
|
39
65
|
:aws_sts_token_expires => Time.parse(result.get('Credentials', 'Expiration')),
|
40
66
|
:aws_sts_assumed_role_arn => result.get('AssumedRoleUser', 'Arn'),
|
41
67
|
:aws_sts_assumed_role_id => result.get('AssumedRoleUser', 'AssumedRoleId')
|
42
68
|
)
|
43
69
|
end
|
44
70
|
|
71
|
+
# @return [String]
|
72
|
+
def default_mfa_serial
|
73
|
+
user_data = Iam.new(
|
74
|
+
Smash[
|
75
|
+
[:aws_access_key_id, :aws_secret_access_key, :aws_region].map do |key|
|
76
|
+
[key, attributes[key]]
|
77
|
+
end
|
78
|
+
]
|
79
|
+
).user_info
|
80
|
+
"arn:aws:iam::#{user_data[:account_id]}:mfa/#{user_data[:username]}"
|
81
|
+
end
|
82
|
+
|
45
83
|
end
|
46
84
|
end
|
47
85
|
end
|
data/lib/miasma-aws/api.rb
CHANGED
data/lib/miasma-aws/version.rb
CHANGED
data/miasma-aws.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.description = 'Smoggy AWS API'
|
11
11
|
s.license = 'Apache 2.0'
|
12
12
|
s.require_path = 'lib'
|
13
|
-
s.
|
13
|
+
s.add_runtime_dependency 'miasma', '>= 0.2.39', '< 0.5'
|
14
14
|
s.add_development_dependency 'rake'
|
15
15
|
s.add_development_dependency 'rubocop'
|
16
16
|
s.add_development_dependency 'pry'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: miasma-aws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: miasma
|
@@ -16,14 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.2.
|
20
|
-
|
19
|
+
version: 0.2.39
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0.5'
|
23
|
+
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.2.
|
29
|
+
version: 0.2.39
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0.5'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: rake
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,6 +153,7 @@ files:
|
|
147
153
|
- README.md
|
148
154
|
- lib/miasma-aws.rb
|
149
155
|
- lib/miasma-aws/api.rb
|
156
|
+
- lib/miasma-aws/api/iam.rb
|
150
157
|
- lib/miasma-aws/api/sts.rb
|
151
158
|
- lib/miasma-aws/version.rb
|
152
159
|
- lib/miasma/contrib/aws.rb
|