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 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
@@ -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.8'
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.8
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: 2013-07-02 00:00:00.000000000 Z
12
+ date: 2014-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby-keychain