aws-keychain-util 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
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