awskeyring 1.12.0 → 1.13.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 +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +6 -0
- data/i18n/en.yml +1 -0
- data/lib/awskeyring/awsapi.rb +18 -0
- data/lib/awskeyring/version.rb +1 -1
- data/lib/awskeyring_command.rb +54 -25
- data/man/awskeyring.5 +9 -3
- 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: 77b3d983a4ed2fefb518f35a38a93070b200b7c6d6a22cb189bf3df954636c6b
|
4
|
+
data.tar.gz: '085d5f2dd6622efd844dcbb952a92030ed9cafb4e52098f96b7fee904c3a5739'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb99fad81b567e8db647ad41b7c3d56c2a42000006c5ef1f9adc9c72db3f524a043c6a0e55d17e82977b9308e242604f5fe4473ab49065698ec440d95fe09727
|
7
|
+
data.tar.gz: f39f3e192b664eab640662e0e74c3d1db37939a4048ee6990c8e1bb411f9b053b24c2dc8614b8ea5f46bc2509a1419b1f32ef5b9799fa6b8284a0930ff4056d9
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|

|
4
4
|
|
5
|
+
* 
|
5
6
|
* [](https://badge.fury.io/rb/awskeyring)
|
6
7
|
* [](https://opensource.org/licenses/MIT)
|
7
8
|
* [](https://rubygems.org/gems/awskeyring)
|
@@ -11,6 +12,11 @@
|
|
11
12
|
Awskeyring is a small tool to manage AWS account keys in the macOS Keychain. It has
|
12
13
|
grown to incorporate a lot of [features](https://github.com/tristanmorgan/awskeyring/wiki/Awskeyring-features).
|
13
14
|
|
15
|
+
## Project Status
|
16
|
+
|
17
|
+
Awskeyring is a fairly mature project so it it doesn't see frequent updates but is still being maintained.
|
18
|
+
It is tested against the version of Ruby that is shipped with the latest version of macOS, but that ruby version is dated.
|
19
|
+
|
14
20
|
## Motivation
|
15
21
|
|
16
22
|
The motivation of this application is to provide a local secure store of AWS
|
data/i18n/en.yml
CHANGED
@@ -33,6 +33,7 @@ en:
|
|
33
33
|
notoken: 'Do not use saved token.'
|
34
34
|
noremote: 'Do not validate with remote api.'
|
35
35
|
path: 'The service PATH to open.'
|
36
|
+
test: 'Generate test credentials.'
|
36
37
|
browser: 'Specify an alternative browser.'
|
37
38
|
secret: 'AWS account secret.'
|
38
39
|
unset: 'Unset environment variables.'
|
data/lib/awskeyring/awsapi.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'aws-sdk-iam'
|
4
4
|
require 'cgi'
|
5
5
|
require 'json'
|
6
|
+
require 'securerandom'
|
6
7
|
|
7
8
|
# Awskeyring Module,
|
8
9
|
# gives you an interface to access keychains and items.
|
@@ -180,6 +181,23 @@ module Awskeyring
|
|
180
181
|
}
|
181
182
|
end
|
182
183
|
|
184
|
+
# Generate test credentials for AWS
|
185
|
+
#
|
186
|
+
# @return [Hash] with the new credentials
|
187
|
+
# key The aws_access_key_id
|
188
|
+
# secret The aws_secret_access_key
|
189
|
+
# expiry expiry time
|
190
|
+
def self.gen_test_credentials(account:)
|
191
|
+
{
|
192
|
+
account: account,
|
193
|
+
key: "AKIA#{Array.new(16) { [*'A'..'Z', *'2'..'7'].sample }.join}",
|
194
|
+
secret: SecureRandom.base64(30),
|
195
|
+
token: nil,
|
196
|
+
expiry: nil,
|
197
|
+
role: nil
|
198
|
+
}
|
199
|
+
end
|
200
|
+
|
183
201
|
# Retrieves an AWS Console login url
|
184
202
|
#
|
185
203
|
# @param [String] key The aws_access_key_id
|
data/lib/awskeyring/version.rb
CHANGED
data/lib/awskeyring_command.rb
CHANGED
@@ -109,10 +109,15 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
109
109
|
desc 'env ACCOUNT', I18n.t('env_desc')
|
110
110
|
method_option :force, type: :boolean, aliases: '-f', desc: I18n.t('method_option.force'), default: false
|
111
111
|
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
|
112
|
+
method_option :test, type: :boolean, aliases: '-t', desc: I18n.t('method_option.test'), default: false
|
112
113
|
method_option :unset, type: :boolean, aliases: '-u', desc: I18n.t('method_option.unset'), default: false
|
113
114
|
# Print Env vars
|
114
115
|
def env(account = nil)
|
115
|
-
if options[:
|
116
|
+
if options[:test]
|
117
|
+
account ||= 'fakeaccount'
|
118
|
+
cred = Awskeyring::Awsapi.gen_test_credentials(account: account)
|
119
|
+
put_env_string(cred)
|
120
|
+
elsif options[:unset]
|
116
121
|
put_env_string(account: nil, key: nil, secret: nil, token: nil)
|
117
122
|
else
|
118
123
|
output_safe(options[:force])
|
@@ -129,21 +134,32 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
129
134
|
desc 'json ACCOUNT', I18n.t('json_desc')
|
130
135
|
method_option :force, type: :boolean, aliases: '-f', desc: I18n.t('method_option.force'), default: false
|
131
136
|
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
|
137
|
+
method_option :test, type: :boolean, aliases: '-t', desc: I18n.t('method_option.test'), default: false
|
132
138
|
# Print JSON for use with credential_process
|
133
|
-
def json(account) # rubocop:disable Metrics/AbcSize
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
139
|
+
def json(account) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
140
|
+
if options[:test]
|
141
|
+
cred = Awskeyring::Awsapi.gen_test_credentials(account: account)
|
142
|
+
puts Awskeyring::Awsapi.get_cred_json(
|
143
|
+
key: cred[:key],
|
144
|
+
secret: cred[:secret],
|
145
|
+
token: cred[:token],
|
146
|
+
expiry: (Time.new + Awskeyring::Awsapi::TWELVE_HOUR).iso8601
|
147
|
+
)
|
148
|
+
else
|
149
|
+
output_safe(options[:force])
|
150
|
+
account = ask_check(
|
151
|
+
existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
|
152
|
+
limited_to: Awskeyring.list_account_names
|
153
|
+
)
|
154
|
+
cred = age_check_and_get(account: account, no_token: options['no-token'])
|
155
|
+
expiry = Time.at(cred[:expiry]) unless cred[:expiry].nil?
|
156
|
+
puts Awskeyring::Awsapi.get_cred_json(
|
157
|
+
key: cred[:key],
|
158
|
+
secret: cred[:secret],
|
159
|
+
token: cred[:token],
|
160
|
+
expiry: (expiry || (Time.new + Awskeyring::Awsapi::ONE_HOUR)).iso8601
|
161
|
+
)
|
162
|
+
end
|
147
163
|
end
|
148
164
|
|
149
165
|
desc 'import ACCOUNT', I18n.t('import_desc')
|
@@ -186,8 +202,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
186
202
|
method_option 'no-bundle', type: :boolean, aliases: '-b', desc: I18n.t('method_option.nobundle'), default: false
|
187
203
|
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
|
188
204
|
# execute an external command with env set
|
189
|
-
def exec(account, *
|
190
|
-
if
|
205
|
+
def exec(account, *exec) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
206
|
+
if exec.empty?
|
191
207
|
warn I18n.t('message.exec')
|
192
208
|
exit 1
|
193
209
|
end
|
@@ -199,7 +215,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
199
215
|
env_vars = Awskeyring::Awsapi.get_env_array(cred)
|
200
216
|
unbundle if options['no-bundle']
|
201
217
|
begin
|
202
|
-
pid = Process.spawn(env_vars,
|
218
|
+
pid = Process.spawn(env_vars, exec.join(' '))
|
203
219
|
Process.wait pid
|
204
220
|
exit 1 if Process.last_status.exitstatus.positive?
|
205
221
|
rescue Errno::ENOENT => e
|
@@ -456,7 +472,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
456
472
|
|
457
473
|
comp_lines = comp_line[0..(comp_point_str.to_i)].split
|
458
474
|
|
459
|
-
comp_type, sub_cmd = comp_type(comp_lines: comp_lines, prev: prev)
|
475
|
+
comp_type, sub_cmd = comp_type(comp_lines: comp_lines, prev: prev, curr: curr)
|
460
476
|
list = fetch_auto_resp(comp_type, sub_cmd)
|
461
477
|
puts list.select { |elem| elem.start_with?(curr) }.sort!.join("\n")
|
462
478
|
end
|
@@ -473,7 +489,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
473
489
|
end
|
474
490
|
|
475
491
|
# determine the type of completion needed
|
476
|
-
def comp_type(comp_lines:, prev:)
|
492
|
+
def comp_type(comp_lines:, prev:, curr:)
|
477
493
|
sub_cmd = sub_command(comp_lines)
|
478
494
|
comp_idx = comp_lines.rindex(prev)
|
479
495
|
|
@@ -484,19 +500,19 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
484
500
|
comp_type = :browser_type
|
485
501
|
else
|
486
502
|
comp_type = :command
|
487
|
-
comp_type = param_type(comp_idx, sub_cmd) unless sub_cmd.empty?
|
503
|
+
comp_type = param_type(comp_idx, sub_cmd, curr) unless sub_cmd.empty?
|
488
504
|
end
|
489
505
|
|
490
506
|
[comp_type, sub_cmd]
|
491
507
|
end
|
492
508
|
|
493
509
|
# check params for named params or fall back to flags
|
494
|
-
def param_type(comp_idx, sub_cmd)
|
495
|
-
types = %i[opt req]
|
510
|
+
def param_type(comp_idx, sub_cmd, curr)
|
511
|
+
types = %i[opt req rest]
|
496
512
|
param_list = method(sub_cmd).parameters.select { |elem| types.include? elem[0] }
|
497
513
|
if comp_idx.zero?
|
498
514
|
:command
|
499
|
-
elsif comp_idx > param_list.length
|
515
|
+
elsif comp_idx > param_list.length || curr.start_with?('-')
|
500
516
|
:flag
|
501
517
|
else
|
502
518
|
param_list[comp_idx - 1][1]
|
@@ -515,7 +531,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
515
531
|
end
|
516
532
|
|
517
533
|
# given a type return the right list for completions
|
518
|
-
def fetch_auto_resp(comp_type, sub_cmd)
|
534
|
+
def fetch_auto_resp(comp_type, sub_cmd) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
519
535
|
case comp_type
|
520
536
|
when :command
|
521
537
|
list_commands
|
@@ -529,6 +545,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
529
545
|
Awskeyring.list_token_names
|
530
546
|
when :browser_type
|
531
547
|
Awskeyring.list_browsers
|
548
|
+
when :exec
|
549
|
+
list_exec
|
532
550
|
else
|
533
551
|
list_arguments(command: sub_cmd)
|
534
552
|
end
|
@@ -540,6 +558,17 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
540
558
|
commands.reject! { |elem| %w[autocomplete default decode].include?(elem) }
|
541
559
|
end
|
542
560
|
|
561
|
+
# list executables
|
562
|
+
def list_exec
|
563
|
+
list = []
|
564
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
565
|
+
list.concat(Dir.children(File.expand_path(path)))
|
566
|
+
rescue Errno::ENOENT
|
567
|
+
next
|
568
|
+
end
|
569
|
+
list.flatten
|
570
|
+
end
|
571
|
+
|
543
572
|
# list flags for a command
|
544
573
|
def list_arguments(command:)
|
545
574
|
options = self.class.all_commands[command].options.values
|
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" "February 2025" "" ""
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain
|
@@ -95,7 +95,10 @@ Outputs bourne shell environment exports for an ACCOUNT
|
|
95
95
|
\-n, \-\-no\-token: Do not use saved token\.
|
96
96
|
.
|
97
97
|
.br
|
98
|
-
\-
|
98
|
+
\-t, \-\-test: Generate test credentials\.
|
99
|
+
.
|
100
|
+
.br
|
101
|
+
\-u, \-\-unset: Unset environment variables\.
|
99
102
|
.
|
100
103
|
.TP
|
101
104
|
exec ACCOUNT command\.\.\.:
|
@@ -153,6 +156,9 @@ Outputs AWS CLI compatible JSON for an ACCOUNT
|
|
153
156
|
.br
|
154
157
|
\-n, \-\-no\-token: Do not use saved token\.
|
155
158
|
.
|
159
|
+
.br
|
160
|
+
\-t, \-\-test: Generate test credentials\.
|
161
|
+
.
|
156
162
|
.TP
|
157
163
|
list:
|
158
164
|
.
|
@@ -347,7 +353,7 @@ The motivation of this application is to provide a local secure store of AWS cre
|
|
347
353
|
If you believe you have found a security issue in Awskeyring, please responsibly disclose by contacting me at \fItristan\.morgan@gmail\.com\fR\. Awskeyring is a Ruby script and as such Ruby is whitelisted to access your "awskeyring" keychain\. Use a strong password and keep the unlock time short\.
|
348
354
|
.
|
349
355
|
.SH "AUTHOR"
|
350
|
-
Tristan Morgan \fItristan\.morgan@gmail\.com\fR is the maintainer of Awskeyring\.
|
356
|
+
Tristan Morgan \fItristan\.morgan@gmail\.com\fR is the maintainer and author of Awskeyring\.
|
351
357
|
.
|
352
358
|
.SH "CONTRIBUTORS"
|
353
359
|
.
|
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.13.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:
|
11
|
+
date: 2025-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-iam
|
@@ -92,9 +92,9 @@ licenses:
|
|
92
92
|
metadata:
|
93
93
|
bug_tracker_uri: https://github.com/tristanmorgan/awskeyring/issues
|
94
94
|
changelog_uri: https://github.com/tristanmorgan/awskeyring/blob/main/CHANGELOG.md
|
95
|
-
documentation_uri: https://rubydoc.info/gems/awskeyring/1.
|
95
|
+
documentation_uri: https://rubydoc.info/gems/awskeyring/1.13.0
|
96
96
|
rubygems_mfa_required: 'true'
|
97
|
-
source_code_uri: https://github.com/tristanmorgan/awskeyring/tree/v1.
|
97
|
+
source_code_uri: https://github.com/tristanmorgan/awskeyring/tree/v1.13.0
|
98
98
|
wiki_uri: https://github.com/tristanmorgan/awskeyring/wiki
|
99
99
|
post_install_message:
|
100
100
|
rdoc_options: []
|