Skip to content

Instantly share code, notes, and snippets.

Created February 16, 2019 21:31
Show Gist options
  • Save Skarlso/34321a230cf0245018288686c9e70b2d to your computer and use it in GitHub Desktop.
Save Skarlso/34321a230cf0245018288686c9e70b2d to your computer and use it in GitHub Desktop.
Golang SSH connection with hostkey verification
package main
import (
kh ""
func main() {
user := "user"
address := ""
command := "uptime"
port := "9999"
key, err := ioutil.ReadFile("/Users/user/.ssh/id_rsa")
if err != nil {
log.Fatalf("unable to read private key: %v", err)
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatalf("unable to parse private key: %v", err)
hostKeyCallback, err := kh.New("/Users/user/.ssh/known_hosts")
if err != nil {
log.Fatal("could not create hostkeycallback function: ", err)
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
// Add in password check here for moar security.
HostKeyCallback: hostKeyCallback,
// Connect to the remote server and perform the SSH handshake.
client, err := ssh.Dial("tcp", address+":"+port, config)
if err != nil {
log.Fatalf("unable to connect: %v", err)
defer client.Close()
ss, err := client.NewSession()
if err != nil {
log.Fatal("unable to create SSH session: ", err)
defer ss.Close()
// Creating the buffer which will hold the remotly executed command's output.
var stdoutBuf bytes.Buffer
ss.Stdout = &stdoutBuf
// Let's print out the result of command.
Copy link

xpufx commented Sep 23, 2020

This is the only implementation I could find that actually has known_hosts checks enabled AND can parse hashed hostname in known_hosts. Thanks!

Most github libraries/wrappers either seem to have disabled the check or are using an example from the docs that doesn't consider hashed hostnames/ips.

(I still had a lot of issues to get it going but those turned out to be some sort of duplicate host keys for the ip/host in question) Since ssh itself works fine in that setup, crypto/ssh/knownhosts probably should too.

Might be a tiny bit more useful if you use a variable for 'user' and get env(HOME) to reach known_hosts and id_rsa etc.

Copy link

Skarlso commented Sep 23, 2020

@oktayaa Hey!

Right? I don't know why anyone would dismiss checking known_hosts especially since pretty much the defence against MITM attacks.

Of course this could be a lot better with variables, but I'll leave that to the user. :) The point was to demonstrate the check it self. :)

Glad you find it useful!

Copy link

steffakasid commented Nov 20, 2021

Does this only work if the hostkey is already added in known_hosts? How would it be possible to write new hosts into the known_hosts file?

I used ssh-keyscan > known_hosts and it works quite well. It also already adds all keys from the server which works quite well. Not sure if there would be also a solution to do this in my golang program.

Copy link

Skarlso commented Nov 21, 2021

@steffakasid Hey! That's a good call.

Yes, there are a couple solutions out there to do an ssh-keyscan, but basically, you can just do a call with TCP.

Here is a more convoluted example:

And here is one that just does a TCP call and returns the output:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment