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