Class: Ssh
- Inherits:
-
Object
- Object
- Ssh
- Defined in:
- lib/sty/ssh.rb
Instance Method Summary collapse
- #all_instances ⇒ Object
- #auth_config ⇒ Object
- #config ⇒ Object
- #connect(search, no_jumphost, jumphost_override, target_key) ⇒ Object
- #ec2 ⇒ Object
- #extract_fields(inst) ⇒ Object
- #find(instances, names) ⇒ Object
- #find_instance(args, type) ⇒ Object
- #find_jumphost_from_config(act_acc, platform) ⇒ Object
- #find_key(key_name) ⇒ Object
- #find_path(hash, path) ⇒ Object
-
#initialize ⇒ Ssh
constructor
A new instance of Ssh.
- #instance_id(instance) ⇒ Object
- #instance_ips(instance) ⇒ Object
- #instance_name(instance) ⇒ Object
- #key_dir ⇒ Object
- #path?(str) ⇒ Boolean
- #path_error(path) ⇒ Object
- #platform(instance) ⇒ Object
- #prepare_regex(names) ⇒ Object
- #print_command(cmd) ⇒ Object
- #print_refine_instances(instances, type) ⇒ Object
- #print_refine_ips(ips) ⇒ Object
-
#print_refine_keys(keys) ⇒ Object
Not used anymore.
- #refine(found) ⇒ Object
- #username ⇒ Object
- #valid_key_file?(key_name, key_file) ⇒ Boolean
- #win?(instance) ⇒ Boolean
Constructor Details
#initialize ⇒ Ssh
Returns a new instance of Ssh.
6 7 8 9 |
# File 'lib/sty/ssh.rb', line 6 def initialize require 'aws-sdk-ec2' Aws.config.update(:http_proxy => ENV['https_proxy']) end |
Instance Method Details
#all_instances ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/sty/ssh.rb', line 11 def all_instances instances = [] = {} loop do resp = ec2.describe_instances() instances += resp.reservations.map { |r| r.instances }.flatten break unless resp.next_token [:next_token] = resp.next_token end instances end |
#auth_config ⇒ Object
112 113 114 |
# File 'lib/sty/ssh.rb', line 112 def auth_config @auth_config = @auth_config || yaml('auth-keys') end |
#config ⇒ Object
104 105 106 |
# File 'lib/sty/ssh.rb', line 104 def config @config = @config || yaml('ec2') end |
#connect(search, no_jumphost, jumphost_override, target_key) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/sty/ssh.rb', line 200 def connect(search, no_jumphost, jumphost_override, target_key) no_strict = "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" server_alive = "-o ServerAliveInterval=25" ec2_user = 'ec2-user' opts = [] opts << 'no_jumphost' if no_jumphost opts << 'select_jumphost' if jumphost_override opts << 'use_key' if target_key puts "Enabled options: #{opts.join(', ')}" puts "Requested search terms: #{search.join(', ')}" puts "Active account: #{act_acc}" instance = find_instance(search, 'target') if instance.platform == 'windows' # username=s:#{username} # jumphost = find_jumphost_from_config(act_acc, instance.platform) cmd = %W( rdp://gatewayusagemethod:i:1 gatewaycredentialssource:i:4 gatewayprofileusagemethod:i:1 promptcredentialonce:i:0 gatewaybrokeringtype:i:0 gatewayhostname=s:#{jumphost} full\ address=s:#{instance.ip} ) cmd = URI.escape(cmd.join('&')) cmd = "open \"#{cmd}\"" else proxy = '' unless no_jumphost if jumphost_override puts 'Type jumphost search terms:' jumphost_query = STDIN.gets.chomp jh_instance = find_instance([jumphost_query], 'jumphost') jh_key = find_key(jh_instance.key_name) jh_string = "-i #{jh_key} #{ec2_user}@#{jh_instance.ip}" else jumphost = find_jumphost_from_config(act_acc, instance.platform) jh_string = "#{username}@#{jumphost}" end proxy = "-o ProxyCommand='ssh #{server_alive} #{no_strict} #{jh_string} nc #{instance.ip} 22'" end if target_key key = find_key(instance.key_name) target_string = "-i #{key} #{ec2_user}@#{instance.ip}" else target_string = "#{username}@#{instance.ip}" end cmd = "ssh #{proxy} #{no_strict} #{server_alive} #{target_string}" end print_command(cmd) exec cmd end |
#ec2 ⇒ Object
108 109 110 |
# File 'lib/sty/ssh.rb', line 108 def ec2 @ec2 = @ec2 || Aws::EC2::Client.new end |
#extract_fields(inst) ⇒ Object
44 45 46 |
# File 'lib/sty/ssh.rb', line 44 def extract_fields(inst) [instance_name(inst), instance_id(inst)] + instance_ips(inst) end |
#find(instances, names) ⇒ Object
53 54 55 56 57 58 59 |
# File 'lib/sty/ssh.rb', line 53 def find(instances, names) re = prepare_regex(names) instances.select do |i| i.state.name == 'running' && extract_fields(i).any? { |f| re.all? { |r| f =~ r } } end.sort{|a,b| instance_name(a) <=> instance_name(b)} end |
#find_instance(args, type) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/sty/ssh.rb', line 161 def find_instance(args, type) found = find(all_instances, args) if found.empty? puts "No instances found for search terms: #{args.join(', ')}" exit 1 end target = refine(found) {|found| print_refine_instances(found, type)} ip = refine(instance_ips(target)) {|found| print_refine_ips(found)} OpenStruct.new(ip: ip, platform: win?(target) ? 'windows' : 'linux', key_name: target.key_name) end |
#find_jumphost_from_config(act_acc, platform) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/sty/ssh.rb', line 141 def find_jumphost_from_config(act_acc, platform) jumphosts = find_path(config, act_acc) unless jumphosts puts red("No jumphost configured for #{act_acc}") exit 1 end path_error(act_acc) unless jumphosts if path?(jumphosts) jumphost_path = jumphosts jumphosts = find_path(config, jumphost_path) end path_error(jumphost_path) unless jumphosts jumphosts[platform] end |
#find_key(key_name) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/sty/ssh.rb', line 174 def find_key(key_name) keys_glob = Dir.glob("#{key_dir}/**/#{key_name}.pem") if keys_glob.size < 1 puts red("ERROR! Unable to find key #{key_name}.pem within #{key_dir}") exit 1 end key = keys_glob.detect do |key_file| valid_key_file?(key_name,key_file) end unless key puts red("ERROR! There is no key file with matching fingerprint") exit 1 end key end |
#find_path(hash, path) ⇒ Object
91 92 93 |
# File 'lib/sty/ssh.rb', line 91 def find_path(hash, path) path.split('/').reduce(hash) { |memo, path| memo[path] if memo} end |
#instance_id(instance) ⇒ Object
31 32 33 |
# File 'lib/sty/ssh.rb', line 31 def instance_id(instance) instance.instance_id end |
#instance_ips(instance) ⇒ Object
40 41 42 |
# File 'lib/sty/ssh.rb', line 40 def instance_ips(instance) instance.network_interfaces.map { |n| n.private_ip_address } end |
#instance_name(instance) ⇒ Object
35 36 37 38 |
# File 'lib/sty/ssh.rb', line 35 def instance_name(instance) name_tag = instance..select { |t| t.key == 'Name' }.first name_tag ? name_tag.value : "None" end |
#key_dir ⇒ Object
120 121 122 123 124 |
# File 'lib/sty/ssh.rb', line 120 def key_dir ssh_keys = auth_config['ssh-keys'] ssh_keys = "#{dir}/#{ssh_keys}" unless ssh_keys =~ /^\/|^~/ ssh_keys end |
#path?(str) ⇒ Boolean
95 96 97 |
# File 'lib/sty/ssh.rb', line 95 def path?(str) str =~ /\// end |
#path_error(path) ⇒ Object
99 100 101 102 |
# File 'lib/sty/ssh.rb', line 99 def path_error(path) puts red("ERROR ! No jumphost found for #{path}") exit 1 end |
#platform(instance) ⇒ Object
65 66 67 |
# File 'lib/sty/ssh.rb', line 65 def platform(instance) win?(instance) ? " [Win] " : "" end |
#prepare_regex(names) ⇒ Object
48 49 50 51 |
# File 'lib/sty/ssh.rb', line 48 def prepare_regex(names) names = ['.'] if names.empty? names.map { |n| Regexp.new(Regexp.quote(n), Regexp::IGNORECASE) } end |
#print_command(cmd) ⇒ Object
195 196 197 198 |
# File 'lib/sty/ssh.rb', line 195 def print_command(cmd) puts "Generated command:\n------------------------\n#{cmd}" puts '------------------------' end |
#print_refine_instances(instances, type) ⇒ Object
69 70 71 72 73 74 |
# File 'lib/sty/ssh.rb', line 69 def print_refine_instances(instances, type) puts "Please refine #{type} instance:" instances.each_with_index do |inst, idx| puts "#{idx}: #{instance_id(inst)} [#{instance_name(inst)}] #{platform(inst)}(#{instance_ips(inst).join(', ')}) " end end |
#print_refine_ips(ips) ⇒ Object
76 77 78 79 80 81 |
# File 'lib/sty/ssh.rb', line 76 def print_refine_ips(ips) puts 'Please refine IP address:' ips.each_with_index do |ip, idx| puts "#{idx}: #{ip}" end end |
#print_refine_keys(keys) ⇒ Object
Not used anymore
84 85 86 87 88 89 |
# File 'lib/sty/ssh.rb', line 84 def print_refine_keys(keys) puts 'Please refine key:' keys.each_with_index do |key, idx| puts "#{idx}: #{key}" end end |
#refine(found) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/sty/ssh.rb', line 126 def refine(found) if found.size > 1 refine = nil loop do yield(found) refine = Integer(STDIN.gets.chomp) rescue false break if refine && refine < found.size end target = found[refine] else target = found.first end target end |
#username ⇒ Object
116 117 118 |
# File 'lib/sty/ssh.rb', line 116 def username auth_config['ec2-username'] || auth_config['username'] end |
#valid_key_file?(key_name, key_file) ⇒ Boolean
25 26 27 28 29 |
# File 'lib/sty/ssh.rb', line 25 def valid_key_file?(key_name, key_file) aws_fp = ec2.describe_key_pairs(key_names: [key_name]).key_pairs[0].key_fingerprint calculated_fp = `openssl pkcs8 -in #{key_file} -nocrypt -topk8 -outform DER | openssl sha1 -c`.chomp aws_fp == calculated_fp end |
#win?(instance) ⇒ Boolean
61 62 63 |
# File 'lib/sty/ssh.rb', line 61 def win?(instance) instance.platform =~ /windows/i end |