aws_assume_role 0.0.2 → 0.0.3

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
  SHA1:
3
- metadata.gz: 199475f5c68d701119ec803d1af1e677583341c1
4
- data.tar.gz: 925d022c466217e38ae89c9345607963156de362
3
+ metadata.gz: 55cb1bdbca27ae7dfaf53948e1ad746a66afcc25
4
+ data.tar.gz: 43b7ce33d786b7ebfabbedb921b2c9b3a5f28cf1
5
5
  SHA512:
6
- metadata.gz: 6d898f41a279403a627b7b16b80747c76402e643af7fcd22311898e116afa96747b22345938430d4621d1d1663f3eda67e237027b354f60806d497258f0b1ebc
7
- data.tar.gz: ca9f4c76a16552e30bbd94f66997675b99c60e1cea48fb0faca796bbf2e57973b1e533f5f07a5dd3865269a8ffa77200f25819555bd64fe3c7b5f42b19bdb1e4
6
+ metadata.gz: ee94a33205511ab48a1c1f0e458ef98a20267b496cc556fd5cc35d87dbb4311d0d305374839348966e5b981ca29dee5ab0848ffa344215f5e20abc4ae864c815
7
+ data.tar.gz: 636303eb8f232061473a6d3de6a5809cc8eea20f3579c2f0eef8cd2e4964e08c569cce83c7b2fe05014c0980e76926038c67a998d7a10fc0201c5194b8ccd194
data/README.md CHANGED
@@ -1,8 +1,35 @@
1
1
  # aws-assume-role
2
2
 
3
3
  This will get role credentials for you, managing 2FA devices, and set those
4
- credentials in environments. It stores the fetched credentials in Gnome Keyring
5
- or OSX Keychain so they are not readable from disk.
4
+ credentials in environment variables then execute a provided command. It stores
5
+ the fetched credentials in Gnome Keyring or OSX Keychain so they are not
6
+ readable from disk.
7
+
8
+ ### Why?
9
+
10
+ This keeps your credentials safe in the keystore, and they are set as
11
+ environment variables for the duration and context of the executing command.
12
+ This helps prevent credential leaking and theft, and means they aren't stored on
13
+ disk as unencrypted files.
14
+
15
+ It allows easy credential management and roll assumption with a 2FA/MFA device.
16
+
17
+ For security and account management purposes we don't want to be managing users
18
+ in multiple accounts, just centrally then allowing them to assume roles in
19
+ other accounts.
20
+
21
+ ###
22
+
23
+ Assumptions:
24
+
25
+ - You have a parent/master account which you authenticate against with a 2FA
26
+ device.
27
+ - You then assume a role in another account.
28
+
29
+ This is easy to achieve in a web console, but you probably want to use tools
30
+ like Terraform of AWS Cli. This makes using those tools easy, without having to
31
+ constantly fetch and manage credentials for assumed roles, or provide
32
+ users/access keys for each account.
6
33
 
7
34
  ## Install
8
35
 
@@ -83,6 +110,31 @@ xx:
83
110
 
84
111
  ## How to use?
85
112
 
113
+ You need a key and secret for each `basic` role (a `parent`). You can set this
114
+ in the environment variable or in the `~/.aws/credentials` file.
115
+
116
+ It is recommended that you set this in the environment variable, the first time
117
+ aws-assume-role runs it will place these values in the keystore so they are
118
+ safe.
119
+
120
+ ### Add the basic/profile credentials to keystore
121
+
122
+ You can add the credentials that the system will use to assume roles to the
123
+ keystore. This is the recommended way of using `aws-assume-role`.
124
+
125
+ To add(or update) credentials use:
126
+
127
+ ```shell
128
+ $ aws-assume-role --profile scalefactory --add
129
+ Enter your AWS_ACCESS_KEY_ID:
130
+ 1234567890010
131
+ Enter your AWS_SECRET_ACCESS_KEY:
132
+ abcdefghijklmnopqrstuvwzyx1
133
+ Enter a AWS Region:
134
+ eu-west-1
135
+
136
+ ```
137
+
86
138
  ### In Environment variable
