awskeyring 1.8.4 → 1.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d6214486cc6877ca62ed23c40f01636f0f5bd726f7d7fdd9dd7f310ec87da84
4
- data.tar.gz: fede3a531c42bab12951bb316e8f4c0f9c3d383f60121c4993359013422fb6b4
3
+ metadata.gz: 6461179e25d74d7a488cc8dd25db6cb3f3965c177f0dd5cdc8fa440f7c0bf1e3
4
+ data.tar.gz: 30ac24cde26e0b407a89b218e61ecfd5a8f3ed2852d1da3e3339fa0ef82d17c1
5
5
  SHA512:
6
- metadata.gz: f23bed2643e3ab8f288ff690f20f540b8486a9aca792ff362696bf867009d36d874391f13b936cc1808a9908f1f16617d2fe81073e08c6620f0997835e653cb3
7
- data.tar.gz: a9732e12755c7465545bdcd59a982f446a33e42988de10158a4db977c4d8fc5a8a391d6c55c67b835fb6af749dd3e77dfef1d335b04fa6683a6df1ce0a36d227
6
+ metadata.gz: c11cee874dbaa962b252a637ebffb6623fbc0bf05cafaab9e32bbf34b8243dcf0a53e91f1ca6b3f1e4a2e65f3112981cae169334fa89817a866b8efe48a650dd
7
+ data.tar.gz: e4bbba7de171b98f88a1e3ea9232ab54c09a785712cddf979f232539ec867676bc0e33fe3b763eaf8217feecb3728aad11436326795f30560034ceeb2ac2d769
data/README.md CHANGED
@@ -62,24 +62,24 @@ more details on this config option.
62
62
  The CLI is using [Thor](http://whatisthor.com) with help provided interactively.
63
63
 
64
64
  Awskeyring commands:
65
- awskeyring --version, -v # Prints the version
66
- awskeyring add ACCOUNT # Adds an ACCOUNT to the keyring
67
- awskeyring add-role ROLE # Adds a ROLE to the keyring
68
- awskeyring console ACCOUNT # Open the AWS Console for the ACCOUNT
69
- awskeyring env ACCOUNT # Outputs bourne shell environment exports for an ACCOUNT
70
- awskeyring exec ACCOUNT command... # Execute a COMMAND with the environment set for an ACCOUNT
71
- awskeyring help [COMMAND] # Describe available commands or one specific command
72
- awskeyring import ACCOUNT # Import an ACCOUNT to the keyring from ~/.aws/credentials
73
- awskeyring initialise # Initialises a new KEYCHAIN
74
- awskeyring json ACCOUNT # Outputs AWS CLI compatible JSON for an ACCOUNT
75
- awskeyring list # Prints a list of accounts in the keyring
76
- awskeyring list-role # Prints a list of roles in the keyring
77
- awskeyring remove ACCOUNT # Removes an ACCOUNT from the keyring
78
- awskeyring remove-role ROLE # Removes a ROLE from the keyring
79
- awskeyring remove-token ACCOUNT # Removes a token for ACCOUNT from the keyring
80
- awskeyring rotate ACCOUNT # Rotate access keys for an ACCOUNT
81
- awskeyring token ACCOUNT [ROLE] [MFA] # Create an STS Token from a ROLE or an MFA code
82
- awskeyring update ACCOUNT # Updates an ACCOUNT in the keyring
65
+ awskeyring --version, -v # Prints the version
66
+ awskeyring add ACCOUNT # Adds an ACCOUNT to the keyring
67
+ awskeyring add-role ROLE # Adds a ROLE to the keyring
68
+ awskeyring console ACCOUNT # Open the AWS Console for the ACCOUNT
69
+ awskeyring env ACCOUNT # Outputs bourne shell environment exports for an ACCOUNT
70
+ awskeyring exec ACCOUNT command... # Execute a COMMAND with the environment set for an ACCOUNT
71
+ awskeyring help [COMMAND] # Describe available commands or one specific command
72
+ awskeyring import ACCOUNT # Import an ACCOUNT to the keyring from ~/.aws/credentials
73
+ awskeyring initialise # Initialises a new KEYCHAIN
74
+ awskeyring json ACCOUNT # Outputs AWS CLI compatible JSON for an ACCOUNT
75
+ awskeyring list # Prints a list of accounts in the keyring
76
+ awskeyring list-role # Prints a list of roles in the keyring
77
+ awskeyring remove ACCOUNT # Removes an ACCOUNT from the keyring
78
+ awskeyring remove-role ROLE # Removes a ROLE from the keyring
79
+ awskeyring remove-token ACCOUNT # Removes a token for ACCOUNT from the keyring
80
+ awskeyring rotate ACCOUNT # Rotate access keys for an ACCOUNT
81
+ awskeyring token ACCOUNT [ROLE] [CODE] # Create an STS Token from a ROLE or an mfa CODE
82
+ awskeyring update ACCOUNT # Updates an ACCOUNT in the keyring
83
83
 
84
84
  and autocomplete that can be installed with:
85
85
 
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
4
  require 'rubocop/rake_task'
6
5
  require 'ronn'
7
6
  require 'github_changelog_generator/task'
@@ -49,8 +48,9 @@ end
49
48
  desc 'generate manpage'
50
49
  task :ronn do
51
50
  puts 'Running Ronn...'
52
- roff_text = Ronn::Document.new('man/awskeyring.5.ronn').to_roff
53
- File.write('man/awskeyring.5', roff_text)
51
+ doc = Ronn::Document.new('man/awskeyring.5.ronn')
52
+ doc.date = Time.parse(`git show -s --format=%ad --date=short`)
53
+ File.write('man/awskeyring.5', doc.to_roff)
54
54
  puts "done\n\n"
55
55
  end
56
56
 
data/i18n/en.yml CHANGED
@@ -17,7 +17,7 @@ en:
17
17
  remove_role_desc: Removes a ROLE from the keyring
18
18
  remove_token_desc: Removes a token for ACCOUNT from the keyring
19
19
  rotate_desc: Rotate access keys for an ACCOUNT
20
- token_desc: Create an STS Token from a ROLE or an MFA code
20
+ token_desc: Create an STS Token from a ROLE or an mfa CODE
21
21
  update_desc: Updates an ACCOUNT in the keyring
22
22
  method_option:
23
23
  arn: 'AWS role arn.'
@@ -209,7 +209,7 @@ module Awskeyring
209
209
  # Get the signin token param
210
210
  private_class_method def self.token_param(session_json:)
211
211
  get_signin_token_url = AWS_SIGNIN_URL + '?Action=getSigninToken' \
212
- '&Session=' + CGI.escape(session_json)
212
+ '&Session=' + CGI.escape(session_json)
213
213
 
214
214
  uri = URI(get_signin_token_url)
215
215
  request = Net::HTTP.new(uri.host, uri.port)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sdk-core'
4
+ require 'awskeyring'
5
+
6
+ module Awskeyring
7
+ # Provide a credential provider for use as a library, eg.
8
+ # require 'awskeyring/credential_provider'
9
+ # client = Aws::STS::Client.new(
10
+ # credentials: Awskeyring::CredentialProvider.new("company-acc")
11
+ # )
12
+ class CredentialProvider
13
+ include Aws::CredentialProvider
14
+
15
+ attr_accessor :account
16
+
17
+ def initialize(account)
18
+ @account = account
19
+ end
20
+
21
+ # returns a new Aws::Credentials object
22
+ def credentials
23
+ cred = Awskeyring.get_valid_creds(account: account)
24
+ Aws::Credentials.new(cred[:key],
25
+ cred[:secret],
26
+ cred[:token])
27
+ end
28
+ end
29
+ end
@@ -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.8.4'
9
+ VERSION = '1.9.2'
10
10
  # The Gem's homepage
11
11
  HOMEPAGE = 'https://github.com/servian/awskeyring'
12
12
 
data/lib/awskeyring.rb CHANGED
@@ -52,6 +52,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
52
52
  prefs = {
53
53
  awskeyring: awskeyring,
54
54
  keyage: DEFAULT_KEY_AGE,
55
+ browser: DEFAULT_BROWSER_LIST,
55
56
  console: DEFAULT_CONSOLE_LIST
56
57
  }
57
58
  File.new(Awskeyring::PREFS_FILE, 'w').write JSON.dump(prefs)
@@ -97,6 +98,17 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
97
98
  all_items.where(account: account).first
98
99
  end
99
100
 
101
+ # return item that matches a prefix if only one.
102
+ def self.solo_select(list, prefix)
103
+ return prefix if list.include?(prefix)
104
+
105
+ list.select! { |elem| elem.start_with?(prefix) }
106
+
107
+ return list.first if list.length == 1
108
+
109
+ nil
110
+ end
111
+
100
112
  # Add an account item
101
113
  #
102
114
  # @param [String] account The account name to create
@@ -317,7 +329,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
317
329
  # @param [String] account_name the associated account name.
318
330
  def self.account_exists(account_name)
319
331
  Awskeyring::Validate.account_name(account_name)
320
- raise 'Account does not exist' unless list_account_names.include?(account_name)
332
+ raise 'Account does not exist' unless (account_name = solo_select(list_account_names, account_name))
321
333
 
322
334
  account_name
323
335
  end
@@ -347,7 +359,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
347
359
  # @param [String] role_name the associated role name.
348
360
  def self.role_exists(role_name)
349
361
  Awskeyring::Validate.role_name(role_name)
350
- raise 'Role does not exist' unless list_role_names.include?(role_name)
362
+ raise 'Role does not exist' unless (role_name = solo_select(list_role_names, role_name))
351
363
 
352
364
  role_name
353
365
  end
@@ -367,7 +379,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
367
379
  # @param [String] token_name the associated account name.
368
380
  def self.token_exists(token_name)
369
381
  Awskeyring::Validate.account_name(token_name)
370
- raise 'Token does not exist' unless list_token_names.include?(token_name)
382
+ raise 'Token does not exist' unless (token_name = solo_select(list_token_names, token_name))
371
383
 
372
384
  token_name
373
385
  end
@@ -16,7 +16,6 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
16
16
  I18n.backend.load_translations
17
17
 
18
18
  map %w[--version -v] => :__version
19
- map %w[--help -h] => :help
20
19
  map 'adr' => :add_role
21
20
  map 'assume-role' => :token
22
21
  map 'ls' => :list
@@ -125,7 +124,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
125
124
  # Print JSON for use with credential_process
126
125
  def json(account)
127
126
  account = ask_check(
128
- existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists)
127
+ existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
128
+ limited_to: Awskeyring.list_account_names
129
129
  )
