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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE +1 -1
- data/README.md +28 -11
- data/aws_runas.gemspec +1 -1
- data/lib/aws_runas/cli.rb +4 -2
- data/lib/aws_runas/main.rb +32 -3
- data/lib/aws_runas/version.rb +1 -1
- data/spec/aws_runas/main_spec.rb +128 -2
- metadata +6 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d280ef6460171b56e718f87a5f60300f5a17c9d06a7f9ee638ebf82e08ec4a9b
|
4
|
+
data.tar.gz: 3059ae7baea24658c569ff71dec7623c53447dd357101ec63544d6cecceb8bcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26104c0fea4f55532118f3be8443750ddafdf018e4e78457a49ceb3b8c6bead60d0ba79425ee065b0407f501bd0d8f3498496ea38b6a1ab46f7437208dc9b17b
|
7
|
+
data.tar.gz: 757866792aa06ce28b68db85ee423111eba5bdf5435615e327a43442ef37ffc06a3e198a2b8e2f5ac9833deb00b2b634d5d27c87a9880c3695ddada9c3c75899
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -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-
|
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
|
39
|
-
After this, your
|
40
|
-
chain environment
|
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,
|
49
|
-
|
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
|
-
* `
|
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
|
-
|
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-
|
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.
|
data/aws_runas.gemspec
CHANGED
@@ -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 '
|
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'
|
data/lib/aws_runas/cli.rb
CHANGED
@@ -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 '
|
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
|
-
|
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
|
|
data/lib/aws_runas/main.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
83
|
+
render_classic_session
|
55
84
|
end
|
56
85
|
|
57
86
|
def assume_role
|
data/lib/aws_runas/version.rb
CHANGED
data/spec/aws_runas/main_spec.rb
CHANGED
@@ -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_#{
|
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_#{
|
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.
|
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-
|
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:
|
65
|
+
name: optimist
|
66
66
|
requirement: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: '
|
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: '
|
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.
|
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
|