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