130
130
  cred = age_check_and_get(account: account, no_token: options['no-token'])
131
131
  expiry = Time.at(cred[:expiry]) unless cred[:expiry].nil?
@@ -177,11 +177,15 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
177
177
  method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
178
178
  method_option 'no-bundle', type: :boolean, aliases: '-b', desc: I18n.t('method_option.nobundle'), default: false
179
179
  # execute an external command with env set
180
- def exec(account, *command)
180
+ def exec(account, *command) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
181
181
  if command.empty?
182
182
  warn I18n.t('message.exec')
183
183
  exit 1
184
184
  end
185
+ account = ask_check(
186
+ existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
187
+ limited_to: Awskeyring.list_account_names
188
+ )
185
189
  cred = age_check_and_get(account: account, no_token: options['no-token'])
186
190
  env_vars = Awskeyring::Awsapi.get_env_array(cred)
187
191
  unbundle if options['no-bundle']
@@ -335,7 +339,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
335
339
  puts I18n.t('message.upaccount', account: account)
336
340
  end
337
341
 
338
- desc 'token ACCOUNT [ROLE] [MFA]', I18n.t('token_desc')
342
+ desc 'token ACCOUNT [ROLE] [CODE]', I18n.t('token_desc')
339
343
  method_option :code, type: :string, aliases: '-c', desc: I18n.t('method_option.code')
