aws-keychain-util 0.0.8 → 0.0.9
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.
- data/README.md +36 -1
- data/aws-keychain-util.gemspec +1 -1
- data/bin/aws-creds +82 -6
- metadata +2 -2
data/README.md
CHANGED
@@ -31,7 +31,9 @@ To add an item to your aws keychain:
|
|
31
31
|
$ aws-creds add
|
32
32
|
|
33
33
|
This will prompt for a friendly name, the access key id,
|
34
|
-
and the secret access key.
|
34
|
+
and the secret access key. This also prompts for an optional
|
35
|
+
MFA arn, which is necessary if you're going to use multifactor
|
36
|
+
auth with AWS.
|
35
37
|
|
36
38
|
To list items in the keychain:
|
37
39
|
|
@@ -46,11 +48,44 @@ set in the environment:
|
|
46
48
|
|
47
49
|
$ aws-creds shell <name>
|
48
50
|
|
51
|
+
To emit the (bourne shell style) environment variable exports that
|
52
|
+
you can source into your shell:
|
53
|
+
|
54
|
+
$ aws-creds env <name>
|
55
|
+
|
56
|
+
To always load the given environment in your shell, add the following to
|
57
|
+
your .bashrc or .zshrc
|
58
|
+
|
59
|
+
source `aws-creds env <name>`
|
60
|
+
|
49
61
|
To automatically grab AWS credentials from your keychain when using
|
50
62
|
the aws-sdk gem, add the following code:
|
51
63
|
|
52
64
|
AWS.config(:credential_provider => AwsKeychainUtil::CredentialProvider.new('<name>', 'keychain name'))
|
53
65
|
|
66
|
+
## AWS Multi-Factor Authentication (MFA)
|
67
|
+
|
68
|
+
To increase AWS security, it's possible to use MFA (multi-factor) authentication with the amazon APIs.
|
69
|
+
Managing temporary credentials is a serious challenge, as by definition the credentials expire after a
|
70
|
+
fixed period of time.
|
71
|
+
|
72
|
+
You then need to associate a multifactor authentication device with the IAM user.
|
73
|
+
[Amazon Directions for MFA Setup](http://docs.aws.amazon.com/IAM/latest/UserGuide/GenerateMFAConfig.html)
|
74
|
+
|
75
|
+
Configuring MFA into your IAM policies for API access is a complex process, the
|
76
|
+
documentation for which is [Here](http://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html#ExampleMFAforResource).
|
77
|
+
|
78
|
+
In order to do a multifactor authentication, you need to run:
|
79
|
+
|
80
|
+
$ aws-creds mfa <name> <code>
|
81
|
+
|
82
|
+
Where `<code>` is the numeric code on your multifactor auth device. Then you just need to either open a
|
83
|
+
fresh shell for the `<name>` key or re-source your environment.
|
84
|
+
|
85
|
+
The tool also tracks mfa expiration, and automatically removes expired tokens when you open a new shell
|
86
|
+
or source your env.
|
87
|
+
|
88
|
+
|
54
89
|
## Security
|
55
90
|
|
56
91
|
Unfortunately, when Keychain whitelists either the `aws-creds` script
|
data/aws-keychain-util.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "aws-keychain-util"
|
7
|
-
gem.version = '0.0.
|
7
|
+
gem.version = '0.0.9'
|
8
8
|
gem.authors = ["Zach Wily"]
|
9
9
|
gem.email = ["zach@zwily.com"]
|
10
10
|
gem.description = %q{Helps manage a keychain of AWS credentials on OS X.}
|
data/bin/aws-creds
CHANGED
@@ -9,6 +9,7 @@ require 'highline'
|
|
9
9
|
require 'keychain'
|
10
10
|
require 'json'
|
11
11
|
require 'aws-keychain-util'
|
12
|
+
require 'aws'
|
12
13
|
|
13
14
|
def ask(question)
|
14
15
|
HighLine.new.ask(question)
|
@@ -43,12 +44,31 @@ end
|
|
43
44
|
|
44
45
|
def get_item_from_args_for_command(command)
|
45
46
|
name = get_name_from_args_for_command(command)
|
47
|
+
item_mfa = get_item("#{name} mfa")
|
48
|
+
item_token = get_item("#{name} token")
|
49
|
+
if item_mfa
|
50
|
+
if item_mfa.attributes[:comment]
|
51
|
+
expires_at = Time.at(item_mfa.attributes[:comment].to_i)
|
52
|
+
if expires_at < Time.now
|
53
|
+
puts "# Removing expired STS credentials"
|
54
|
+
item_token.delete
|
55
|
+
item_token = nil
|
56
|
+
item_mfa.delete
|
57
|
+
item_mfa = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if item_mfa and item_token
|
62
|
+
puts "# Using temporary STS credentials"
|
63
|
+
return item_mfa, item_token
|
64
|
+
end
|
65
|
+
|
46
66
|
item = get_item(name)
|
47
67
|
unless item
|
48
68
|
puts "Could not find item with name #{name}"
|
49
69
|
exit 1
|
50
70
|
end
|
51
|
-
item
|
71
|
+
return item, nil
|
52
72
|
end
|
53
73
|
|
54
74
|
command = ARGV.shift
|
@@ -91,39 +111,95 @@ when 'add'
|
|
91
111
|
name = ask(" account name: ")
|
92
112
|
account = ask(" access key id: ")
|
93
113
|
password = ask_secure(" secret_access_key: ")
|
114
|
+
arn = ask(" mfa arn: ")
|
94
115
|
|
95
116
|
item = keychain.generic_passwords.create(
|
96
117
|
:label => name,
|
97
118
|
:account => account,
|
98
|
-
:password => password
|
119
|
+
:password => password,
|
120
|
+
:comment => arn
|
99
121
|
)
|
100
122
|
|
101
123
|
when 'cat'
|
102
|
-
item = get_item_from_args_for_command('cat')
|
124
|
+
item, token = get_item_from_args_for_command('cat')
|
103
125
|
puts "AWS_ACCESS_KEY_ID=#{item.attributes[:account]}"
|
104
126
|
puts "AWS_SECRET_ACCESS_KEY=#{item.password}"
|
127
|
+
if token
|
128
|
+
puts "AWS_SECURITY_TOKEN=#{token.password}"
|
129
|
+
end
|
105
130
|
|
106
131
|
when 'rm'
|
107
|
-
item = get_item_from_args_for_command('rm')
|
132
|
+
item, token = get_item_from_args_for_command('rm')
|
108
133
|
item.delete
|
109
134
|
|
135
|
+
when 'mfa'
|
136
|
+
keychain = load_keychain
|
137
|
+
item_name = ARGV.shift
|
138
|
+
code = ARGV.shift
|
139
|
+
if not item_name or not code
|
140
|
+
puts "Usage: aws-creds mfa <item-name> <mfa-code>"
|
141
|
+
exit(1)
|
142
|
+
end
|
143
|
+
|
144
|
+
sts_item = get_item("#{item_name} mfa")
|
145
|
+
sts_token = get_item("#{item_name} token")
|
146
|
+
if sts_item
|
147
|
+
puts "Removing existing STS credentials"
|
148
|
+
sts_item.delete
|
149
|
+
sts_token.delete if sts_token
|
150
|
+
end
|
151
|
+
|
152
|
+
item, token = get_item(item_name)
|
153
|
+
sts = AWS::STS.new(:access_key_id => item.attributes[:account], :secret_access_key => item.password)
|
154
|
+
begin
|
155
|
+
response = sts.new_session(:duration => (60 * 60 * 12), :serial_number => item.attributes[:comment], :token_code => code)
|
156
|
+
temp_item = keychain.generic_passwords.create(:label => "#{item_name} mfa",
|
157
|
+
:account => response.credentials[:access_key_id],
|
158
|
+
:password=> response.credentials[:secret_access_key],
|
159
|
+
:comment => response.expires_at.to_i.to_s)
|
160
|
+
temp_token = keychain.generic_passwords.create(:label => "#{item_name} token",
|
161
|
+
:account => "#{response.credentials[:access_key_id]}_token",
|
162
|
+
:password=> response.credentials[:session_token],
|
163
|
+
:comment => response.expires_at.to_i.to_s)
|
164
|
+
|
165
|
+
puts "MultiFactorAuthentication succeeded, expiration is #{response.expires_at}"
|
166
|
+
rescue AWS::STS::Errors::AccessDenied => e
|
167
|
+
puts e.to_s
|
168
|
+
end
|
169
|
+
|
170
|
+
when 'env'
|
171
|
+
item, token = get_item_from_args_for_command('shell')
|
172
|
+
puts "export AWS_ACCESS_KEY_ID=\"#{item.attributes[:account]}\""
|
173
|
+
puts "export AWS_ACCESS_KEY=\"#{item.attributes[:account]}\""
|
174
|
+
puts "export AWS_SECRET_ACCESS_KEY=\"#{item.password}\""
|
175
|
+
puts "export AWS_SECRET_KEY=\"#{item.password}\""
|
176
|
+
puts "export RPROMPT=\"(aws #{item.attributes[:label]})\""
|
177
|
+
puts "export AWS_CREDS_NAME=\"#{item.attributes[:label]}\""
|
178
|
+
if token
|
179
|
+
puts "export AWS_SECURITY_TOKEN=\"#{token.password}\""
|
180
|
+
end
|
181
|
+
|
110
182
|
when 'shell'
|
111
183
|
if ENV['AWS_CREDS_NAME']
|
112
184
|
puts "Already in aws-creds shell (AWS_CREDS_NAME is #{ENV['AWS_CREDS_NAME']})"
|
113
185
|
exit 1
|
114
186
|
end
|
115
187
|
|
116
|
-
item = get_item_from_args_for_command('shell')
|
188
|
+
item, token = get_item_from_args_for_command('shell')
|
117
189
|
aws_env = {}
|
118
190
|
aws_env['AWS_ACCESS_KEY_ID'] = aws_env['AWS_ACCESS_KEY'] = item.attributes[:account]
|
119
191
|
aws_env['AWS_SECRET_ACCESS_KEY'] = aws_env['AWS_SECRET_KEY'] = item.password
|
120
192
|
aws_env['AWS_CREDS_NAME'] = item.attributes[:label]
|
193
|
+
if token
|
194
|
+
aws_env['AWS_SECURITY_TOKEN'] = token.password
|
195
|
+
end
|
196
|
+
|
121
197
|
aws_env['RPROMPT'] = "(aws #{item.attributes[:label]})" # zsh only
|
122
198
|
|
123
199
|
exec(aws_env, ENV['SHELL'])
|
124
200
|
|
125
201
|
else
|
126
202
|
puts "Usage: #{$0} <command> <arguments>"
|
127
|
-
puts " Commands: init, ls, add, cat, rm, shell"
|
203
|
+
puts " Commands: init, ls, add, cat, env, mfa, rm, shell"
|
128
204
|
end
|
129
205
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-keychain-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-02-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-keychain
|