aws_runas 0.6.0 → 0.7.0

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
- SHA1:
3
- metadata.gz: 29d8ce9a9034488a4faa15f5243852d67fb45850
4
- data.tar.gz: 177b2295df14d918a2a0105527f6fb0c4057b22a
2
+ SHA256:
3
+ metadata.gz: d280ef6460171b56e718f87a5f60300f5a17c9d06a7f9ee638ebf82e08ec4a9b
4
+ data.tar.gz: 3059ae7baea24658c569ff71dec7623c53447dd357101ec63544d6cecceb8bcc
5
5
  SHA512:
6
- metadata.gz: 051dc45bdd27dc5a6c93d41f0f3e25cfde3767e8d7b0d0774ef8db619d30136644edfd716d974f1ecdb0850be1c8fc2e1b78a214f4bde92918e28d5c9562dcca
7
- data.tar.gz: 7508a80014cc4d18de0f7228b7871a519038d8b9a7c83728904abc3d534de9cbc1fc0f1c4355097369766c2a6074778810c2e308b34349902f9a594cb8359d1c
6
+ metadata.gz: 26104c0fea4f55532118f3be8443750ddafdf018e4e78457a49ceb3b8c6bead60d0ba79425ee065b0407f501bd0d8f3498496ea38b6a1ab46f7437208dc9b17b
7
+ data.tar.gz: 757866792aa06ce28b68db85ee423111eba5bdf5435615e327a43442ef37ffc06a3e198a2b8e2f5ac9833deb00b2b634d5d27c87a9880c3695ddada9c3c75899
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,25 @@
1
+ ## v0.7.0
2
+
3
+ * Version now can be printed by supplying --version.
4
+ * The gem now uses [Optimist][ref-optimist], and as such should no longer give
5
+ deprecation warnings for its previous name.
6
+ [#21](https://github.com/vancluever/aws-runas/issues/21)
7
+ * Corrected an issue with session ID generation when the calculated new
8
+ long-from session ID exceeded 64 characters. In this situation, the session
9
+ name will fall back to the classic generic timestamped ID.
10
+ [#17](https://github.com/vancluever/aws-runas/issues/17)
11
+ * When calling from an assumed role, the session ID now takes on the name of the
12
+ access key ID instead of the account ID and user name. This should help
13
+ prevent length or session name nesting issues, while still making the session
14
+ name useful. [#17](https://github.com/vancluever/aws-runas/issues/17)
15
+ * The access key ID-based session ID will also be used if the account and
16
+ user-based session ID would exceed 64 characters under normal circumstances,
17
+ ensuring that the classic ID is strictly a fallback in major edge cases where
18
+ either is unusable or if the user has no access to GetCallerIdentity.
19
+ [#17](https://github.com/vancluever/aws-runas/issues/17)
20
+
21
+ [ref-optimist]: https://github.com/ManageIQ/optimist
22
+
1
23
  ## v0.6.0
2
24
 
3
25
  ### Session Duration Support
data/LICENSE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2015-2017 Chris Marchesi
189
+ Copyright 2015-2018 Chris Marchesi
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -30,14 +30,24 @@ thing, but there are some differentiators in this gem:
30
30
  with `--no-role`. Subsequent uses of `aws-runas` after this will not prompt
31
31
  you for MFA (useful for tooling that needs to assume multiple roles off the
32
32
  same session token).
33
+ * The session duration can be controlled with the `--duration` parameter. This
34
+ allows you to change the session expiration if you require a period longer or
35
+ shorter than an hour. The actual ranges you can choose with this setting
36
+ depend on the account you are using and any configured maximums set on your
37
+ role. More details can be found in the API documentation for
38
+ [GetSesionToken][get-session-token] and [AssumeRole][assume-role].
39
+
40
+ [get-session-token]: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html
41
+ [assume-role]: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
33
42
 
34
43
  How it Works
35
44
  -------------
36
45
 
37
46
  Roles are assumed, or session tokens are simply acquired (if `--no-role` is
38
- specified) via the `AssumeRole` or the `GetSessionToken` AWS STS API calls.
39
- After this, your command or shell is launched with the standard AWS credential
40
- chain environment variables set:
47
+ specified) via the [`AssumeRole`][assume-role] or the
48
+ [`GetSessionToken`][get-session-token] AWS STS API calls. After this, your
49
+ command or shell is launched with the standard AWS credential chain environment
50
+ variables set:
41
51
 
42
52
  * `AWS_ACCESS_KEY_ID`
43
53
  * `AWS_SECRET_ACCESS_KEY`
@@ -45,17 +55,24 @@ chain environment variables set:
45
55
 
46
56
  ### Additional Variables
47
57
 
48
- In addition to the above, two toolchain-local environment variables are set to
49
- help you determine what credentials are in use locally:
58
+ In addition to the above, the following environment variables are set to help
59
+ you gather additional information about the role and environment you are running
60
+ under:
50
61
 
51
62
  * `AWS_RUNAS_ASSUMED_ROLE_ARN` - set when a role is assumed (not set if
52
63
  `--no-role` is used)
53
- * `AWS_RUNAS_PROFILE` - set with the profile used when `aws-runas` was run
64
+ * `AWS_ROLE_SESSION_NAME` - contains the assumed role's session name (not set
65
+ if `--no-role` is used). The format is
66
+ `aws-runas-session_ACCTID_USERNAME_TIMESTAMP` when the user has access to
67
+ [`GetCallerIdentity`][get-caller-identity], and `aws-runas-session_TIMESTAMP`
68
+ format when they do not.
69
+ * `AWS_RUNAS_PROFILE` - set with the profile used when `aws-runas` was run.
54
70
  * `AWS_REGION` and `AWS_DEFAULT_REGION` - set with the region name defined in
55
- the profile being used
56
- * `AWS_SESSION_EXPIRATION` - set with the expiry timestamp in UTC
57
- * `AWS_SESSION_EXPIRATION_UNIX` - set with the expiry timestamp in Unix time,
58
- useful for scripting
71
+ the profile being used.
72
+ * `AWS_SESSION_EXPIRATION` - set with the expiry timestamp in UTC.
73
+ * `AWS_SESSION_EXPIRATION_UNIX` - set with the expiry timestamp in Unix time.
74
+
75
+ [get-caller-identity]: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
59
76
 
60
77
  ### Fancy Bash/Zsh Prompt
61
78
 
@@ -143,7 +160,7 @@ License
143
160
  --------
144
161
 
145
162
  ```
146
- Copyright 2015-2017 Chris Marchesi
163
+ Copyright 2015-2018 Chris Marchesi
147
164
 
148
165
  Licensed under the Apache License, Version 2.0 (the "License");
149
166
  you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
 
40
40
  spec.add_dependency 'aws-sdk', '~> 2.11'
41
41
  spec.add_dependency 'inifile', '~> 3.0'
42
- spec.add_dependency 'trollop', '~> 2.1'
42
+ spec.add_dependency 'optimist', '~> 3.0'
43
43
 
44
44
  spec.add_development_dependency 'rake', '~> 10.4'
45
45
  spec.add_development_dependency 'rspec', '~> 3.4'
@@ -12,9 +12,10 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'trollop'
15
+ require 'optimist'
16
16
  require 'aws_runas/config'
17
17
  require 'aws_runas/main'
18
+ require 'aws_runas/version'
18
19
  require 'io/console'
19
20
 
20
21
  module AwsRunAs
@@ -23,7 +24,8 @@ module AwsRunAs
23
24
 
24
25
  # loads the command-line options.
25
26
  def load_opts(args: ARGV)
26
- Trollop.options(args) do
27
+ Optimist.options(args) do
28
+ version AwsRunAs::VERSION
27
29
  banner <<-EOS.gsub(/^ {10}/, '')
28
30
  aws-runas: Run commands under AWS IAM roles
29
31
 
@@ -25,7 +25,9 @@ module AwsRunAs
25
25
  # Main program logic for aws-runas - sets up sts asession and assumed role,
26
26
  # and hands off environment to called process.
27
27
  class Main
28
- # Instantiate the object and set up the path, profile, and populate MFA
28
+ # Instantiate the object and set up the path, profile, and populate MFA.
29
+ #
30
+ # Session timestamp is also registered here to prevent races.
29
31
  def initialize(path: nil, profile: default, mfa_code: nil, no_role: nil, duration_seconds: 3600)
30
32
  cfg_path = if path
31
33
  path
@@ -36,6 +38,7 @@ module AwsRunAs
36
38
  @mfa_code = mfa_code
37
39
  @no_role = no_role
38
40
  @duration_seconds = duration_seconds
41
+ @session_timestamp = Time.now.to_i
39
42
  end
40
43
 
41
44
  def sts_client
@@ -47,11 +50,37 @@ module AwsRunAs
47
50
  )
48
51
  end
49
52
 
53
+ def render_classic_session
54
+ "aws-runas-session_#{@session_timestamp}"
55
+ end
56
+
57
+ def render_account_user_session(caller_identity)
58
+ "aws-runas-session_#{caller_identity.account}_#{caller_identity.arn.split('/')[-1]}_#{@session_timestamp}"
59
+ end
60
+
61
+ def render_access_key_session(caller_identity)
62
+ "aws-runas-session_#{caller_identity.user_id.split(':')[0]}_#{@session_timestamp}"
63
+ end
64
+
65
+ def use_access_key_id?(caller_identity)
66
+ caller_identity.arn =~ %r{^arn:aws:sts::\d+:assumed-role\/} ||
67
+ render_account_user_session(caller_identity).length > 64
68
+ end
69
+
70
+ # Returns a session name based on the following criteria:
71
+ # * If the user ARN matches that of an assumed role, return the access key ID
72
+ # * Otherwise, return the account ID and the user (last part of the ARN).
73
+ def render_modern_session(caller_identity)
74
+ return render_access_key_session(caller_identity) if use_access_key_id?(caller_identity)
75
+ render_account_user_session(caller_identity)
76
+ end
77
+
50
78
  def session_id
51
79
  caller_identity = sts_client.get_caller_identity
52
- "aws-runas-session_#{caller_identity.account}_#{caller_identity.arn.split('/')[-1]}_#{Time.now.to_i}"
80
+ return render_classic_session if render_modern_session(caller_identity).length > 64
81
+ render_modern_session(caller_identity)
53
82
  rescue Aws::STS::Errors::AccessDeniedException
54
- "aws-runas-session_#{Time.now.to_i}"
83
+ render_classic_session
55
84
  end
56
85
 
57
86
  def assume_role
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  module AwsRunAs
16
- VERSION = '0.6.0'
16
+ VERSION = '0.7.0'
17
17
  end
@@ -35,6 +35,104 @@ describe AwsRunAs::Main do
35
35
  end
36
36
  end
37
37
 
38
+ describe '#render_classic_session' do
39
+ it 'renders an account ID and user based session' do
40
+ expect(@main.render_classic_session).to eq("aws-runas-session_#{@main.instance_variable_get(:@session_timestamp)}")
41
+ end
42
+ end
43
+
44
+ describe '#render_account_user_session' do
45
+ it 'renders an account ID and user based session' do
46
+ expect(
47
+ @main.render_account_user_session(
48
+ double(
49
+ account: '123456789012',
50
+ arn: 'arn:aws:iam::123456789012:user/Alice',
51
+ user_id: 'AKIAI44QH8DHBEXAMPLE'
52
+ )
53
+ )
54
+ ).to eq("aws-runas-session_123456789012_Alice_#{@main.instance_variable_get(:@session_timestamp)}")
55
+ end
56
+ end
57
+
58
+ describe '#render_access_key_session' do
59
+ it 'renders an access key ID-based session' do
60
+ expect(
61
+ @main.render_access_key_session(
62
+ double(
63
+ account: '123456789012',
64
+ arn: 'arn:aws:iam::123456789012:user/Alice',
65
+ user_id: 'AKIAI44QH8DHBEXAMPLE'
66
+ )
67
+ )
68
+ ).to eq("aws-runas-session_AKIAI44QH8DHBEXAMPLE_#{@main.instance_variable_get(:@session_timestamp)}")
69
+ end
70
+ end
71
+
72
+ describe '#use_access_key_id?' do
73
+ it 'is falsey when an account ID and user based session is within 64 characters' do
74
+ expect(
75
+ @main.use_access_key_id?(
76
+ double(
77
+ account: '123456789012',
78
+ arn: 'arn:aws:iam::123456789012:user/Alice',
79
+ user_id: 'AKIAI44QH8DHBEXAMPLE'
80
+ )
81
+ )
82
+ ).to be_falsey
83
+ end
84
+
85
+ it 'is truthy when an account ID and user based session is more than 64 characters' do
86
+ expect(
87
+ @main.use_access_key_id?(
88
+ double(
89
+ account: '123456789012',
90
+ arn: 'arn:aws:iam::123456789012:user/AliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAlice',
91
+ user_id: 'AKIAI44QH8DHBEXAMPLE'
92
+ )
93
+ )
94
+ ).to be_truthy
95
+ end
96
+ end
97
+
98
+ describe '#render_modern_session' do
99
+ it 'returns account ID and user based session when caller identity is not an assumed role' do
100
+ expect(
101
+ @main.render_modern_session(
102
+ double(
103
+ account: '123456789012',
104
+ arn: 'arn:aws:iam::123456789012:user/Alice',
105
+ user_id: 'AKIAI44QH8DHBEXAMPLE'
106
+ )
107
+ )
108
+ ).to eq("aws-runas-session_123456789012_Alice_#{@main.instance_variable_get(:@session_timestamp)}")
109
+ end
110
+
111
+ it 'returns access key ID based session when caller identity is an assumed role' do
112
+ expect(
113
+ @main.render_modern_session(
114
+ double(
115
+ account: '123456789012',
116
+ arn: 'arn:aws:sts::123456789012:assumed-role/AliceAdmins/AliceSession',
117
+ user_id: 'AKIAI44QH8DHBEXAMPLE:AliceSession'
118
+ )
119
+ )
120
+ ).to eq("aws-runas-session_AKIAI44QH8DHBEXAMPLE_#{@main.instance_variable_get(:@session_timestamp)}")
121
+ end
122
+
123
+ it 'returns access key ID based session when account ID and user session is over 64 characters' do
124
+ expect(
125
+ @main.render_modern_session(
126
+ double(
127
+ account: '123456789012',
128
+ arn: 'arn:aws:iam::123456789012:user/AliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAlice',
129
+ user_id: 'AKIAI44QH8DHBEXAMPLE'
130
+ )
131
+ )
132
+ ).to eq("aws-runas-session_AKIAI44QH8DHBEXAMPLE_#{@main.instance_variable_get(:@session_timestamp)}")
133
+ end
134
+ end
135
+
38
136
  describe '#session_id' do
39
137
  it 'returns a properly formatted AWS session name for assuming roles' do
40
138
  allow_any_instance_of(Aws::STS::Client).to receive(:get_caller_identity) do |obj|
@@ -47,7 +145,21 @@ describe AwsRunAs::Main do
47
145
  }
48
146
  )
49
147
  end
50
- expect(@main.session_id).to eq("aws-runas-session_123456789012_Alice_#{Time.now.to_i}")
148
+ expect(@main.session_id).to eq("aws-runas-session_123456789012_Alice_#{@main.instance_variable_get(:@session_timestamp)}")
149
+ end
150
+
151
+ it 'returns a session name formatted on access key ID when user is assumed role' do
152
+ allow_any_instance_of(Aws::STS::Client).to receive(:get_caller_identity) do |obj|
153
+ obj.stub_data(
154
+ :get_caller_identity,
155
+ {
156
+ account: '123456789012',
157
+ arn: 'arn:aws:sts::123456789012:assumed-role/AliceAdmins/AliceSession',
158
+ user_id: 'AKIAI44QH8DHBEXAMPLE:AliceSession'
159
+ }
160
+ )
161
+ end
162
+ expect(@main.session_id).to eq("aws-runas-session_AKIAI44QH8DHBEXAMPLE_#{@main.instance_variable_get(:@session_timestamp)}")
51
163
  end
52
164
 
53
165
  it 'returns a basic session ID when caller has no access to get_caller_identity' do
@@ -58,7 +170,21 @@ describe AwsRunAs::Main do
58
170
  }
59
171
  )
60
172
  )
61
- expect(@main.session_id).to eq("aws-runas-session_#{Time.now.to_i}")
173
+ expect(@main.session_id).to eq("aws-runas-session_#{@main.instance_variable_get(:@session_timestamp)}")
174
+ end
175
+
176
+ it 'returns a basic session ID if the resultant session would be longer than 64 characters' do
177
+ allow_any_instance_of(Aws::STS::Client).to receive(:get_caller_identity) do |obj|
178
+ obj.stub_data(
179
+ :get_caller_identity,
180
+ {
181
+ account: '123456789012',
182
+ arn: 'arn:aws:iam::123456789012:user/AliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAliceAlice',
183
+ user_id: 'AKIAI44QH8DHBEXAMPLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE'
184
+ }
185
+ )
186
+ end
187
+ expect(@main.session_id).to eq("aws-runas-session_#{@main.instance_variable_get(:@session_timestamp)}")
62
188
  end
63
189
  end
64
190
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_runas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Marchesi
@@ -31,7 +31,7 @@ cert_chain:
31
31
  /CMDeSP9Z1l0CVvcRsZvmOu3NllZcezFyYi78K+tlmRajCeAV4pWXdcJg26w+u7I
32
32
  uK4=
33
33
  -----END CERTIFICATE-----
34
- date: 2018-04-17 00:00:00.000000000 Z
34
+ date: 2018-09-23 00:00:00.000000000 Z
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: aws-sdk
@@ -62,19 +62,19 @@ dependencies:
62
62
  - !ruby/object:Gem::Version
63
63
  version: '3.0'
64
64
  - !ruby/object:Gem::Dependency
65
- name: trollop
65
+ name: optimist
66
66
  requirement: !ruby/object:Gem::Requirement
67
67
  requirements:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
- version: '2.1'
70
+ version: '3.0'
71
71
  type: :runtime
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  requirements:
75
75
  - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: '2.1'
77
+ version: '3.0'
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: rake
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -188,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
188
  version: '0'
189
189
  requirements: []
190
190
  rubyforge_project:
191
- rubygems_version: 2.6.14.1
191
+ rubygems_version: 2.7.7
192
192
  signing_key:
193
193
  specification_version: 4
194
194
  summary: Run a command or shell under an assumed AWS IAM role
metadata.gz.sig CHANGED
Binary file