awskeyring 1.3.3 → 1.4.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 +8 -0
- data/README.md +1 -0
- data/Rakefile +9 -3
- data/i18n/en.yml +2 -0
- data/lib/awskeyring.rb +29 -11
- data/lib/awskeyring/awsapi.rb +23 -2
- data/lib/awskeyring/version.rb +1 -1
- data/lib/awskeyring_command.rb +44 -4
- data/man/awskeyring.5 +7 -1
- data/man/awskeyring.5.ronn +4 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae2606582cb2a9c079bf4ebcb6223570148954cf66fe9938c9b4d969c1312da6
|
4
|
+
data.tar.gz: d6b24f01901e6c3161e1874f9bd9d018f9b62e734d7d73f5ffaed78f0125ecb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7704820e908585b67575c319e03493512917a9e5ea5db9620040402c49fbcd6466448e108949bcf32ea2d2f782e2ee8bf7e3e1bdd4e4138cb6d462c2c603635
|
7
|
+
data.tar.gz: 667e7d6d0417cda0a79c1d81680469f1ba2c7a03630bd8e7269e03f137ad669155126a927eb39542b1e9e0b07ee0f408678bb603bc77900cc7db9ff60e702c6b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v1.4.0](https://github.com/servian/awskeyring/tree/v1.4.0) (2020-06-19)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/servian/awskeyring/compare/v1.3.3...v1.4.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Import Keys and Tokens from shared credentials files. [\#65](https://github.com/servian/awskeyring/pull/65) ([tristanmorgan](https://github.com/tristanmorgan))
|
10
|
+
|
3
11
|
## [v1.3.3](https://github.com/servian/awskeyring/tree/v1.3.3) (2020-06-04)
|
4
12
|
|
5
13
|
[Full Changelog](https://github.com/servian/awskeyring/compare/v1.3.2...v1.3.3)
|
data/README.md
CHANGED
@@ -65,6 +65,7 @@ The CLI is using [Thor](http://whatisthor.com) with help provided interactively.
|
|
65
65
|
awskeyring env ACCOUNT # Outputs bourne shell environment exports for an ACCOUNT
|
66
66
|
awskeyring exec ACCOUNT command... # Execute a COMMAND with the environment set for an ACCOUNT
|
67
67
|
awskeyring help [COMMAND] # Describe available commands or one specific command
|
68
|
+
awskeyring import ACCOUNT # Import an ACCOUNT to the keyring from ~/.aws/credentials
|
68
69
|
awskeyring initialise # Initialises a new KEYCHAIN
|
69
70
|
awskeyring json ACCOUNT # Outputs AWS CLI compatible JSON for an ACCOUNT
|
70
71
|
awskeyring list # Prints a list of accounts in the keyring
|
data/Rakefile
CHANGED
@@ -22,12 +22,18 @@ RuboCop::RakeTask.new do |rubocop|
|
|
22
22
|
rubocop.requires << 'rubocop-rubycw'
|
23
23
|
end
|
24
24
|
|
25
|
-
RSpec
|
26
|
-
|
25
|
+
desc 'Run RSpec code examples'
|
26
|
+
task :spec do
|
27
|
+
puts 'Running RSpec...'
|
28
|
+
require 'rspec/core'
|
29
|
+
runner = RSpec::Core::Runner
|
30
|
+
xcode = runner.run(%w[--pattern spec/**{,/*/**}/*_spec.rb --order rand --format documentation --color])
|
31
|
+
abort 'RSpec failed' if xcode.positive?
|
27
32
|
end
|
28
33
|
|
29
34
|
desc 'Check filemode bits'
|
30
35
|
task :filemode do
|
36
|
+
puts 'Running FileMode...'
|
31
37
|
files = Set.new(`git ls-files -z`.split("\x0"))
|
32
38
|
dirs = Set.new(files.map { |file| File.dirname(file) })
|
33
39
|
failure = []
|
@@ -42,7 +48,7 @@ end
|
|
42
48
|
|
43
49
|
desc 'generate manpage'
|
44
50
|
task :ronn do
|
45
|
-
puts '
|
51
|
+
puts 'Running Ronn...'
|
46
52
|
roff_text = Ronn::Document.new('man/awskeyring.5.ronn').to_roff
|
47
53
|
File.write('man/awskeyring.5', roff_text)
|
48
54
|
puts "done\n\n"
|
data/i18n/en.yml
CHANGED
@@ -14,6 +14,8 @@ en:
|
|
14
14
|
desc: Outputs bourne shell environment exports for an ACCOUNT
|
15
15
|
exec:
|
16
16
|
desc: Execute a COMMAND with the environment set for an ACCOUNT
|
17
|
+
import:
|
18
|
+
desc: Import an ACCOUNT to the keyring from ~/.aws/credentials
|
17
19
|
initialise:
|
18
20
|
desc: Initialises a new KEYCHAIN
|
19
21
|
json:
|
data/lib/awskeyring.rb
CHANGED
@@ -72,18 +72,17 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
|
|
72
72
|
|
73
73
|
# Return a list of all acount items
|
74
74
|
private_class_method def self.list_items
|
75
|
-
|
76
|
-
elem_a.attributes[:label] <=> elem_b.attributes[:label]
|
77
|
-
end
|
78
|
-
items.select { |elem| elem.attributes[:label].start_with?(ACCOUNT_PREFIX) }
|
75
|
+
all_items.all.select { |elem| elem.attributes[:label].start_with?(ACCOUNT_PREFIX) }
|
79
76
|
end
|
80
77
|
|
81
78
|
# Return a list of all role items
|
82
79
|
private_class_method def self.list_roles
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
80
|
+
all_items.all.select { |elem| elem.attributes[:label].start_with?(ROLE_PREFIX) }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return a list of all acount items
|
84
|
+
private_class_method def self.list_tokens
|
85
|
+
all_items.all.select { |elem| elem.attributes[:label].start_with?(SESSION_KEY_PREFIX) }
|
87
86
|
end
|
88
87
|
|
89
88
|
# Return all keychain items
|
@@ -175,12 +174,21 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
|
|
175
174
|
|
176
175
|
# Return a list account item names
|
177
176
|
def self.list_account_names
|
178
|
-
list_items.map { |elem| elem.attributes[:label][(ACCOUNT_PREFIX.length)..-1] }
|
177
|
+
items = list_items.map { |elem| elem.attributes[:label][(ACCOUNT_PREFIX.length)..-1] }
|
178
|
+
|
179
|
+
tokens = list_tokens.map { |elem| elem.attributes[:label][(SESSION_KEY_PREFIX.length)..-1] }
|
180
|
+
|
181
|
+
(items + tokens).uniq.sort
|
179
182
|
end
|
180
183
|
|
181
184
|
# Return a list role item names
|
182
185
|
def self.list_role_names
|
183
|
-
list_roles.map { |elem| elem.attributes[:label][(ROLE_PREFIX.length)..-1] }
|
186
|
+
list_roles.map { |elem| elem.attributes[:label][(ROLE_PREFIX.length)..-1] }.sort
|
187
|
+
end
|
188
|
+
|
189
|
+
# Return a list token item names
|
190
|
+
def self.list_token_names
|
191
|
+
list_tokens.map { |elem| elem.attributes[:label][(SESSION_KEY_PREFIX.length)..-1] }.sort
|
184
192
|
end
|
185
193
|
|
186
194
|
# Return a list role item names and arns
|
@@ -246,7 +254,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
|
|
246
254
|
# Delete session token items if expired
|
247
255
|
private_class_method def self.delete_expired(key:, token:)
|
248
256
|
expires_at = Time.at(token.attributes[:account].to_i)
|
249
|
-
if expires_at < Time.
|
257
|
+
if expires_at < Time.new
|
250
258
|
delete_pair(key: key, token: token, message: I18n.t('message.delexpired'))
|
251
259
|
key = nil
|
252
260
|
token = nil
|
@@ -347,6 +355,16 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
|
|
347
355
|
role_name
|
348
356
|
end
|
349
357
|
|
358
|
+
# Validate token exists
|
359
|
+
#
|
360
|
+
# @param [String] token_name the associated account name.
|
361
|
+
def self.token_exists(token_name)
|
362
|
+
Awskeyring::Validate.account_name(token_name)
|
363
|
+
raise 'Token does not exist' unless list_token_names.include?(token_name)
|
364
|
+
|
365
|
+
token_name
|
366
|
+
end
|
367
|
+
|
350
368
|
# Validate role arn not exists
|
351
369
|
#
|
352
370
|
# @param [String] role_arn the associated role arn.
|
data/lib/awskeyring/awsapi.rb
CHANGED
@@ -141,10 +141,11 @@ module Awskeyring
|
|
141
141
|
#
|
142
142
|
# @param [String] key The aws_access_key_id
|
143
143
|
# @param [String] secret The aws_secret_access_key
|
144
|
-
|
144
|
+
# @param [String] token The aws_session_token
|
145
|
+
def self.verify_cred(key:, secret:, token:)
|
145
146
|
begin
|
146
147
|
ENV['AWS_DEFAULT_REGION'] = 'us-east-1' unless region
|
147
|
-
sts = Aws::STS::Client.new(access_key_id: key, secret_access_key: secret)
|
148
|
+
sts = Aws::STS::Client.new(access_key_id: key, secret_access_key: secret, session_token: token)
|
148
149
|
sts.get_caller_identity
|
149
150
|
rescue Aws::Errors::ServiceError => e
|
150
151
|
warn e.to_s
|
@@ -153,6 +154,26 @@ module Awskeyring
|
|
153
154
|
true
|
154
155
|
end
|
155
156
|
|
157
|
+
# Retrieve credentials from the AWS Credentials file
|
158
|
+
#
|
159
|
+
# @param [String] account the profile name wanted
|
160
|
+
# @return [Hash] with the new credentials
|
161
|
+
# key The aws_access_key_id
|
162
|
+
# secret The aws_secret_access_key
|
163
|
+
# token The aws_session_token
|
164
|
+
# expiry expiry time
|
165
|
+
def self.get_credentials_from_file(account:)
|
166
|
+
creds = Aws::SharedCredentials.new(profile_name: account)
|
167
|
+
{
|
168
|
+
account: account,
|
169
|
+
key: creds.credentials.access_key_id,
|
170
|
+
secret: creds.credentials.secret_access_key,
|
171
|
+
token: creds.credentials.session_token,
|
172
|
+
expiry: Time.new + TWELVE_HOUR,
|
173
|
+
role: nil
|
174
|
+
}
|
175
|
+
end
|
176
|
+
|
156
177
|
# Retrieves an AWS Console login url
|
157
178
|
#
|
158
179
|
# @param [String] key The aws_access_key_id
|
data/lib/awskeyring/version.rb
CHANGED
data/lib/awskeyring_command.rb
CHANGED
@@ -122,6 +122,42 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
122
122
|
)
|
123
123
|
end
|
124
124
|
|
125
|
+
desc 'import ACCOUNT', I18n.t('import.desc')
|
126
|
+
method_option 'no-remote', type: :boolean, aliases: '-r', desc: I18n.t('method_option.noremote'), default: false
|
127
|
+
# Import an Account
|
128
|
+
def import(account = nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
129
|
+
account = ask_check(
|
130
|
+
existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_not_exists)
|
131
|
+
)
|
132
|
+
new_creds = Awskeyring::Awsapi.get_credentials_from_file(account: account)
|
133
|
+
unless options['no-remote']
|
134
|
+
Awskeyring::Awsapi.verify_cred(
|
135
|
+
key: new_creds[:key],
|
136
|
+
secret: new_creds[:secret],
|
137
|
+
token: new_creds[:token]
|
138
|
+
)
|
139
|
+
end
|
140
|
+
if new_creds[:token].nil?
|
141
|
+
Awskeyring.add_account(
|
142
|
+
account: new_creds[:account],
|
143
|
+
key: new_creds[:key],
|
144
|
+
secret: new_creds[:secret],
|
145
|
+
mfa: ''
|
146
|
+
)
|
147
|
+
puts I18n.t('message.addaccount', account: account)
|
148
|
+
else
|
149
|
+
Awskeyring.add_token(
|
150
|
+
account: new_creds[:account],
|
151
|
+
key: new_creds[:key],
|
152
|
+
secret: new_creds[:secret],
|
153
|
+
token: new_creds[:token],
|
154
|
+
expiry: new_creds[:expiry].to_i.to_s,
|
155
|
+
role: nil
|
156
|
+
)
|
157
|
+
puts I18n.t('message.addtoken', account: account, time: Time.at(new_creds[:expiry].to_i))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
125
161
|
desc 'exec ACCOUNT command...', I18n.t('exec.desc')
|
126
162
|
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
|
127
163
|
# execute an external command with env set
|
@@ -163,7 +199,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
163
199
|
existing: options[:mfa], message: I18n.t('message.mfa'),
|
164
200
|
flags: 'optional', validator: Awskeyring::Validate.method(:mfa_arn)
|
165
201
|
)
|
166
|
-
Awskeyring::Awsapi.verify_cred(key: key, secret: secret) unless options['no-remote']
|
202
|
+
Awskeyring::Awsapi.verify_cred(key: key, secret: secret, token: nil) unless options['no-remote']
|
167
203
|
Awskeyring.add_account(
|
168
204
|
account: account,
|
169
205
|
key: key,
|
@@ -235,8 +271,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
235
271
|
# remove a session token
|
236
272
|
def remove_token(account = nil)
|
237
273
|
account = ask_check(
|
238
|
-
existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:
|
239
|
-
limited_to: Awskeyring.
|
274
|
+
existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:token_exists),
|
275
|
+
limited_to: Awskeyring.list_token_names
|
240
276
|
)
|
241
277
|
Awskeyring.delete_token(account: account, message: I18n.t('message.deltoken', account: account))
|
242
278
|
end
|
@@ -415,6 +451,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
415
451
|
comp_len = 2
|
416
452
|
when '--path', '-p'
|
417
453
|
comp_len = 4
|
454
|
+
when 'remove-token', 'rmt'
|
455
|
+
comp_len = 5
|
418
456
|
end
|
419
457
|
|
420
458
|
[curr, comp_len, sub_cmd]
|
@@ -430,7 +468,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
430
468
|
self.class.map[sub_cmd].to_s
|
431
469
|
end
|
432
470
|
|
433
|
-
def print_auto_resp(curr, len, sub_cmd)
|
471
|
+
def print_auto_resp(curr, len, sub_cmd) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
434
472
|
list = []
|
435
473
|
case len
|
436
474
|
when 0
|
@@ -443,6 +481,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
443
481
|
list = list_arguments(command: sub_cmd)
|
444
482
|
when 4
|
445
483
|
list = Awskeyring.list_console_path
|
484
|
+
when 5
|
485
|
+
list = Awskeyring.list_token_names
|
446
486
|
else
|
447
487
|
exit 1
|
448
488
|
end
|
data/man/awskeyring.5
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
.\" generated with Ronn/v0.7.3
|
2
2
|
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
3
3
|
.
|
4
|
-
.TH "AWSKEYRING" "5" "
|
4
|
+
.TH "AWSKEYRING" "5" "June 2020" "" ""
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain
|
@@ -61,6 +61,12 @@ help [COMMAND]:
|
|
61
61
|
Describe available commands or one specific command
|
62
62
|
.
|
63
63
|
.TP
|
64
|
+
import:
|
65
|
+
.
|
66
|
+
.IP
|
67
|
+
Import an ACCOUNT to the keyring from ~/\.aws/credentials
|
68
|
+
.
|
69
|
+
.TP
|
64
70
|
initialise:
|
65
71
|
.
|
66
72
|
.IP
|
data/man/awskeyring.5.ronn
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: awskeyring
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tristan Morgan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-iam
|
@@ -97,8 +97,8 @@ licenses:
|
|
97
97
|
metadata:
|
98
98
|
bug_tracker_uri: https://github.com/servian/awskeyring/issues
|
99
99
|
changelog_uri: https://github.com/servian/awskeyring/blob/master/CHANGELOG.md
|
100
|
-
documentation_uri: https://rubydoc.info/gems/awskeyring/1.
|
101
|
-
source_code_uri: https://github.com/servian/awskeyring/tree/v1.
|
100
|
+
documentation_uri: https://rubydoc.info/gems/awskeyring/1.4.0
|
101
|
+
source_code_uri: https://github.com/servian/awskeyring/tree/v1.4.0
|
102
102
|
wiki_uri: https://github.com/servian/awskeyring/wiki
|
103
103
|
post_install_message:
|
104
104
|
rdoc_options: []
|