awskeyring 1.3.3 → 1.4.0

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
2
  SHA256:
3
- metadata.gz: 3207b3732716f614eecc291edeaa629ebac97934e590cf7b6bf97d385cd593e5
4
- data.tar.gz: 37c0275281e5f4b2e42e8319be344aba943f4fbf81fa64e687d8cbda8e8f827f
3
+ metadata.gz: ae2606582cb2a9c079bf4ebcb6223570148954cf66fe9938c9b4d969c1312da6
4
+ data.tar.gz: d6b24f01901e6c3161e1874f9bd9d018f9b62e734d7d73f5ffaed78f0125ecb1
5
5
  SHA512:
6
- metadata.gz: 158d8f44b19e2b40a4873ecfa84f22ac2751a8470409f45ec733d614e617a00b7ad7b52786c5d3ffa1d98149120603f04e6db21c5a279fecaee55e679e10718d
7
- data.tar.gz: 0c9d3561a5c6ef181527e8ab52e858e17c5dd722403aec9df246606099c4b9bc66eb54dbacc98a770534012faf8fa52f3ebbab7c97a7fbaacd0673f5aac3f2f2
6
+ metadata.gz: d7704820e908585b67575c319e03493512917a9e5ea5db9620040402c49fbcd6466448e108949bcf32ea2d2f782e2ee8bf7e3e1bdd4e4138cb6d462c2c603635
7
+ data.tar.gz: 667e7d6d0417cda0a79c1d81680469f1ba2c7a03630bd8e7269e03f137ad669155126a927eb39542b1e9e0b07ee0f408678bb603bc77900cc7db9ff60e702c6b
@@ -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::Core::RakeTask.new(:spec) do |rspec|
26
- rspec.rspec_opts = %w[--order rand --format documentation --color]
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 'Writing manpage'
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"
@@ -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:
@@ -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
- items = all_items.all.sort do |elem_a, elem_b|
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
- items = all_items.all.sort do |elem_a, elem_b|
84
- elem_a.attributes[:label] <=> elem_b.attributes[:label]
85
- end
86
- items.select { |elem| elem.attributes[:label].start_with?(ROLE_PREFIX) }
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.now
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.
@@ -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
- def self.verify_cred(key:, secret:)
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
@@ -6,7 +6,7 @@ require 'json'
6
6
  # Version const and query of latest.
7
7
  module Awskeyring
8
8
  # The Gem's version number
9
- VERSION = '1.3.3'
9
+ VERSION = '1.4.0'
10
10
  # The Gem's homepage
11
11
  HOMEPAGE = 'https://github.com/servian/awskeyring'
12
12
 
@@ -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(:account_exists),
239
- limited_to: Awskeyring.list_account_names
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
@@ -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" "April 2020" "" ""
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
@@ -42,6 +42,10 @@ The commands are as follows:
42
42
 
43
43
  Describe available commands or one specific command
44
44
 
45
+ * import:
46
+
47
+ Import an ACCOUNT to the keyring from ~/.aws/credentials
48
+
45
49
  * initialise:
46
50
 
47
51
  Initialises a new KEYCHAIN
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.3.3
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-04 00:00:00.000000000 Z
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.3.3
101
- source_code_uri: https://github.com/servian/awskeyring/tree/v1.3.3
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: []