87
139
 
88
140
  ```
@@ -141,3 +193,13 @@ aws-assume-role --profile yy_mgmt -- aws ec2 describe-instances --query "Reserva
141
193
  10.254.0.10
142
194
  10.254.4.5
143
195
  ```
196
+
197
+
198
+ ## Deleting keystore values
199
+
200
+ Maybe you have a new keypair?
201
+
202
+ ```
203
+ aws-assume-role --profile yy_mgmt --delete
204
+ aws-assume-role --profile scalefactory --delete
205
+ ```
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'aws_assume_role'
7
- spec.version = '0.0.2'
7
+ spec.version = '0.0.3'
8
8
  spec.authors = ['Jon Topper', 'Jack Thomas']
9
9
  spec.email = ['jon@scalefactory.com', 'jack@scalefactory.com']
10
10
 
data/bin/aws-assume-role CHANGED
@@ -15,13 +15,25 @@ optparse = OptionParser.new do |opts|
15
15
  end
16
16
 
17
17
  options[:profile] = false
18
- opts.on('--profile name', 'Load the credentials for a profile into AWS ' \
19
- 'environment variables. If this is not specified the ') do |c|
18
+ opts.on('-p', '--profile name', 'Load the credentials for a profile into AWS ' \
19
+ 'environment variables.') do |c|
20
20
  options[:profile] = c
21
21
  end
22
22
 
23
+ options[:add] = false
24
+ opts.on('-a', '--add', 'Add basic/parent account credentials to keystore' \
25
+ 'environment variables. Must provide a profile name') do |c|
26
+ options[:add] = c
27
+ end
28
+
29
+ options[:delete] = false
30
+ opts.on('-d', '--delete', 'Delete credentials from keystore. Must ' \
31
+ 'provide a profile name.') do
32
+ options[:delete] = true
33
+ end
34
+
23
35
  options[:debug] = false
24
- opts.on('-d', '--debug', 'Enable debugging') do
36
+ opts.on('--debug', 'Enable debugging') do
25
37
  options[:debug] = true
26
38
  end
27
39
 
@@ -45,14 +57,20 @@ begin
45
57
  AWSAssumeRole::Profile.load_profiles
46
58
  AWSAssumeRole::Profile.load_config_file(options[:config])
47
59
  rescue Errno::ENOENT
48
- puts "No config file at options[:config]. Please create one!"
49
- exit 1
60
+ STDERR.puts "No config file at options[:config]. Please create one!"
61
+ exit -1 # rubocop:disable Lint/AmbiguousOperator
50
62
  end
51
63
 
52
-
53
64
  if options[:profile] != false
54
65
  profile = AWSAssumeRole::Profile.get_by_name(options[:profile] )
55
- profile.use
66
+
67
+ if options[:delete]
68
+ profile.remove
69
+ elsif options[:add]
70
+ profile.add
71
+ else
72
+ profile.use
73
+ end
56
74
 
57
75
  if options[:verbose]
58
76
  system('env | grep "AWS" | sort')
@@ -29,7 +29,7 @@ module AWSAssumeRole
29
29
  return nil
30
30
  end
31
31
 
32
- hash[:expiration] = Time.parse(hash[:expiration])
32
+ hash[:expiration] = Time.parse(hash[:expiration]) unless hash[:expiration].nil?
33
33
 
34
34
  logger.debug("Loaded #{hash}")
35
35
  AWSAssumeRole::Credentials.new(hash)
@@ -65,6 +65,10 @@ module AWSAssumeRole
65
65
  @credentials[:expiration]
66
66
  end
67
67
 
68
+ def region
69
+ @credentials[:region]
70
+ end
71
+
68
72
  def store_in_keyring(key)
