aws_assume_role 0.0.2 → 0.0.3
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 +4 -4
- data/README.md +64 -2
- data/aws_assume_role.gemspec +1 -1
- data/bin/aws-assume-role +25 -7
- data/lib/aws_assume_role/credentials.rb +5 -1
- data/lib/aws_assume_role/profile/assume_role.rb +10 -0
- data/lib/aws_assume_role/profile/basic.rb +84 -24
- data/lib/aws_assume_role/profile.rb +26 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55cb1bdbca27ae7dfaf53948e1ad746a66afcc25
|
4
|
+
data.tar.gz: 43b7ce33d786b7ebfabbedb921b2c9b3a5f28cf1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee94a33205511ab48a1c1f0e458ef98a20267b496cc556fd5cc35d87dbb4311d0d305374839348966e5b981ca29dee5ab0848ffa344215f5e20abc4ae864c815
|
7
|
+
data.tar.gz: 636303eb8f232061473a6d3de6a5809cc8eea20f3579c2f0eef8cd2e4964e08c569cce83c7b2fe05014c0980e76926038c67a998d7a10fc0201c5194b8ccd194
|
data/README.md
CHANGED
@@ -1,8 +1,35 @@
|
|
1
1
|
# aws-assume-role
|
2
2
|
|
3
3
|
This will get role credentials for you, managing 2FA devices, and set those
|
4
|
-
credentials in
|
5
|
-
or OSX Keychain so they are not
|
4
|
+
credentials in environment variables then execute a provided command. It stores
|
5
|
+
the fetched credentials in Gnome Keyring or OSX Keychain so they are not
|
6
|
+
readable from disk.
|
7
|
+
|
8
|
+
### Why?
|
9
|
+
|
10
|
+
This keeps your credentials safe in the keystore, and they are set as
|
11
|
+
environment variables for the duration and context of the executing command.
|
12
|
+
This helps prevent credential leaking and theft, and means they aren't stored on
|
13
|
+
disk as unencrypted files.
|
14
|
+
|
15
|
+
It allows easy credential management and roll assumption with a 2FA/MFA device.
|
16
|
+
|
17
|
+
For security and account management purposes we don't want to be managing users
|
18
|
+
in multiple accounts, just centrally then allowing them to assume roles in
|
19
|
+
other accounts.
|
20
|
+
|
21
|
+
###
|
22
|
+
|
23
|
+
Assumptions:
|
24
|
+
|
25
|
+
- You have a parent/master account which you authenticate against with a 2FA
|
26
|
+
device.
|
27
|
+
- You then assume a role in another account.
|
28
|
+
|
29
|
+
This is easy to achieve in a web console, but you probably want to use tools
|
30
|
+
like Terraform of AWS Cli. This makes using those tools easy, without having to
|
31
|
+
constantly fetch and manage credentials for assumed roles, or provide
|
32
|
+
users/access keys for each account.
|
6
33
|
|
7
34
|
## Install
|
8
35
|
|
@@ -83,6 +110,31 @@ xx:
|
|
83
110
|
|
84
111
|
## How to use?
|
85
112
|
|
113
|
+
You need a key and secret for each `basic` role (a `parent`). You can set this
|
114
|
+
in the environment variable or in the `~/.aws/credentials` file.
|
115
|
+
|
116
|
+
It is recommended that you set this in the environment variable, the first time
|
117
|
+
aws-assume-role runs it will place these values in the keystore so they are
|
118
|
+
safe.
|
119
|
+
|
120
|
+
### Add the basic/profile credentials to keystore
|
121
|
+
|
122
|
+
You can add the credentials that the system will use to assume roles to the
|
123
|
+
keystore. This is the recommended way of using `aws-assume-role`.
|
124
|
+
|
125
|
+
To add(or update) credentials use:
|
126
|
+
|
127
|
+
```shell
|
128
|
+
$ aws-assume-role --profile scalefactory --add
|
129
|
+
Enter your AWS_ACCESS_KEY_ID:
|
130
|
+
1234567890010
|
131
|
+
Enter your AWS_SECRET_ACCESS_KEY:
|
132
|
+
abcdefghijklmnopqrstuvwzyx1
|
133
|
+
Enter a AWS Region:
|
134
|
+
eu-west-1
|
135
|
+
|
136
|
+
```
|
137
|
+
|
86
138
|
### In Environment variable
|
87
139
|
|
88
140
|
```
|
@@ -141,3 +193,13 @@ aws-assume-role --profile yy_mgmt -- aws ec2 describe-instances --query "Reserva
|
|
141
193
|
10.254.0.10
|
142
194
|
10.254.4.5
|
143
195
|
```
|
196
|
+
|
197
|
+
|
198
|
+
## Deleting keystore values
|
199
|
+
|
200
|
+
Maybe you have a new keypair?
|
201
|
+
|
202
|
+
```
|
203
|
+
aws-assume-role --profile yy_mgmt --delete
|
204
|
+
aws-assume-role --profile scalefactory --delete
|
205
|
+
```
|
data/aws_assume_role.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'aws_assume_role'
|
7
|
-
spec.version = '0.0.
|
7
|
+
spec.version = '0.0.3'
|
8
8
|
spec.authors = ['Jon Topper', 'Jack Thomas']
|
9
9
|
spec.email = ['jon@scalefactory.com', 'jack@scalefactory.com']
|
10
10
|
|
data/bin/aws-assume-role
CHANGED
@@ -15,13 +15,25 @@ optparse = OptionParser.new do |opts|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
options[:profile] = false
|
18
|
-
opts.on('--profile name', 'Load the credentials for a profile into AWS ' \
|
19
|
-
'environment variables.
|
18
|
+
opts.on('-p', '--profile name', 'Load the credentials for a profile into AWS ' \
|
19
|
+
'environment variables.') do |c|
|
20
20
|
options[:profile] = c
|
21
21
|
end
|
22
22
|
|
23
|
+
options[:add] = false
|
24
|
+
opts.on('-a', '--add', 'Add basic/parent account credentials to keystore' \
|
25
|
+
'environment variables. Must provide a profile name') do |c|
|
26
|
+
options[:add] = c
|
27
|
+
end
|
28
|
+
|
29
|
+
options[:delete] = false
|
30
|
+
opts.on('-d', '--delete', 'Delete credentials from keystore. Must ' \
|
31
|
+
'provide a profile name.') do
|
32
|
+
options[:delete] = true
|
33
|
+
end
|
34
|
+
|
23
35
|
options[:debug] = false
|
24
|
-
opts.on('
|
36
|
+
opts.on('--debug', 'Enable debugging') do
|
25
37
|
options[:debug] = true
|
26
38
|
end
|
27
39
|
|
@@ -45,14 +57,20 @@ begin
|
|
45
57
|
AWSAssumeRole::Profile.load_profiles
|
46
58
|
AWSAssumeRole::Profile.load_config_file(options[:config])
|
47
59
|
rescue Errno::ENOENT
|
48
|
-
puts "No config file at options[:config]. Please create one!"
|
49
|
-
exit 1
|
60
|
+
STDERR.puts "No config file at options[:config]. Please create one!"
|
61
|
+
exit -1 # rubocop:disable Lint/AmbiguousOperator
|
50
62
|
end
|
51
63
|
|
52
|
-
|
53
64
|
if options[:profile] != false
|
54
65
|
profile = AWSAssumeRole::Profile.get_by_name(options[:profile] )
|
55
|
-
|
66
|
+
|
67
|
+
if options[:delete]
|
68
|
+
profile.remove
|
69
|
+
elsif options[:add]
|
70
|
+
profile.add
|
71
|
+
else
|
72
|
+
profile.use
|
73
|
+
end
|
56
74
|
|
57
75
|
if options[:verbose]
|
58
76
|
system('env | grep "AWS" | sort')
|
@@ -29,7 +29,7 @@ module AWSAssumeRole
|
|
29
29
|
return nil
|
30
30
|
end
|
31
31
|
|
32
|
-
hash[:expiration] = Time.parse(hash[:expiration])
|
32
|
+
hash[:expiration] = Time.parse(hash[:expiration]) unless hash[:expiration].nil?
|
33
33
|
|
34
34
|
logger.debug("Loaded #{hash}")
|
35
35
|
AWSAssumeRole::Credentials.new(hash)
|
@@ -65,6 +65,10 @@ module AWSAssumeRole
|
|
65
65
|
@credentials[:expiration]
|
66
66
|
end
|
67
67
|
|
68
|
+
def region
|
69
|
+
@credentials[:region]
|
70
|
+
end
|
71
|
+
|
68
72
|
def store_in_keyring(key)
|
69
73
|
keyring = Keyring.new
|
70
74
|
logger.debug("Keyring: store '#{key}' with #{@credentials.to_json}")
|
@@ -110,6 +110,16 @@ module AWSAssumeRole
|
|
110
110
|
set_env if @options['set_environment']
|
111
111
|
end
|
112
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
|
+
|
113
123
|
end
|
114
124
|
|
115
125
|
end
|
@@ -26,30 +26,11 @@ module AWSAssumeRole
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def sts_client
|
29
|
+
logger.debug("Calling STS client")
|
29
30
|
|
30
31
|
return @sts_client unless @sts_client.nil?
|
31
32
|
|
32
|
-
if @options.key?('
|
33
|
-
@options.key?('secret_access_key')
|
34
|
-
|
35
|
-
if @options.key?('region')
|
36
|
-
|
37
|
-
@sts_client = Aws::STS::Client.new(
|
38
|
-
access_key_id: @options['access_key_id'],
|
39
|
-
secret_access_key: @options['secret_access_key'],
|
40
|
-
region: @options['region'],
|
41
|
-
)
|
42
|
-
|
43
|
-
else
|
44
|
-
|
45
|
-
@sts_client = Aws::STS::Client.new(
|
46
|
-
access_key_id: @options['access_key_id'],
|
47
|
-
secret_access_key: @options['secret_access_key'],
|
48
|
-
)
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
elsif @options.key?('profile')
|
33
|
+
if @options.key?('profile')
|
53
34
|
|
54
35
|
logger.info("Loading profile #{@options['profile']} from ~/.aws/credentials")
|
55
36
|
# Attempt to load with profile name suplied
|
@@ -57,6 +38,18 @@ module AWSAssumeRole
|
|
57
38
|
profile: @options['profile'],
|
58
39
|
)
|
59
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
|
+
|
60
53
|
else
|
61
54
|
|
62
55
|
@sts_client = Aws::STS::Client.new
|
@@ -73,18 +66,85 @@ module AWSAssumeRole
|
|
73
66
|
|
74
67
|
end
|
75
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
|
+
|
76
98
|
def access_key_id
|
77
|
-
@options['access_key_id']
|
99
|
+
@options['access_key_id'] || basic_credentials.access_key_id
|
78
100
|
end
|
79
101
|
|
80
102
|
def secret_access_key
|
81
|
-
@options['secret_access_key']
|
103
|
+
@options['secret_access_key'] || basic_credentials.secret_access_key
|
82
104
|
end
|
83
105
|
|
84
106
|
def region
|
85
|
-
@options['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")
|
86
113
|
end
|
87
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
|
88
148
|
end
|
89
149
|
|
90
150
|
end
|
@@ -119,6 +119,14 @@ module AWSAssumeRole
|
|
119
119
|
raise NotImplementedError
|
120
120
|
end
|
121
121
|
|
122
|
+
def add
|
123
|
+
raise NotImplementedError
|
124
|
+
end
|
125
|
+
|
126
|
+
def remove
|
127
|
+
raise NotImplementedError
|
128
|
+
end
|
129
|
+
|
122
130
|
def token_code
|
123
131
|
puts "Enter your MFA's time-based one time password: "
|
124
132
|
token_code = STDIN.gets
|
@@ -158,17 +166,29 @@ module AWSAssumeRole
|
|
158
166
|
|
159
167
|
end
|
160
168
|
|
161
|
-
|
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
|
162
176
|
user_name = identity.arn.split('/')[1]
|
163
177
|
mfa_arn = "arn:aws:iam::#{identity.account}:mfa/#{user_name}"
|
164
178
|
|
165
179
|
mfa_token_code = token_code
|
166
180
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
172
192
|
|
173
193
|
@session = Credentials.create_from_sdk(session.credentials)
|
174
194
|
logger.info("Storing session in keyring '#{keyring_key}'")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws_assume_role
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Topper
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-12-
|
12
|
+
date: 2016-12-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|