aws_assume_role 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -11
- data/Gemfile +7 -13
- data/LICENSE.md +201 -19
- data/README.md +176 -145
- data/aws_assume_role.gemspec +35 -21
- data/bin/aws-assume-role +1 -83
- data/i18n/en.yml +106 -0
- data/lib/aws_assume_role.rb +2 -3
- data/lib/aws_assume_role/cli.rb +15 -0
- data/lib/aws_assume_role/cli/actions/abstract_action.rb +53 -0
- data/lib/aws_assume_role/cli/actions/configure_profile.rb +21 -0
- data/lib/aws_assume_role/cli/actions/configure_role_assumption.rb +19 -0
- data/lib/aws_assume_role/cli/actions/console.rb +68 -0
- data/lib/aws_assume_role/cli/actions/delete_profile.rb +20 -0
- data/lib/aws_assume_role/cli/actions/includes.rb +18 -0
- data/lib/aws_assume_role/cli/actions/list_profiles.rb +10 -0
- data/lib/aws_assume_role/cli/actions/migrate_profile.rb +18 -0
- data/lib/aws_assume_role/cli/actions/reset_environment.rb +48 -0
- data/lib/aws_assume_role/cli/actions/run.rb +34 -0
- data/lib/aws_assume_role/cli/actions/set_environment.rb +60 -0
- data/lib/aws_assume_role/cli/actions/test.rb +31 -0
- data/lib/aws_assume_role/cli/commands/configure.rb +29 -0
- data/lib/aws_assume_role/cli/commands/console.rb +17 -0
- data/lib/aws_assume_role/cli/commands/delete.rb +11 -0
- data/lib/aws_assume_role/cli/commands/environment.rb +32 -0
- data/lib/aws_assume_role/cli/commands/list.rb +10 -0
- data/lib/aws_assume_role/cli/commands/migrate.rb +11 -0
- data/lib/aws_assume_role/cli/commands/run.rb +17 -0
- data/lib/aws_assume_role/cli/commands/test.rb +18 -0
- data/lib/aws_assume_role/configuration.rb +19 -0
- data/lib/aws_assume_role/core_ext/aws-sdk/credential_provider_chain.rb +2 -0
- data/lib/aws_assume_role/core_ext/aws-sdk/includes.rb +7 -0
- data/lib/aws_assume_role/credentials/factories.rb +9 -0
- data/lib/aws_assume_role/credentials/factories/abstract_factory.rb +31 -0
- data/lib/aws_assume_role/credentials/factories/assume_role.rb +38 -0
- data/lib/aws_assume_role/credentials/factories/default_chain_provider.rb +101 -0
- data/lib/aws_assume_role/credentials/factories/environment.rb +24 -0
- data/lib/aws_assume_role/credentials/factories/includes.rb +17 -0
- data/lib/aws_assume_role/credentials/factories/instance_profile.rb +17 -0
- data/lib/aws_assume_role/credentials/factories/repository.rb +35 -0
- data/lib/aws_assume_role/credentials/factories/shared.rb +15 -0
- data/lib/aws_assume_role/credentials/factories/shared_keyring.rb +16 -0
- data/lib/aws_assume_role/credentials/factories/static.rb +16 -0
- data/lib/aws_assume_role/credentials/providers/assume_role_credentials.rb +58 -0
- data/lib/aws_assume_role/credentials/providers/includes.rb +9 -0
- data/lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb +102 -0
- data/lib/aws_assume_role/credentials/providers/shared_keyring_credentials.rb +22 -0
- data/lib/aws_assume_role/includes.rb +30 -0
- data/lib/aws_assume_role/logging.rb +16 -28
- data/lib/aws_assume_role/profile_configuration.rb +71 -0
- data/lib/aws_assume_role/runner.rb +39 -0
- data/lib/aws_assume_role/store/includes.rb +16 -0
- data/lib/aws_assume_role/store/keyring.rb +59 -0
- data/lib/aws_assume_role/store/serialization.rb +18 -0
- data/lib/aws_assume_role/store/shared_config_with_keyring.rb +175 -0
- data/lib/aws_assume_role/types.rb +30 -0
- data/lib/aws_assume_role/ui.rb +55 -0
- data/lib/aws_assume_role/vendored/aws.rb +4 -0
- data/lib/aws_assume_role/vendored/aws/README.md +2 -0
- data/lib/aws_assume_role/vendored/aws/assume_role_credentials.rb +68 -0
- data/lib/aws_assume_role/vendored/aws/includes.rb +9 -0
- data/lib/aws_assume_role/vendored/aws/refreshing_credentials.rb +60 -0
- data/lib/aws_assume_role/vendored/aws/shared_config.rb +220 -0
- data/lib/aws_assume_role/version.rb +3 -0
- metadata +264 -20
- data/.rspec +0 -2
- data/Rakefile +0 -2
- data/bin/test.rb +0 -39
- data/lib/aws_assume_role/credentials.rb +0 -92
- data/lib/aws_assume_role/profile.rb +0 -203
- data/lib/aws_assume_role/profile/assume_role.rb +0 -127
- data/lib/aws_assume_role/profile/basic.rb +0 -152
- data/lib/aws_assume_role/profile/list.rb +0 -57
@@ -1,203 +0,0 @@
|
|
1
|
-
require 'keyring'
|
2
|
-
|
3
|
-
module AWSAssumeRole
|
4
|
-
|
5
|
-
# Base Profile superclass
|
6
|
-
class Profile
|
7
|
-
|
8
|
-
include Logging
|
9
|
-
|
10
|
-
# Class methods for dispatch to individual Profile strategy
|
11
|
-
|
12
|
-
@implementations = {}
|
13
|
-
@named_profiles = {}
|
14
|
-
@config_file = '-'
|
15
|
-
|
16
|
-
class << self
|
17
|
-
|
18
|
-
attr_accessor :implementations
|
19
|
-
attr_accessor :named_profiles
|
20
|
-
attr_accessor :config_file
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.register_implementation(type, impl)
|
25
|
-
logger.info('Registering implementation ' \
|
26
|
-
"for type '#{type}': #{impl}")
|
27
|
-
AWSAssumeRole::Profile.implementations[type] = impl
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.load_profiles
|
31
|
-
Dir.glob(
|
32
|
-
File.expand_path('profile/*.rb', File.dirname(__FILE__)),
|
33
|
-
).each do |profile_class|
|
34
|
-
require profile_class
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.create(name, options)
|
39
|
-
|
40
|
-
options['type'] = 'basic' unless options.key?('type')
|
41
|
-
|
42
|
-
if implementations.key?(options['type'])
|
43
|
-
logger.info("Creating profile '#{name}' "\
|
44
|
-
"with type #{options['type']}")
|
45
|
-
i = implementations[options['type']].new(name, options)
|
46
|
-
named_profiles[name] = i
|
47
|
-
return i
|
48
|
-
end
|
49
|
-
|
50
|
-
STDERR.puts 'No implementation for profiles of type '\
|
51
|
-
"'#{options['type']}'"
|
52
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.get_by_name(name)
|
57
|
-
unless named_profiles.key?(name)
|
58
|
-
STDERR.puts "No profile '#{name}' found"
|
59
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
60
|
-
end
|
61
|
-
named_profiles[name]
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.load_config_file(config_path)
|
65
|
-
@config_file = config_path
|
66
|
-
logger.info("Loading configuration from #{config_path}")
|
67
|
-
parse_config(File.open(config_path))
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.parse_config(yaml)
|
71
|
-
|
72
|
-
require 'yaml'
|
73
|
-
|
74
|
-
profiles = YAML.load(yaml)
|
75
|
-
profiles.each do |name, options|
|
76
|
-
options['config_file'] = config_file
|
77
|
-
options['name'] = name
|
78
|
-
AWSAssumeRole::Profile.create(name, options)
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
# Superclass for Profile strategies
|
84
|
-
|
85
|
-
def set_env(prefix = '') # rubocop:disable Style/AccessorMethodName
|
86
|
-
|
87
|
-
logger.info("Setting environment with prefix '#{prefix}'")
|
88
|
-
|
89
|
-
ENV["#{prefix}AWS_ACCESS_KEY_ID"] = access_key_id
|
90
|
-
ENV["#{prefix}AWS_SECRET_ACCESS_KEY"] = secret_access_key
|
91
|
-
ENV["#{prefix}AWS_DEFAULT_REGION"] = region
|
92
|
-
|
93
|
-
return unless respond_to?(:session_token)
|
94
|
-
|
95
|
-
logger.info(':session_token available, setting environment')
|
96
|
-
ENV["#{prefix}AWS_SESSION_TOKEN"] = session_token
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
def access_key_id
|
101
|
-
raise NotImplementedError
|
102
|
-
end
|
103
|
-
|
104
|
-
def secret_access_key
|
105
|
-
raise NotImplementedError
|
106
|
-
end
|
107
|
-
|
108
|
-
def region
|
109
|
-
raise NotImplementedError
|
110
|
-
end
|
111
|
-
|
112
|
-
def sts_client
|
113
|
-
raise NotImplementedError
|
114
|
-
end
|
115
|
-
|
116
|
-
attr_reader :name
|
117
|
-
|
118
|
-
def use
|
119
|
-
raise NotImplementedError
|
120
|
-
end
|
121
|
-
|
122
|
-
def add
|
123
|
-
raise NotImplementedError
|
124
|
-
end
|
125
|
-
|
126
|
-
def remove
|
127
|
-
raise NotImplementedError
|
128
|
-
end
|
129
|
-
|
130
|
-
def token_code
|
131
|
-
puts "Enter your MFA's time-based one time password: "
|
132
|
-
token_code = STDIN.gets
|
133
|
-
token_code.chomp!
|
134
|
-
end
|
135
|
-
|
136
|
-
def keyring_key
|
137
|
-
"#{@options['config_file']}|#{@options['name']}"
|
138
|
-
end
|
139
|
-
|
140
|
-
def session(duration = 3600)
|
141
|
-
|
142
|
-
# See if we already have a non-expired session cached in this
|
143
|
-
# object.
|
144
|
-
|
145
|
-
unless @session.nil?
|
146
|
-
|
147
|
-
logger.info('Found session cached in object')
|
148
|
-
return @session unless @session.expired?
|
149
|
-
logger.info('Session expired, deleting keyring key '\
|
150
|
-
"'#{keyring_key}'")
|
151
|
-
@session.delete_from_keyring(keyring_key)
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
# See if there's a non-exipred session cached in the keyring
|
156
|
-
|
157
|
-
@session = AWSAssumeRole::Credentials.load_from_keyring(keyring_key)
|
158
|
-
|
159
|
-
unless @session.nil?
|
160
|
-
|
161
|
-
logger.info("Found session in keyring for '#{keyring_key}'")
|
162
|
-
return @session unless @session.expired?
|
163
|
-
logger.info('Session expired, deleting keyring key '\
|
164
|
-
"'#{keyring_key}'")
|
165
|
-
@session.delete_from_keyring(keyring_key)
|
166
|
-
|
167
|
-
end
|
168
|
-
|
169
|
-
begin
|
170
|
-
identity = sts_client.get_caller_identity
|
171
|
-
rescue Aws::Errors::MissingCredentialsError
|
172
|
-
STDERR.puts "No credentials found. Set one in the credentials file "\
|
173
|
-
"or environment."
|
174
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
175
|
-
end
|
176
|
-
user_name = identity.arn.split('/')[1]
|
177
|
-
mfa_arn = "arn:aws:iam::#{identity.account}:mfa/#{user_name}"
|
178
|
-
|
179
|
-
mfa_token_code = token_code
|
180
|
-
|
181
|
-
begin
|
182
|
-
session = sts_client.get_session_token(
|
183
|
-
duration_seconds: duration,
|
184
|
-
serial_number: mfa_arn,
|
185
|
-
token_code: mfa_token_code,
|
186
|
-
)
|
187
|
-
rescue Aws::STS::Errors::AccessDenied
|
188
|
-
STDERR.puts 'MultiFactorAuthentication failed with invalid MFA ' \
|
189
|
-
'one time pass code.'
|
190
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
191
|
-
end
|
192
|
-
|
193
|
-
@session = Credentials.create_from_sdk(session.credentials)
|
194
|
-
logger.info("Storing session in keyring '#{keyring_key}'")
|
195
|
-
@session.store_in_keyring(keyring_key)
|
196
|
-
|
197
|
-
@session
|
198
|
-
|
199
|
-
end
|
200
|
-
|
201
|
-
end
|
202
|
-
|
203
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
# AWSAssumeRole
|
2
|
-
module AWSAssumeRole
|
3
|
-
|
4
|
-
class Profile
|
5
|
-
|
6
|
-
# A Profile implementation for assuming roles using STS
|
7
|
-
class AssumeRole < Profile
|
8
|
-
|
9
|
-
include Logging
|
10
|
-
|
11
|
-
register_implementation('assume_role', self)
|
12
|
-
|
13
|
-
@sts_client = nil
|
14
|
-
@role = nil
|
15
|
-
@options = nil
|
16
|
-
@name = nil
|
17
|
-
|
18
|
-
def default_options
|
19
|
-
{
|
20
|
-
'parent' => 'default',
|
21
|
-
'duration' => 3600,
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize(name, options = {})
|
26
|
-
|
27
|
-
require 'aws-sdk'
|
28
|
-
|
29
|
-
@options = default_options.merge(options)
|
30
|
-
@name = name
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def sts_client
|
35
|
-
|
36
|
-
return @sts_client unless @sts_client.nil?
|
37
|
-
|
38
|
-
parent = AWSAssumeRole::Profile.get_by_name(@options['parent'])
|
39
|
-
|
40
|
-
@sts_client = Aws::STS::Client.new(
|
41
|
-
access_key_id: parent.session.access_key_id,
|
42
|
-
secret_access_key: parent.session.secret_access_key,
|
43
|
-
session_token: parent.session.session_token,
|
44
|
-
)
|
45
|
-
|
46
|
-
@sts_client
|
47
|
-
|
48
|
-
rescue Aws::Errors::MissingRegionError
|
49
|
-
|
50
|
-
STDERR.puts 'No region was given. \
|
51
|
-
Set one in the credentials file or environment'
|
52
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def role_credentials
|
57
|
-
|
58
|
-
# Check for non-expired session cached here
|
59
|
-
|
60
|
-
unless @role_credentials.nil?
|
61
|
-
|
62
|
-
return @role_credentials unless @role_credentials.expired?
|
63
|
-
@role_credentials.delete_from_keyring(keyring_key)
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
# See if here's a non-exipred session in the keyring
|
68
|
-
|
69
|
-
@role_credentials = Credentials.load_from_keyring(keyring_key)
|
70
|
-
|
71
|
-
unless @role_credentials.nil?
|
72
|
-
|
73
|
-
return @role_credentials unless @role_credentials.expired?
|
74
|
-
@role_credentials.delete_from_keyring(keyring_key)
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
role = sts_client.assume_role(
|
79
|
-
role_arn: @options['role_arn'],
|
80
|
-
role_session_name: name, # use something else?
|
81
|
-
duration_seconds: @options['duration'],
|
82
|
-
)
|
83
|
-
|
84
|
-
@role_credentials =
|
85
|
-
Credentials.create_from_sdk(role.credentials)
|
86
|
-
|
87
|
-
@role_credentials.store_in_keyring(keyring_key)
|
88
|
-
|
89
|
-
@role_credentials
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
def access_key_id
|
94
|
-
role_credentials.access_key_id
|
95
|
-
end
|
96
|
-
|
97
|
-
def secret_access_key
|
98
|
-
role_credentials.secret_access_key
|
99
|
-
end
|
100
|
-
|
101
|
-
def session_token
|
102
|
-
role_credentials.session_token
|
103
|
-
end
|
104
|
-
|
105
|
-
def region
|
106
|
-
@options['region']
|
107
|
-
end
|
108
|
-
|
109
|
-
def use
|
110
|
-
set_env if @options['set_environment']
|
111
|
-
end
|
112
|
-
|
113
|
-
def remove
|
114
|
-
Credentials.new({}).delete_from_keyring(keyring_key)
|
115
|
-
end
|
116
|
-
|
117
|
-
def add
|
118
|
-
STDERR.puts "You can't add credentials to an assume_role "\
|
119
|
-
'just basic/parent accounts.'
|
120
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
@@ -1,152 +0,0 @@
|
|
1
|
-
# AWSAssumeRole
|
2
|
-
module AWSAssumeRole
|
3
|
-
|
4
|
-
class Profile
|
5
|
-
|
6
|
-
# Profile implementation which takes credentials from either
|
7
|
-
# passed options, from the environment, or from .aws/credentials
|
8
|
-
# file (per the standard behaviour of Aws::STS::Client)
|
9
|
-
class Basic < Profile
|
10
|
-
|
11
|
-
include Logging
|
12
|
-
|
13
|
-
register_implementation('basic', self)
|
14
|
-
|
15
|
-
@sts_client = nil
|
16
|
-
@options = nil
|
17
|
-
@name = nil
|
18
|
-
|
19
|
-
def initialize(name, options = {})
|
20
|
-
|
21
|
-
require 'aws-sdk'
|
22
|
-
|
23
|
-
@options = options
|
24
|
-
@name = name
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def sts_client
|
29
|
-
logger.debug("Calling STS client")
|
30
|
-
|
31
|
-
return @sts_client unless @sts_client.nil?
|
32
|
-
|
33
|
-
if @options.key?('profile')
|
34
|
-
|
35
|
-
logger.info("Loading profile #{@options['profile']} from ~/.aws/credentials")
|
36
|
-
# Attempt to load with profile name suplied
|
37
|
-
@sts_client = Aws::STS::Client.new(
|
38
|
-
profile: @options['profile'],
|
39
|
-
)
|
40
|
-
|
41
|
-
elsif access_key_id && secret_access_key
|
42
|
-
|
43
|
-
logger.debug("Access Key: #{access_key_id}")
|
44
|
-
logger.debug("Secret Key: #{secret_access_key}")
|
45
|
-
logger.debug("Region: #{region}")
|
46
|
-
|
47
|
-
@sts_client = Aws::STS::Client.new(
|
48
|
-
access_key_id: access_key_id,
|
49
|
-
secret_access_key: secret_access_key,
|
50
|
-
region: region,
|
51
|
-
)
|
52
|
-
|
53
|
-
else
|
54
|
-
|
55
|
-
@sts_client = Aws::STS::Client.new
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
@sts_client
|
60
|
-
|
61
|
-
rescue Aws::Errors::MissingRegionError
|
62
|
-
|
63
|
-
STDERR.puts 'No region was given. \
|
64
|
-
Set one in the credentials file or environment'
|
65
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def basic_credentials
|
70
|
-
logger.debug("Loading basic credentials")
|
71
|
-
# Check for profile creds in keyring first
|
72
|
-
@basic_credentials = Credentials.load_from_keyring("#{keyring_key}|basic")
|
73
|
-
|
74
|
-
return @basic_credentials unless @basic_credentials.nil?
|
75
|
-
|
76
|
-
creds = {
|
77
|
-
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
|
78
|
-
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
|
79
|
-
}
|
80
|
-
|
81
|
-
if creds[:access_key_id].nil? or creds[:secret_access_key].nil?
|
82
|
-
STDERR.puts 'No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY ' \
|
83
|
-
'found in the environment.'
|
84
|
-
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
85
|
-
end
|
86
|
-
|
87
|
-
unless @options['region'].nil?
|
88
|
-
creds[:region] = @options['region']
|
89
|
-
else
|
90
|
-
creds[:region] = ENV['AWS_DEFAULT_REGION']
|
91
|
-
end
|
92
|
-
|
93
|
-
@basic_credentials = AWSAssumeRole::Credentials.new(creds)
|
94
|
-
|
95
|
-
@basic_credentials
|
96
|
-
end
|
97
|
-
|
98
|
-
def access_key_id
|
99
|
-
@options['access_key_id'] || basic_credentials.access_key_id
|
100
|
-
end
|
101
|
-
|
102
|
-
def secret_access_key
|
103
|
-
@options['secret_access_key'] || basic_credentials.secret_access_key
|
104
|
-
end
|
105
|
-
|
106
|
-
def region
|
107
|
-
@options['region'] || basic_credentials.region
|
108
|
-
end
|
109
|
-
|
110
|
-
def remove
|
111
|
-
Credentials.new({}).delete_from_keyring(keyring_key)
|
112
|
-
Credentials.new({}).delete_from_keyring("#{keyring_key}|basic")
|
113
|
-
end
|
114
|
-
|
115
|
-
def add
|
116
|
-
if @options['profile']
|
117
|
-
puts "WARNING: Storing credentials but a profile is specified and used for #{@name}"
|
118
|
-
end
|
119
|
-
if @options['access_key_id'] or @options['secret_access_key']
|
120
|
-
puts "WARNING: Storing credentials but they are specified in config for #{@name}"
|
121
|
-
end
|
122
|
-
|
123
|
-
@basic_credentials = Credentials.load_from_keyring("#{keyring_key}|basic")
|
124
|
-
new_creds = get_credentials
|
125
|
-
@basic_credentials.delete_from_keyring(keyring_key) unless @basic_credentials.nil?
|
126
|
-
@basic_credentials = AWSAssumeRole::Credentials.new(new_creds)
|
127
|
-
@basic_credentials.store_in_keyring("#{keyring_key}|basic")
|
128
|
-
end
|
129
|
-
|
130
|
-
def get_credentials
|
131
|
-
puts "Enter your AWS_ACCESS_KEY_ID: "
|
132
|
-
id = STDIN.gets
|
133
|
-
id.chomp!
|
134
|
-
puts "Enter your AWS_SECRET_ACCESS_KEY: "
|
135
|
-
secret = STDIN.gets
|
136
|
-
secret.chomp!
|
137
|
-
puts "Enter a AWS Region:"
|
138
|
-
region = STDIN.gets
|
139
|
-
region.chomp!
|
140
|
-
|
141
|
-
creds = {
|
142
|
-
:access_key_id => id,
|
143
|
-
:secret_access_key => secret,
|
144
|
-
:region => region,
|
145
|
-
}
|
146
|
-
creds
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|