340
344
  method_option :duration, type: :string, aliases: '-d', desc: I18n.t('method_option.duration')
341
345
  # generate a sessiopn token
@@ -430,7 +434,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
430
434
  desc "#{File.basename($PROGRAM_NAME)} CURR PREV", I18n.t('awskeyring_desc'), hide: true
431
435
  map File.basename($PROGRAM_NAME) => :autocomplete
432
436
  # autocomplete
433
- def autocomplete(curr, prev)
437
+ def autocomplete(curr, prev = nil)
438
+ curr, prev = fix_args(curr, prev)
434
439
  comp_line = ENV['COMP_LINE']
435
440
  comp_point_str = ENV['COMP_POINT']
436
441
  unless comp_line && comp_point_str
@@ -448,16 +453,16 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
448
453
 
449
454
  private
450
455
 
451
- def age_check_and_get(account:, no_token:)
452
- cred = Awskeyring.get_valid_creds(account: account, no_token: no_token)
453
-
454
- maxage = Awskeyring.key_age
455
- age = (Time.new - cred[:updated]).div Awskeyring::Awsapi::ONE_DAY
456
- warn I18n.t('message.age_check', account: account, age: age) unless age < maxage
457
-
458
- cred
456
+ # when a double dash is parsed it is dropped from the args but we need it
457
+ def fix_args(curr, prev)
458
+ if prev.nil?
459
+ [ARGV[1], ARGV[2]]
460
+ else
461
+ [curr, prev]
462
+ end
459
463
  end