69
73
  keyring = Keyring.new
70
74
  logger.debug("Keyring: store '#{key}' with #{@credentials.to_json}")
@@ -110,6 +110,16 @@ module AWSAssumeRole
110
110
  set_env if @options['set_environment']
111
111
  end
112
112
 
113
+ def remove
114
+ Credentials.new({}).delete_from_keyring(keyring_key)
115
+ end
116
+
117
+ def add
118
+ STDERR.puts "You can't add credentials to an assume_role "\
119
+ 'just basic/parent accounts.'
120
+ exit -1 # rubocop:disable Lint/AmbiguousOperator
121
+ end
122
+
113
123
  end
114
124
 
115
125
  end
@@ -26,30 +26,11 @@ module AWSAssumeRole
26
26
  end
27
27
 
28
28
  def sts_client
29
+ logger.debug("Calling STS client")
29
30
 
30
31
  return @sts_client unless @sts_client.nil?
31
32
 
32
- if @options.key?('access_key_id') &&
33
- @options.key?('secret_access_key')
34
-
35
- if @options.key?('region')
36
-
37
- @sts_client = Aws::STS::Client.new(
38
- access_key_id: @options['access_key_id'],
39
- secret_access_key: @options['secret_access_key'],
40
- region: @options['region'],
41
- )
42
-
43
- else
44
-
45
- @sts_client = Aws::STS::Client.new(
46
- access_key_id: @options['access_key_id'],
47
- secret_access_key: @options['secret_access_key'],
48
- )
49
-
50
- end
51
-
52
- elsif @options.key?('profile')
33
+ if @options.key?('profile')
53
34
 
54
35
  logger.info("Loading profile #{@options['profile']} from ~/.aws/credentials")
55
36
  # Attempt to load with profile name suplied
@@ -57,6 +38,18 @@ module AWSAssumeRole
57
38
  profile: @options['profile'],
58
39
  )
59
40
 
41
+ elsif access_key_id && secret_access_key
42
+
43
+ logger.debug("Access Key: #{access_key_id}")
44
+ logger.debug("Secret Key: #{secret_access_key}")
45
+ logger.debug("Region: #{region}")
46
+
47
+ @sts_client = Aws::STS::Client.new(
48
+ access_key_id: access_key_id,
49
+ secret_access_key: secret_access_key,
50
+ region: region,
51
+ )
52
+
60
53
  else
61
54
 
62
55
  @sts_client = Aws::STS::Client.new
@@ -73,18 +66,85 @@ module AWSAssumeRole
73
66
 
74
67
  end
75
68
 
69
+ def basic_credentials
70
+ logger.debug("Loading basic credentials")
71
+ # Check for profile creds in keyring first
72
+ @basic_credentials = Credentials.load_from_keyring("#{keyring_key}|basic")
73
+
74
+ return @basic_credentials unless @basic_credentials.nil?
75
+
76
+ creds = {
77
+ :access_key_id => ENV['AWS_ACCESS_KEY_ID'],
78
+ :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
79
+ }
80
+
81
+ if creds[:access_key_id].nil? or creds[:secret_access_key].nil?
82
+ STDERR.puts 'No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY ' \
83
+ 'found in the environment.'
84
+ exit -1 # rubocop:disable Lint/AmbiguousOperator
85
+ end
86
+
87
+ unless @options['region'].nil?
88
+ creds[:region] = @options['region']
89
+ else
90
+ creds[:region] = ENV['AWS_DEFAULT_REGION']
91
+ end
92
+
93
+ @basic_credentials = AWSAssumeRole::Credentials.new(creds)
94
+
95
+ @basic_credentials
96
+ end
97
+
76
98
  def access_key_id
77
- @options['access_key_id']
99
+ @options['access_key_id'] || basic_credentials.access_key_id
78
100
  end
79
101
 
80
102
  def secret_access_key
81
- @options['secret_access_key']
103
+ @options['secret_access_key'] || basic_credentials.secret_access_key
82
104
  end
