sty 0.0.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/.document +2 -0
- data/README.md +5 -0
- data/auth-keys.yaml +8 -0
- data/auth.yaml +19 -0
- data/bin/sty +21 -0
- data/ec2.yaml +7 -0
- data/ext/install/Rakefile +39 -0
- data/lib/sty.rb +7 -0
- data/lib/sty/account.rb +18 -0
- data/lib/sty/auth-rotate.rb +69 -0
- data/lib/sty/auth.rb +188 -0
- data/lib/sty/cli.rb +71 -0
- data/lib/sty/config.rb +9 -0
- data/lib/sty/console.rb +106 -0
- data/lib/sty/dig.rb +22 -0
- data/lib/sty/functions.rb +94 -0
- data/lib/sty/info.rb +42 -0
- data/lib/sty/keychain.rb +3 -0
- data/lib/sty/proxy.rb +55 -0
- data/lib/sty/ssh.rb +270 -0
- data/lib/sty/ssm.rb +164 -0
- data/lib/sty/store.rb +3 -0
- data/proxy.yaml +7 -0
- data/sty.gemspec +27 -0
- metadata +157 -0
data/lib/sty/config.rb
ADDED
data/lib/sty/console.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative 'functions'
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'json'
|
5
|
+
require 'net/http'
|
6
|
+
require 'open3'
|
7
|
+
|
8
|
+
class Console
|
9
|
+
|
10
|
+
CONSOLE_URL = 'https://ap-southeast-2.console.aws.amazon.com/'
|
11
|
+
SIGN_IN_URL = 'https://signin.aws.amazon.com/federation'
|
12
|
+
SIGN_OUT_URL = 'https://ap-southeast-2.console.aws.amazon.com/console/logout!doLogout'
|
13
|
+
|
14
|
+
SESSION_DURATION_SECONDS = 43200
|
15
|
+
|
16
|
+
BROWSERS = %w(chrome firefox vivaldi safari)
|
17
|
+
|
18
|
+
def go(url, browser = '', incognito = false)
|
19
|
+
url = "'#{url}'"
|
20
|
+
run = %w(open)
|
21
|
+
run << '-n' if incognito
|
22
|
+
case browser.downcase
|
23
|
+
when 'safari'
|
24
|
+
run << "-a 'Safari'"
|
25
|
+
run << url
|
26
|
+
when 'chrome'
|
27
|
+
run << "-a 'Google Chrome'"
|
28
|
+
incognito ? run << "--args --incognito #{url}" : run << url
|
29
|
+
when 'firefox'
|
30
|
+
run << '-a Firefox'
|
31
|
+
incognito ? run << "--args -private-window #{url}" : run << url
|
32
|
+
when 'vivaldi'
|
33
|
+
run << '-a Vivaldi'
|
34
|
+
incognito ? run << "--args --incognito #{url}" : run << url
|
35
|
+
else
|
36
|
+
run << url
|
37
|
+
end
|
38
|
+
|
39
|
+
puts run.join(' ')
|
40
|
+
system(run.join(' '))
|
41
|
+
end
|
42
|
+
|
43
|
+
def signin_params
|
44
|
+
return @signin_params if @signin_params
|
45
|
+
|
46
|
+
creds_string = {'sessionId' => ENV['AWS_ACCESS_KEY_ID'],
|
47
|
+
'sessionKey' => ENV['AWS_SECRET_ACCESS_KEY'],
|
48
|
+
'sessionToken' => ENV['AWS_SESSION_TOKEN']}.to_json
|
49
|
+
|
50
|
+
uri = URI(SIGN_IN_URL)
|
51
|
+
params = {'Action' => 'getSigninToken',
|
52
|
+
'Session' => creds_string}
|
53
|
+
uri.query = URI.encode_www_form(params)
|
54
|
+
|
55
|
+
begin
|
56
|
+
res = Net::HTTP.get_response(uri)
|
57
|
+
rescue Exception => e
|
58
|
+
puts red("ERROR! Unable to obtain signin token.")
|
59
|
+
puts white(e.message)
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
|
63
|
+
unless res.is_a?(Net::HTTPSuccess)
|
64
|
+
puts red("ERROR! Unable to obtain signin token.")
|
65
|
+
puts white("#{SIGN_IN_URL} returns #{res.code}")
|
66
|
+
puts res.body
|
67
|
+
exit 1
|
68
|
+
end
|
69
|
+
|
70
|
+
@signin_params = JSON.parse(res.body)
|
71
|
+
end
|
72
|
+
|
73
|
+
def action(browser, incognito, logout)
|
74
|
+
if logout
|
75
|
+
logout(browser, incognito)
|
76
|
+
else
|
77
|
+
login(browser, incognito)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def logout(browser, incognito)
|
82
|
+
go(SIGN_OUT_URL, browser || '', incognito)
|
83
|
+
end
|
84
|
+
|
85
|
+
def login(browser, incognito)
|
86
|
+
act_acc
|
87
|
+
|
88
|
+
if remained_minutes <= 0
|
89
|
+
puts red("Session expired")
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
|
93
|
+
signin_params['Action'] = 'login'
|
94
|
+
signin_params['Destination'] = CONSOLE_URL
|
95
|
+
|
96
|
+
params_str = signin_params.map do |k, v|
|
97
|
+
"#{k}=#{CGI.escape(v.to_s)}"
|
98
|
+
end.join('&')
|
99
|
+
|
100
|
+
console_url = "#{SIGN_IN_URL}?#{params_str}"
|
101
|
+
|
102
|
+
go(console_url, browser || '', incognito)
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
end
|
data/lib/sty/dig.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module RubyDig
|
2
|
+
def dig(key, *rest)
|
3
|
+
value = self[key]
|
4
|
+
if value.nil? || rest.empty?
|
5
|
+
value
|
6
|
+
elsif value.respond_to?(:dig)
|
7
|
+
value.dig(*rest)
|
8
|
+
else
|
9
|
+
fail TypeError, "#{value.class} does not have #dig method"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
if RUBY_VERSION < '2.3'
|
15
|
+
class Array
|
16
|
+
include RubyDig
|
17
|
+
end
|
18
|
+
|
19
|
+
class Hash
|
20
|
+
include RubyDig
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'psych'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
def sty_home
|
5
|
+
home = File.expand_path('~')
|
6
|
+
"#{home}/.sty"
|
7
|
+
end
|
8
|
+
|
9
|
+
def colorize(string, color_code)
|
10
|
+
"\e[#{color_code}m#{string}\e[0m"
|
11
|
+
end
|
12
|
+
|
13
|
+
def red(string)
|
14
|
+
colorize(string, 31)
|
15
|
+
end
|
16
|
+
|
17
|
+
def green(string)
|
18
|
+
colorize(string, 32)
|
19
|
+
end
|
20
|
+
|
21
|
+
def yellow(string)
|
22
|
+
colorize(string, 33)
|
23
|
+
end
|
24
|
+
|
25
|
+
def magenta(string)
|
26
|
+
colorize(string, 35)
|
27
|
+
end
|
28
|
+
|
29
|
+
def white(string)
|
30
|
+
colorize(string, 97)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_path(fqn)
|
34
|
+
[fqn].flatten.map { |a| a.split("/") }.flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_fqn(path)
|
38
|
+
path.join('/')
|
39
|
+
end
|
40
|
+
|
41
|
+
def dir
|
42
|
+
@dir = @dir || sty_home
|
43
|
+
end
|
44
|
+
|
45
|
+
def cache_file(path, identity)
|
46
|
+
"#{dir}/auth-cache/#{path.join('-')}-#{identity}.yaml"
|
47
|
+
end
|
48
|
+
|
49
|
+
def yaml(file)
|
50
|
+
Psych.load_file("#{dir}/#{file}.yaml")
|
51
|
+
end
|
52
|
+
|
53
|
+
def dump(hash, file)
|
54
|
+
File.open("#{dir}/#{file}.yaml", 'w') do |f|
|
55
|
+
f.write(Psych.dump(hash))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def remained_minutes
|
60
|
+
((Time.parse(ENV['AWS_SESSION_EXPIRY']) - Time.now) / 60).to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
def region
|
64
|
+
ENV['AWS_REGION'] || DEFAULT_REGION
|
65
|
+
end
|
66
|
+
|
67
|
+
def act_acc
|
68
|
+
act_acc = ENV['AWS_ACTIVE_ACCOUNT']
|
69
|
+
unless act_acc
|
70
|
+
puts red('ERROR! AWS_ACTIVE_ACCOUNT variable is not set. Is your session authenticated ?')
|
71
|
+
exit 1
|
72
|
+
end
|
73
|
+
act_acc
|
74
|
+
end
|
75
|
+
|
76
|
+
def matches(container, value)
|
77
|
+
container = container.to_s
|
78
|
+
if /#{value}/i =~ container.to_s
|
79
|
+
match = $&
|
80
|
+
container.split(match).insert(1,white(match)).join
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def deep_find(obj, value, result = {}, path = [])
|
85
|
+
if obj.is_a?(Hash)
|
86
|
+
obj.each do |k,v|
|
87
|
+
deep_find(v, value, result, path + [k])
|
88
|
+
end
|
89
|
+
return result
|
90
|
+
else
|
91
|
+
m = matches(obj, value)
|
92
|
+
result[to_fqn(path)] = m if m
|
93
|
+
end
|
94
|
+
end
|
data/lib/sty/info.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'functions'
|
2
|
+
|
3
|
+
class Info
|
4
|
+
|
5
|
+
def session_info
|
6
|
+
if ENV['AWS_ACTIVE_ACCOUNT']
|
7
|
+
puts "Active account: #{white(ENV['AWS_ACTIVE_ACCOUNT'])}"
|
8
|
+
else
|
9
|
+
puts red("You are not authenticated with sty")
|
10
|
+
end
|
11
|
+
|
12
|
+
if ENV['AWS_ACTIVE_IDENTITY']
|
13
|
+
puts "Active identity: #{white(ENV['AWS_ACTIVE_IDENTITY'])}"
|
14
|
+
end
|
15
|
+
|
16
|
+
if ENV['AWS_SESSION_EXPIRY']
|
17
|
+
if remained_minutes > 0
|
18
|
+
puts "Session active, expires in #{white(remained_minutes)} min."
|
19
|
+
else
|
20
|
+
puts red("Session expired")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def account_info(partial)
|
27
|
+
|
28
|
+
config = yaml('auth')
|
29
|
+
|
30
|
+
puts "Searching config for '#{partial}':"
|
31
|
+
result = deep_find(config, partial)
|
32
|
+
|
33
|
+
if result.any?
|
34
|
+
result.each do |k, v|
|
35
|
+
puts "#{k}: #{v}"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
puts 'Nothing found'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/sty/keychain.rb
ADDED
data/lib/sty/proxy.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative 'functions'
|
2
|
+
|
3
|
+
class Proxy
|
4
|
+
|
5
|
+
def config
|
6
|
+
@config = @config || yaml('proxy')
|
7
|
+
end
|
8
|
+
|
9
|
+
def proxy_vars
|
10
|
+
ENV.select { |e| e =~ /(https?|no)_proxy/i }
|
11
|
+
end
|
12
|
+
|
13
|
+
def unset
|
14
|
+
proxy_vars.keys.map do |e|
|
15
|
+
"unset #{e}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def set(px)
|
20
|
+
proxy = config[px]
|
21
|
+
|
22
|
+
unless proxy
|
23
|
+
STDERR.puts red("ERROR! Proxy #{px} was not found in the config file.")
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
STDERR.puts "Proxy is set to #{proxy['proxy']}"
|
28
|
+
["export http_proxy=#{proxy['proxy']}",
|
29
|
+
"export https_proxy=#{proxy['proxy']}",
|
30
|
+
"export no_proxy=#{proxy['no-proxy']}"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def output(strings)
|
34
|
+
puts "#EVAL#"
|
35
|
+
strings.each do |s|
|
36
|
+
puts "#{s};"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def action(px)
|
41
|
+
case
|
42
|
+
when px.nil?
|
43
|
+
STDERR.puts "Current proxy vars:"
|
44
|
+
proxy_vars.each do |k,v|
|
45
|
+
STDERR.puts "#{k}=#{v}"
|
46
|
+
end
|
47
|
+
when px =~ /off/i
|
48
|
+
STDERR.puts "Proxy vars unset"
|
49
|
+
output(unset)
|
50
|
+
else
|
51
|
+
output(unset + set(px))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/sty/ssh.rb
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
require_relative 'functions'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class Ssh
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
require 'aws-sdk-ec2'
|
8
|
+
Aws.config.update(:http_proxy => ENV['https_proxy'])
|
9
|
+
end
|
10
|
+
|
11
|
+
def all_instances
|
12
|
+
instances = []
|
13
|
+
options = {}
|
14
|
+
|
15
|
+
loop do
|
16
|
+
resp = ec2.describe_instances(options)
|
17
|
+
instances += resp.reservations.map { |r| r.instances }.flatten
|
18
|
+
break unless resp.next_token
|
19
|
+
options[:next_token] = resp.next_token
|
20
|
+
end
|
21
|
+
|
22
|
+
instances
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_key_file?(key_name, key_file)
|
26
|
+
aws_fp = ec2.describe_key_pairs(key_names: [key_name]).key_pairs[0].key_fingerprint
|
27
|
+
calculated_fp = `openssl pkcs8 -in #{key_file} -nocrypt -topk8 -outform DER | openssl sha1 -c`.chomp
|
28
|
+
aws_fp == calculated_fp
|
29
|
+
end
|
30
|
+
|
31
|
+
def instance_id(instance)
|
32
|
+
instance.instance_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def instance_name(instance)
|
36
|
+
name_tag = instance.tags.select { |t| t.key == 'Name' }.first
|
37
|
+
name_tag ? name_tag.value : "None"
|
38
|
+
end
|
39
|
+
|
40
|
+
def instance_ips(instance)
|
41
|
+
instance.network_interfaces.map { |n| n.private_ip_address }
|
42
|
+
end
|
43
|
+
|
44
|
+
def extract_fields(inst)
|
45
|
+
[instance_name(inst), instance_id(inst)] + instance_ips(inst)
|
46
|
+
end
|
47
|
+
|
48
|
+
def prepare_regex(names)
|
49
|
+
names = ['.'] if names.empty?
|
50
|
+
names.map { |n| Regexp.new(Regexp.quote(n), Regexp::IGNORECASE) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def find(instances, names)
|
54
|
+
re = prepare_regex(names)
|
55
|
+
instances.select do |i|
|
56
|
+
i.state.name == 'running' &&
|
57
|
+
extract_fields(i).any? { |f| re.all? { |r| f =~ r } }
|
58
|
+
end.sort{|a,b| instance_name(a) <=> instance_name(b)}
|
59
|
+
end
|
60
|
+
|
61
|
+
def win?(instance)
|
62
|
+
instance.platform =~ /windows/i
|
63
|
+
end
|
64
|
+
|
65
|
+
def platform(instance)
|
66
|
+
win?(instance) ? " [Win] " : ""
|
67
|
+
end
|
68
|
+
|
69
|
+
def print_refine_instances(instances, type)
|
70
|
+
puts "Please refine #{type} instance:"
|
71
|
+
instances.each_with_index do |inst, idx|
|
72
|
+
puts "#{idx}: #{instance_id(inst)} [#{instance_name(inst)}] #{platform(inst)}(#{instance_ips(inst).join(', ')}) "
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def print_refine_ips(ips)
|
77
|
+
puts 'Please refine IP address:'
|
78
|
+
ips.each_with_index do |ip, idx|
|
79
|
+
puts "#{idx}: #{ip}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#Not used anymore
|
84
|
+
def print_refine_keys(keys)
|
85
|
+
puts 'Please refine key:'
|
86
|
+
keys.each_with_index do |key, idx|
|
87
|
+
puts "#{idx}: #{key}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def find_path(hash, path)
|
92
|
+
path.split('/').reduce(hash) { |memo, path| memo[path] if memo}
|
93
|
+
end
|
94
|
+
|
95
|
+
def path?(str)
|
96
|
+
str =~ /\//
|
97
|
+
end
|
98
|
+
|
99
|
+
def path_error(path)
|
100
|
+
puts red("ERROR ! No jumphost found for #{path}")
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
|
104
|
+
def config
|
105
|
+
@config = @config || yaml('ec2')
|
106
|
+
end
|
107
|
+
|
108
|
+
def ec2
|
109
|
+
@ec2 = @ec2 || Aws::EC2::Client.new
|
110
|
+
end
|
111
|
+
|
112
|
+
def auth_config
|
113
|
+
@auth_config = @auth_config || yaml('auth-keys')
|
114
|
+
end
|
115
|
+
|
116
|
+
def username
|
117
|
+
auth_config['ec2-username'] || auth_config['username']
|
118
|
+
end
|
119
|
+
|
120
|
+
def key_dir
|
121
|
+
ssh_keys = auth_config['ssh-keys']
|
122
|
+
ssh_keys = "#{dir}/#{ssh_keys}" unless ssh_keys =~ /^\/|^~/
|
123
|
+
ssh_keys
|
124
|
+
end
|
125
|
+
|
126
|
+
def refine(found)
|
127
|
+
if found.size > 1
|
128
|
+
refine = nil
|
129
|
+
loop do
|
130
|
+
yield(found)
|
131
|
+
refine = Integer(STDIN.gets.chomp) rescue false
|
132
|
+
break if refine && refine < found.size
|
133
|
+
end
|
134
|
+
target = found[refine]
|
135
|
+
else
|
136
|
+
target = found.first
|
137
|
+
end
|
138
|
+
target
|
139
|
+
end
|
140
|
+
|
141
|
+
def find_jumphost_from_config(act_acc, platform)
|
142
|
+
jumphosts = find_path(config, act_acc)
|
143
|
+
|
144
|
+
unless jumphosts
|
145
|
+
puts red("No jumphost configured for #{act_acc}")
|
146
|
+
exit 1
|
147
|
+
end
|
148
|
+
|
149
|
+
path_error(act_acc) unless jumphosts
|
150
|
+
|
151
|
+
if path?(jumphosts)
|
152
|
+
jumphost_path = jumphosts
|
153
|
+
jumphosts = find_path(config, jumphost_path)
|
154
|
+
end
|
155
|
+
|
156
|
+
path_error(jumphost_path) unless jumphosts
|
157
|
+
|
158
|
+
jumphosts[platform]
|
159
|
+
end
|
160
|
+
|
161
|
+
def find_instance(args, type)
|
162
|
+
found = find(all_instances, args)
|
163
|
+
if found.empty?
|
164
|
+
puts "No instances found for search terms: #{args.join(', ')}"
|
165
|
+
exit 1
|
166
|
+
end
|
167
|
+
target = refine(found) {|found| print_refine_instances(found, type)}
|
168
|
+
ip = refine(instance_ips(target)) {|found| print_refine_ips(found)}
|
169
|
+
OpenStruct.new(ip: ip,
|
170
|
+
platform: win?(target) ? 'windows' : 'linux',
|
171
|
+
key_name: target.key_name)
|
172
|
+
end
|
173
|
+
|
174
|
+
def find_key(key_name)
|
175
|
+
|
176
|
+
keys_glob = Dir.glob("#{key_dir}/**/#{key_name}.pem")
|
177
|
+
|
178
|
+
if keys_glob.size < 1
|
179
|
+
puts red("ERROR! Unable to find key #{key_name}.pem within #{key_dir}")
|
180
|
+
exit 1
|
181
|
+
end
|
182
|
+
|
183
|
+
key = keys_glob.detect do |key_file|
|
184
|
+
valid_key_file?(key_name,key_file)
|
185
|
+
end
|
186
|
+
|
187
|
+
unless key
|
188
|
+
puts red("ERROR! There is no key file with matching fingerprint")
|
189
|
+
exit 1
|
190
|
+
end
|
191
|
+
|
192
|
+
key
|
193
|
+
end
|
194
|
+
|
195
|
+
def print_command(cmd)
|
196
|
+
puts "Generated command:\n------------------------\n#{cmd}"
|
197
|
+
puts '------------------------'
|
198
|
+
end
|
199
|
+
|
200
|
+
def connect(search, no_jumphost, jumphost_override, target_key)
|
201
|
+
|
202
|
+
no_strict = "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
203
|
+
server_alive = "-o ServerAliveInterval=25"
|
204
|
+
ec2_user = 'ec2-user'
|
205
|
+
|
206
|
+
opts = []
|
207
|
+
opts << 'no_jumphost' if no_jumphost
|
208
|
+
opts << 'select_jumphost' if jumphost_override
|
209
|
+
opts << 'use_key' if target_key
|
210
|
+
puts "Enabled options: #{opts.join(', ')}"
|
211
|
+
puts "Requested search terms: #{search.join(', ')}"
|
212
|
+
|
213
|
+
puts "Active account: #{act_acc}"
|
214
|
+
|
215
|
+
instance = find_instance(search, 'target')
|
216
|
+
|
217
|
+
if instance.platform == 'windows'
|
218
|
+
|
219
|
+
# username=s:#{username}
|
220
|
+
#
|
221
|
+
jumphost = find_jumphost_from_config(act_acc, instance.platform)
|
222
|
+
cmd = %W(
|
223
|
+
rdp://gatewayusagemethod:i:1
|
224
|
+
gatewaycredentialssource:i:4
|
225
|
+
gatewayprofileusagemethod:i:1
|
226
|
+
promptcredentialonce:i:0
|
227
|
+
gatewaybrokeringtype:i:0
|
228
|
+
|
229
|
+
gatewayhostname=s:#{jumphost}
|
230
|
+
full\ address=s:#{instance.ip}
|
231
|
+
)
|
232
|
+
cmd = URI.escape(cmd.join('&'))
|
233
|
+
cmd = "open \"#{cmd}\""
|
234
|
+
|
235
|
+
else
|
236
|
+
|
237
|
+
proxy = ''
|
238
|
+
unless no_jumphost
|
239
|
+
|
240
|
+
if jumphost_override
|
241
|
+
puts 'Type jumphost search terms:'
|
242
|
+
jumphost_query = STDIN.gets.chomp
|
243
|
+
jh_instance = find_instance([jumphost_query], 'jumphost')
|
244
|
+
jh_key = find_key(jh_instance.key_name)
|
245
|
+
jh_string = "-i #{jh_key} #{ec2_user}@#{jh_instance.ip}"
|
246
|
+
else
|
247
|
+
jumphost = find_jumphost_from_config(act_acc, instance.platform)
|
248
|
+
jh_string = "#{username}@#{jumphost}"
|
249
|
+
end
|
250
|
+
|
251
|
+
proxy = "-o ProxyCommand='ssh #{server_alive} #{no_strict} #{jh_string} nc #{instance.ip} 22'"
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
if target_key
|
256
|
+
key = find_key(instance.key_name)
|
257
|
+
target_string = "-i #{key} #{ec2_user}@#{instance.ip}"
|
258
|
+
else
|
259
|
+
target_string = "#{username}@#{instance.ip}"
|
260
|
+
end
|
261
|
+
|
262
|
+
cmd = "ssh #{proxy} #{no_strict} #{server_alive} #{target_string}"
|
263
|
+
|
264
|
+
end
|
265
|
+
print_command(cmd)
|
266
|
+
exec cmd
|
267
|
+
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|