460
464
 
465
+ # determine the type of completion needed
461
466
  def comp_type(comp_lines:, prev:)
462
467
  sub_cmd = sub_command(comp_lines)
463
468
  comp_idx = comp_lines.rindex(prev)
@@ -475,8 +480,10 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
475
480
  [comp_type, sub_cmd]
476
481
  end
477
482
 
483
+ # check params for named params or fall back to flags
478
484
  def param_type(comp_idx, sub_cmd)
479
- param_list = method(sub_cmd).parameters
485
+ types = %i[opt req]
486
+ param_list = method(sub_cmd).parameters.select { |elem| types.include? elem[0] }
480
487
  if comp_idx.zero?
481
488
  :command
482
489
  elsif comp_idx > param_list.length
@@ -486,18 +493,18 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
486
493
  end
487
494
  end
488
495
 
496
+ # catch the command from prefixes and aliases
489
497
  def sub_command(comp_lines)
490
- return '' if comp_lines.nil? || comp_lines.length < 2
498
+ return '' if comp_lines.length < 2
491
499
 
492
- sub_cmd = comp_lines[1].tr('-', '_')
500
+ sub_cmd = comp_lines[1]
493
501
 
494
- sub_cmds = self.class.all_commands.keys.select { |elem| elem.start_with?(sub_cmd) }
502
+ return self.class.map[sub_cmd].to_s if self.class.map.key? sub_cmd
495
503
 
496
- return sub_cmds.first if sub_cmds.length == 1
497
-
498
- self.class.map[sub_cmd].to_s
504
+ (Awskeyring.solo_select(list_commands, sub_cmd) || '').tr('-', '_')
499
505
  end
500
506
 
507
+ # given a type return the right list for completions
501
508
  def fetch_auto_resp(comp_type, sub_cmd)
502
509
  case comp_type
503
510
  when :command
@@ -517,11 +524,13 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
517
524
  end
518
525
  end
519
526
 
527
+ # list command names
520
528
  def list_commands
521
529
  commands = self.class.all_commands.keys.map { |elem| elem.tr('_', '-') }
522
530
  commands.reject! { |elem| %w[autocomplete default].include?(elem) }
523
531
  end
524
532
 
533
+ # list flags for a command
525
534
  def list_arguments(command:)
526
535
  options = self.class.all_commands[command].options.values
527
536
  exit 1 if options.empty?
@@ -530,18 +539,32 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
530
539
  options.map(&:switch_name)
531
540
  end
532
541
 
542
+ # add warning about old keys
543
+ def age_check_and_get(account:, no_token:)
544
+ cred = Awskeyring.get_valid_creds(account: account, no_token: no_token)
545
+
546
+ maxage = Awskeyring.key_age
547
+ age = (Time.new - cred[:updated]).div Awskeyring::Awsapi::ONE_DAY
548
+ warn I18n.t('message.age_check', account: account, age: age) unless age < maxage
549
+
550
+ cred
551
+ end
552
+
553
+ # print exports from map
533
554
  def put_env_string(cred)
534
555
  env_var = Awskeyring::Awsapi.get_env_array(cred)
535
556
  env_var.each { |var, value| puts "export #{var}=\"#{value}\"" }
536
557
  Awskeyring::Awsapi::AWS_ENV_VARS.each { |key| puts "unset #{key}" unless env_var.key?(key) }
537
558
  end
538
559
 
560
+ # select duration for sts token types
539
561
  def default_duration(duration, role, code)
540
562
  duration ||= Awskeyring::Awsapi::ONE_HOUR.to_s if role
541
563
  duration ||= Awskeyring::Awsapi::TWELVE_HOUR.to_s if code
542
564
  duration || Awskeyring::Awsapi::ONE_HOUR.to_s
543
565
  end
544
566
 
567
+ # ask and validate input values.
545
568
  def ask_check(existing:, message:, flags: nil, validator: nil, limited_to: nil) # rubocop:disable Metrics/MethodLength
546
569
  retries ||= 3
547
570
  begin
@@ -562,10 +585,12 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
562
585
  value
563
586
  end
564
587
 
588
+ # ask for somthinng if its missing.
565
589
  def ask_missing(existing:, message:, secure: false, optional: false, limited_to: nil)
566
590
  existing || ask(message: message, secure: secure, optional: optional, limited_to: limited_to).strip
567
591
  end
568
592
 
593
+ # ask in different ways
569
594
  def ask(message:, secure: false, optional: false, limited_to: nil)
570
595
  if secure
571
596
  Awskeyring::Input.read_secret("#{message.rjust(20)}: ")
@@ -578,6 +603,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
578
603
  end
579
604
  end
580
605
 
606
+ # undo Bundler env vars
581
607
  def unbundle
582
608
  to_delete = ENV.keys.select { |elem| elem.start_with?('BUNDLER_ORIG_') }
583
609
  bundled_env = to_delete.map { |elem| elem[('BUNDLER_ORIG_'.length)..] }
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" "May 2021" "" ""
4
+ .TH "AWSKEYRING" "5" "September 2021" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain
@@ -189,10 +189,10 @@ rotate ACCOUNT:
189
189
  Rotate access keys for an ACCOUNT
190
190
  .
191
191
  .TP
192
- token ACCOUNT [ROLE] [MFA]:
192
+ token ACCOUNT [ROLE] [CODE]:
193
193
  .
194
194
  .IP
195
- Create an STS Token from a ROLE or an MFA code
195
+ Create an STS Token from a ROLE or an mfa CODE
196
196
  .
197
197
  .br
198
198
  .
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.8.4
4
+ version: 1.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tristan Morgan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-24 00:00:00.000000000 Z
11
+ date: 2021-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-iam
@@ -82,6 +82,7 @@ files:
82
82
  - i18n/en.yml
83
83
  - lib/awskeyring.rb
84
84
  - lib/awskeyring/awsapi.rb
85
+ - lib/awskeyring/credential_provider.rb
85
86
  - lib/awskeyring/input.rb
86
87
  - lib/awskeyring/validate.rb
87
88
  - lib/awskeyring/version.rb
@@ -93,8 +94,8 @@ licenses:
93
94
  metadata:
94
95
  bug_tracker_uri: https://github.com/servian/awskeyring/issues
95
96
  changelog_uri: https://github.com/servian/awskeyring/blob/main/CHANGELOG.md
96
- documentation_uri: https://rubydoc.info/gems/awskeyring/1.8.4
97
- source_code_uri: https://github.com/servian/awskeyring/tree/v1.8.4
97
+ documentation_uri: https://rubydoc.info/gems/awskeyring/1.9.2
98
+ source_code_uri: https://github.com/servian/awskeyring/tree/v1.9.2
98
99
  wiki_uri: https://github.com/servian/awskeyring/wiki
99
100
  post_install_message:
100
101
  rdoc_options: []