aws_runas 0.6.0 → 0.7.0

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.
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