wdi_runas 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +7 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +107 -0
- data/Gemfile +17 -0
- data/LICENSE +201 -0
- data/README.md +157 -0
- data/Rakefile +19 -0
- data/certs/vancluever.pem +22 -0
- data/exe/wdi-runas +19 -0
- data/lib/aws_runas/cli.rb +67 -0
- data/lib/aws_runas/config.rb +61 -0
- data/lib/aws_runas/main.rb +104 -0
- data/lib/aws_runas/utils.rb +106 -0
- data/lib/aws_runas/version.rb +17 -0
- data/lib/aws_runas.rb +15 -0
- data/shell_profiles/sh.profile +23 -0
- data/spec/aws_runas/cli_spec.rb +59 -0
- data/spec/aws_runas/config_spec.rb +114 -0
- data/spec/aws_runas/main_spec.rb +208 -0
- data/spec/aws_runas/utils_spec.rb +197 -0
- data/spec/helpers/config_spec.rb +20 -0
- data/spec/helpers/files/aws_config +8 -0
- data/spec/helpers/files/aws_config_nomfa +7 -0
- data/spec/helpers/files/aws_config_noregion +6 -0
- data/spec/helpers/files/aws_config_nosource +6 -0
- data/spec/helpers/utils_spec.rb +36 -0
- data/spec/spec_helper.rb +34 -0
- data/wdi_runas.gemspec +45 -0
- metadata +183 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'inifile'
|
16
|
+
|
17
|
+
module AwsRunAs
|
18
|
+
# Manages the configuartion file, including loading and retrieving values.
|
19
|
+
class Config
|
20
|
+
attr_reader :profile
|
21
|
+
# Finds the configuration file (used if no file is specified).
|
22
|
+
# paths searched: ./aws_config, and ~/.aws/config.
|
23
|
+
def self.find_config_file
|
24
|
+
local_config = File.expand_path('aws_config')
|
25
|
+
user_config = File.expand_path('~/.aws/config')
|
26
|
+
return local_config if File.exist?(local_config)
|
27
|
+
user_config if File.exist?(user_config)
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(path:, profile:)
|
31
|
+
@path = path
|
32
|
+
@path = self.class.find_config_file unless @path
|
33
|
+
fail(Errno::ENOENT, "#{@path}") unless File.exist?(@path.to_s)
|
34
|
+
@profile = profile
|
35
|
+
end
|
36
|
+
|
37
|
+
# Loads the config section for a specific profile.
|
38
|
+
def load_config_value(key:)
|
39
|
+
section = @profile
|
40
|
+
section = "profile #{@profile}" unless @profile == 'default'
|
41
|
+
aws_config = IniFile.load(@path)
|
42
|
+
unless aws_config.has_section?(section)
|
43
|
+
fail(NameError, "Profile #{@profile} not found in #{@path}")
|
44
|
+
end
|
45
|
+
aws_config[section][key]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Checks to see if MFA is required for a specific profile.
|
49
|
+
def mfa_required?
|
50
|
+
return true if load_config_value(key: 'mfa_serial') && !ENV.include?('AWS_SESSION_TOKEN')
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
# loads the soruce credentials profile based on the supplied profile.
|
55
|
+
def load_source_profile
|
56
|
+
source_profile = load_config_value(key: 'source_profile')
|
57
|
+
return source_profile if source_profile
|
58
|
+
@profile
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'aws_runas/config'
|
16
|
+
require 'aws_runas/utils'
|
17
|
+
|
18
|
+
# AWS_SDK_CONFIG_OPT_OUT must be set here so that we use the pre-2.4 SDK
|
19
|
+
# behaviour, which ensures that ~/.aws/config is not re-read when assuming
|
20
|
+
# roles.
|
21
|
+
ENV.store('AWS_SDK_CONFIG_OPT_OUT', '1')
|
22
|
+
require 'aws-sdk'
|
23
|
+
|
24
|
+
module AwsRunAs
|
25
|
+
# Main program logic for aws-runas - sets up sts asession and assumed role,
|
26
|
+
# and hands off environment to called process.
|
27
|
+
class Main
|
28
|
+
# Instantiate the object and set up the path, profile, and populate MFA
|
29
|
+
def initialize(path: nil, profile: default, mfa_code: nil, no_role: nil)
|
30
|
+
cfg_path = if path
|
31
|
+
path
|
32
|
+
else
|
33
|
+
AwsRunAs::Config.find_config_file
|
34
|
+
end
|
35
|
+
@cfg = AwsRunAs::Config.new(path: cfg_path, profile: profile)
|
36
|
+
@mfa_code = mfa_code
|
37
|
+
@no_role = no_role
|
38
|
+
end
|
39
|
+
|
40
|
+
def sts_client
|
41
|
+
region = @cfg.load_config_value(key: 'region')
|
42
|
+
region = 'us-east-1' unless region
|
43
|
+
Aws::STS::Client.new(
|
44
|
+
profile: @cfg.load_source_profile,
|
45
|
+
region: region
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def assume_role
|
50
|
+
session_id = "aws-runas-session_#{Time.now.to_i}"
|
51
|
+
role_arn = @cfg.load_config_value(key: 'role_arn')
|
52
|
+
mfa_serial = @cfg.load_config_value(key: 'mfa_serial') unless ENV.include?('AWS_SESSION_TOKEN')
|
53
|
+
if @no_role
|
54
|
+
raise 'No mfa_serial in selected profile, session will be useless' if mfa_serial.nil?
|
55
|
+
@session = sts_client.get_session_token(
|
56
|
+
duration_seconds: 86400,
|
57
|
+
serial_number: mfa_serial,
|
58
|
+
token_code: @mfa_code
|
59
|
+
)
|
60
|
+
else
|
61
|
+
@session = Aws::AssumeRoleCredentials.new(
|
62
|
+
client: sts_client,
|
63
|
+
role_arn: role_arn,
|
64
|
+
serial_number: mfa_serial,
|
65
|
+
token_code: @mfa_code,
|
66
|
+
role_session_name: session_id
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def session_credentials
|
72
|
+
@session.credentials
|
73
|
+
end
|
74
|
+
|
75
|
+
def credentials_env
|
76
|
+
env = {}
|
77
|
+
env['AWS_ACCESS_KEY_ID'] = session_credentials.access_key_id
|
78
|
+
env['AWS_SECRET_ACCESS_KEY'] = session_credentials.secret_access_key
|
79
|
+
env['AWS_SESSION_TOKEN'] = session_credentials.session_token
|
80
|
+
env['AWS_RUNAS_PROFILE'] = @cfg.profile
|
81
|
+
unless @cfg.load_config_value(key: 'region').nil?
|
82
|
+
env['AWS_REGION'] = @cfg.load_config_value(key: 'region')
|
83
|
+
env['AWS_DEFAULT_REGION'] = @cfg.load_config_value(key: 'region')
|
84
|
+
end
|
85
|
+
if @no_role
|
86
|
+
env['AWS_SESSION_EXPIRATION'] = session_credentials.expiration.to_s
|
87
|
+
env['AWS_SESSION_EXPIRATION_UNIX'] = DateTime.parse(session_credentials.expiration.to_s).strftime('%s')
|
88
|
+
else
|
89
|
+
env['AWS_SESSION_EXPIRATION'] = @session.expiration.to_s
|
90
|
+
env['AWS_SESSION_EXPIRATION_UNIX'] = DateTime.parse(@session.expiration.to_s).strftime('%s')
|
91
|
+
env['AWS_RUNAS_ASSUMED_ROLE_ARN'] = @cfg.load_config_value(key: 'role_arn')
|
92
|
+
end
|
93
|
+
env
|
94
|
+
end
|
95
|
+
|
96
|
+
def handoff(command: nil, argv: nil, skip_prompt:)
|
97
|
+
env = credentials_env
|
98
|
+
unless command
|
99
|
+
AwsRunAs::Utils.handoff_to_shell(env: env, profile: @no_role ? nil : @cfg.profile, skip_prompt: skip_prompt)
|
100
|
+
end
|
101
|
+
exec(env, command, *argv)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Copyright 2016 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'rbconfig'
|
16
|
+
require 'tempfile'
|
17
|
+
require 'tmpdir'
|
18
|
+
require 'fileutils'
|
19
|
+
require 'English'
|
20
|
+
|
21
|
+
module AwsRunAs
|
22
|
+
# Utility functions that aren't specifically tied to a class.
|
23
|
+
module Utils
|
24
|
+
module_function
|
25
|
+
|
26
|
+
# Return the path to the shell_profiles directory vendored with the gem.
|
27
|
+
def shell_profiles_dir
|
28
|
+
File.expand_path('../../../shell_profiles', __FILE__)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Run an interactive bash session with a special streamed RC file. The RC
|
32
|
+
# merges a local .bashrc if it exists, with a prompt that includes the
|
33
|
+
# computed message from handoff_to_shell.
|
34
|
+
def handoff_bash(env:, path:, message:, skip_prompt:)
|
35
|
+
rc_data = IO.read("#{ENV['HOME']}/.bashrc") if File.exist?("#{ENV['HOME']}/.bashrc")
|
36
|
+
rc_file = Tempfile.new('aws_runas_bashrc')
|
37
|
+
rc_file.write("#{rc_data}\n") unless rc_data.nil?
|
38
|
+
rc_file.write(IO.read("#{shell_profiles_dir}/sh.profile"))
|
39
|
+
unless skip_prompt
|
40
|
+
rc_file.write("PS1=\"\\[\\e[\\$(aws_session_status_color)m\\](#{message})\\[\\e[0m\\] $PS1\"\n")
|
41
|
+
end
|
42
|
+
rc_file.close
|
43
|
+
system(env, path, '--rcfile', rc_file.path)
|
44
|
+
ensure
|
45
|
+
rc_file.unlink
|
46
|
+
end
|
47
|
+
|
48
|
+
# Run an interactive zsh session with a special streamed RC file. The RC
|
49
|
+
# merges a local .zshrc if it exists, with a prompt that includes the
|
50
|
+
# computed message from handoff_to_shell.
|
51
|
+
def handoff_zsh(env:, path:, message:, skip_prompt:)
|
52
|
+
rc_data = IO.read("#{ENV['HOME']}/.zshrc") if File.exist?("#{ENV['HOME']}/.zshrc")
|
53
|
+
rc_dir = Dir.mktmpdir('aws_runas_zsh')
|
54
|
+
rc_file = File.new("#{rc_dir}/.zshrc", 'w')
|
55
|
+
rc_file.write("#{rc_data}\n") unless rc_data.nil?
|
56
|
+
rc_file.write(IO.read("#{shell_profiles_dir}/sh.profile"))
|
57
|
+
unless skip_prompt
|
58
|
+
rc_file.write("setopt PROMPT_SUBST\n")
|
59
|
+
rc_file.write("export OLDPROMPT=\"${PROMPT}\"\n")
|
60
|
+
rc_file.write("PROMPT=$'%{\\e[\\%}$(aws_session_status_color)m(#{message})%{\\e[0m%} $OLDPROMPT'\n")
|
61
|
+
end
|
62
|
+
rc_file.close
|
63
|
+
env.store('ZDOTDIR', rc_dir)
|
64
|
+
system(env, path)
|
65
|
+
ensure
|
66
|
+
FileUtils.rmtree(rc_dir)
|
67
|
+
end
|
68
|
+
|
69
|
+
# load the shell for a specific operating system.
|
70
|
+
# if $SHELL exists, load that.
|
71
|
+
def shell
|
72
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw32/i
|
73
|
+
'cmd.exe'
|
74
|
+
elsif ENV.include?('SHELL')
|
75
|
+
ENV['SHELL']
|
76
|
+
else
|
77
|
+
'/bin/sh'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Compute the message given to the prompt based off supplied profile.
|
82
|
+
def compute_message(profile:)
|
83
|
+
if profile.nil?
|
84
|
+
'AWS'
|
85
|
+
else
|
86
|
+
"AWS:#{profile}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# "Handoff" to a supported interactive shell. More technically, this runs
|
91
|
+
# an interactive shell with the shell prompt customized to the current
|
92
|
+
# running AWS profile. If the shell is not something we can handle
|
93
|
+
# specifically, just run the shell.
|
94
|
+
def handoff_to_shell(env:, profile: nil, skip_prompt:)
|
95
|
+
path = shell
|
96
|
+
if path.end_with?('/bash')
|
97
|
+
handoff_bash(env: env, path: path, message: compute_message(profile: profile), skip_prompt: skip_prompt)
|
98
|
+
elsif path.end_with?('/zsh')
|
99
|
+
handoff_zsh(env: env, path: path, message: compute_message(profile: profile), skip_prompt: skip_prompt)
|
100
|
+
else
|
101
|
+
system(env, path)
|
102
|
+
end
|
103
|
+
exit $CHILD_STATUS.exitstatus
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module AwsRunAs
|
16
|
+
VERSION = '0.5.1'
|
17
|
+
end
|
data/lib/aws_runas.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'aws_runas/main'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# vim:filetype=sh
|
2
|
+
#
|
3
|
+
# aws_session_expired checks to see if the current session has expired, based
|
4
|
+
# off of the value stored in AWS_SESSION_EXPIRATION_UNIX. This functionality
|
5
|
+
# relies on date being in $PATH.
|
6
|
+
aws_session_expired() {
|
7
|
+
if [[ "${AWS_SESSION_EXPIRATION_UNIX}" -lt "$(date +%s)" ]]; then
|
8
|
+
return 0
|
9
|
+
fi
|
10
|
+
return 1
|
11
|
+
}
|
12
|
+
|
13
|
+
# aws_session_status_color returns an ANSI color number for the specific status
|
14
|
+
# of the session. Note that if session_expired is not correctly functioning,
|
15
|
+
# this will always be yellow. Red is shown when it's verified that the session
|
16
|
+
# has expired.
|
17
|
+
aws_session_status_color() {
|
18
|
+
if aws_session_expired; then
|
19
|
+
echo "31"
|
20
|
+
else
|
21
|
+
echo "33"
|
22
|
+
fi
|
23
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'spec_helper'
|
16
|
+
require 'aws_runas/cli'
|
17
|
+
require 'aws_runas/main'
|
18
|
+
|
19
|
+
describe AwsRunAs::Cli do
|
20
|
+
describe '::load_opts' do
|
21
|
+
it 'loads the path option' do
|
22
|
+
opts = AwsRunAs::Cli.load_opts(args: ['--path', 'test-opts/aws_config'])
|
23
|
+
expect(opts[:path]).to eq('test-opts/aws_config')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'loads the profile option' do
|
27
|
+
opts = AwsRunAs::Cli.load_opts(args: ['--profile', 'test-profile'])
|
28
|
+
expect(opts[:profile]).to eq('test-profile')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '::start' do
|
33
|
+
before(:example) do
|
34
|
+
allow(AwsRunAs::Cli).to receive(:load_opts).and_return({})
|
35
|
+
allow(AwsRunAs::Cli).to receive(:read_mfa_if_needed)
|
36
|
+
allow(AwsRunAs::Main).to receive(:new).and_return double(
|
37
|
+
'AwsRunAs::Main',
|
38
|
+
assume_role: true,
|
39
|
+
handoff: true
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'creates an AwsConfig::Main instance' do
|
44
|
+
expect(AwsRunAs::Main).to receive(:new)
|
45
|
+
AwsRunAs::Cli.start
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '::read_mfa_if_needed' do
|
50
|
+
it 'reads the MFA code' do
|
51
|
+
allow(STDIN).to receive(:gets).and_return('123456')
|
52
|
+
mfa_code = AwsRunAs::Cli.read_mfa_if_needed(
|
53
|
+
path: MOCK_AWS_CONFIGPATH,
|
54
|
+
profile: 'test-profile'
|
55
|
+
)
|
56
|
+
expect(mfa_code).to eq('123456')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'spec_helper'
|
16
|
+
require 'aws_runas/config'
|
17
|
+
|
18
|
+
describe AwsRunAs::Config do
|
19
|
+
describe '::find_config_file' do
|
20
|
+
before(:example) do
|
21
|
+
allow(File).to receive(:expand_path).with('aws_config').and_return('./aws_config')
|
22
|
+
allow(File).to receive(:expand_path).with('~/.aws/config').and_return('./.aws/config')
|
23
|
+
allow(File).to receive(:exist?).with('./.aws/config').and_return true
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'finds a file at ./aws_config' do
|
27
|
+
allow(File).to receive(:exist?).with('./aws_config').and_return true
|
28
|
+
expect(AwsRunAs::Config.find_config_file).to eq('./aws_config')
|
29
|
+
end
|
30
|
+
it 'finds a file at ~/.aws/config' do
|
31
|
+
allow(File).to receive(:exist?).with('./aws_config').and_return false
|
32
|
+
expect(AwsRunAs::Config.find_config_file).to eq('./.aws/config')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with profile set to default' do
|
37
|
+
before(:context) do
|
38
|
+
@cfg = AwsRunAs::Config.new(path: MOCK_AWS_CONFIGPATH, profile: 'default')
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#load_config_value' do
|
42
|
+
it 'loads a value from the default profile' do
|
43
|
+
expect(@cfg.load_config_value(key: 'region')).to eq('us-east-1')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#load_source_profile' do
|
48
|
+
it 'returns the default profile when no source profile is present' do
|
49
|
+
expect(@cfg.load_source_profile).to eq('default')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with profile set to test-profile' do
|
55
|
+
before(:context) do
|
56
|
+
@cfg = AwsRunAs::Config.new(path: MOCK_AWS_CONFIGPATH, profile: 'test-profile')
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#initialize' do
|
60
|
+
it 'sets the profile correctly' do
|
61
|
+
expect(@cfg.instance_variable_get('@profile')).to eq('test-profile')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#load_config_value' do
|
66
|
+
it 'loads a value from the non-default profile' do
|
67
|
+
expect(@cfg.load_config_value(key: 'mfa_serial')).to eq('arn:aws:iam::123456789012:mfa/test')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#mfa_required' do
|
72
|
+
it 'confirms MFA is required the non-default profile' do
|
73
|
+
expect(@cfg.instance_variable_get('@profile')).to eq('test-profile')
|
74
|
+
expect(@cfg.mfa_required?).to be true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'confirms MFA is not required if AWS_SESSION_TOKEN is set' do
|
78
|
+
expect(@cfg.instance_variable_get('@profile')).to eq('test-profile')
|
79
|
+
expect(@cfg.mfa_required?).to be true
|
80
|
+
ENV.store('AWS_SESSION_TOKEN', 'foo')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#load_source_profile' do
|
85
|
+
it 'loads the source credentials profile for the the non-default profile' do
|
86
|
+
expect(@cfg.load_source_profile).to eq('test-credentials')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'with profile set to an invalid profile' do
|
92
|
+
before(:context) do
|
93
|
+
@cfg = AwsRunAs::Config.new(path: MOCK_AWS_CONFIGPATH, profile: 'bad-profile')
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#load_config_value' do
|
97
|
+
it 'raises a NameError when a value load is attempted' do
|
98
|
+
expect { @cfg.load_config_value(key: 'region') }.to raise_error(NameError)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with an invalid config file supplied' do
|
104
|
+
describe '#load_config_value' do
|
105
|
+
it 'raises a Errno::ENOENT error' do
|
106
|
+
expect do
|
107
|
+
AwsRunAs::Config.new(
|
108
|
+
path: '/bad/path/here', profile: 'default'
|
109
|
+
)
|
110
|
+
end.to raise_error(Errno::ENOENT)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|