83
105
 
84
106
  def region
85
- @options['region']
107
+ @options['region'] || basic_credentials.region
108
+ end
109
+
110
+ def remove
111
+ Credentials.new({}).delete_from_keyring(keyring_key)
112
+ Credentials.new({}).delete_from_keyring("#{keyring_key}|basic")
86
113
  end
87
114
 
115
+ def add
116
+ if @options['profile']
117
+ puts "WARNING: Storing credentials but a profile is specified and used for #{@name}"
118
+ end
119
+ if @options['access_key_id'] or @options['secret_access_key']
120
+ puts "WARNING: Storing credentials but they are specified in config for #{@name}"
121
+ end
122
+
123
+ @basic_credentials = Credentials.load_from_keyring("#{keyring_key}|basic")
124
+ new_creds = get_credentials
125
+ @basic_credentials.delete_from_keyring(keyring_key) unless @basic_credentials.nil?
126
+ @basic_credentials = AWSAssumeRole::Credentials.new(new_creds)
127
+ @basic_credentials.store_in_keyring("#{keyring_key}|basic")
128
+ end
129
+
130
+ def get_credentials
131
+ puts "Enter your AWS_ACCESS_KEY_ID: "
132
+ id = STDIN.gets
133
+ id.chomp!
134
+ puts "Enter your AWS_SECRET_ACCESS_KEY: "
135
+ secret = STDIN.gets
136
+ secret.chomp!
137
+ puts "Enter a AWS Region:"
138
+ region = STDIN.gets
139
+ region.chomp!
140
+
141
+ creds = {
142
+ :access_key_id => id,
143
+ :secret_access_key => secret,
144
+ :region => region,
145
+ }
146
+ creds
147
+ end
88
148
  end
89
149
 
90
150
  end
@@ -119,6 +119,14 @@ module AWSAssumeRole
119
119
  raise NotImplementedError
120
120
  end
121
121
 
122
+ def add
123
+ raise NotImplementedError
124
+ end
125
+
126
+ def remove
127
+ raise NotImplementedError
128
+ end
129
+
122
130
  def token_code
123
131
  puts "Enter your MFA's time-based one time password: "
124
132
  token_code = STDIN.gets
@@ -158,17 +166,29 @@ module AWSAssumeRole
158
166
 
159
167
  end
160
168
 
161
- identity = sts_client.get_caller_identity
169
+ begin
170
+ identity = sts_client.get_caller_identity
171
+ rescue Aws::Errors::MissingCredentialsError
172
+ STDERR.puts "No credentials found. Set one in the credentials file "\
173
+ "or environment."
174
+ exit -1 # rubocop:disable Lint/AmbiguousOperator
175
+ end
162
176
  user_name = identity.arn.split('/')[1]
163
177
  mfa_arn = "arn:aws:iam::#{identity.account}:mfa/#{user_name}"
164
178
 
165
179
  mfa_token_code = token_code
166
180
 
167
- session = sts_client.get_session_token(
168
- duration_seconds: duration,
169
- serial_number: mfa_arn,
170
- token_code: mfa_token_code,
171
- )
181
+ begin
182
+ session = sts_client.get_session_token(
183
+ duration_seconds: duration,
184
+ serial_number: mfa_arn,
185
+ token_code: mfa_token_code,
186
+ )
187
+ rescue Aws::STS::Errors::AccessDenied
188
+ STDERR.puts 'MultiFactorAuthentication failed with invalid MFA ' \
189
+ 'one time pass code.'
190
+ exit -1 # rubocop:disable Lint/AmbiguousOperator
191
+ end
172
192
 
173
193
  @session = Credentials.create_from_sdk(session.credentials)
174
194
  logger.info("Storing session in keyring '#{keyring_key}'")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_assume_role
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Topper
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-12-09 00:00:00.000000000 Z
12
+ date: 2016-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk