sty 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|