Validating host keys in Go's ssh package
Sep 2017    |    golang     ssh     hostkey     HostKeyCallback    

So you upgraded the package: go get -u -v

and got an error: ssh: must specify HostKeyCallback

A quick google search returns this great post Golang SSH Security, as well as issue#19767 and e4e2799.

Briefly, prior to the patch users could omit ssh.HostKeyCallback from ssh.ClientConfig, allowing SSH connections to bypass host key checking and “just work”.

Given the onus is on the client to verify the identity of the host, this was a step in the right direction in terms of security. E.g., MITM attack

For sake of clarity, neither Go or the docs had issues. It was users misusing the library.

So what can you do?

1.use ssh.InsecureIgnoreHostKey(), allowing almost any host key to be used.

It should not be used for production code.

2.use ssh.FixedHostKey() and pass in a key from known_hosts file, typically $HOME/.ssh/known_hosts

For an example check out ExampleHostKeyCheck(), which assumes standard port

Some gotchas, if you have many hosts with varying ports on a single domain or IP address the above snippet will match the first occurrence, return an incorrect host key to the caller and ssh.Dial() will eventually fail:

ssh: handshake failed: ssh: host key mismatch

Another issue is if you have many hosts to check, you don’t want the entire program to exit due to a single failed host key check, watch out for log.Fatalf which is Printf() followed by call to os.Exit(1)

Furthermore, for non-standard ports you’ll need to modify the above snippet. Because non-standard ports have hostnames enclosed with square brackets followed by a colon and the port number:

[]:1999 ssh-rsa AAAAB3Nza...vguvx+81N1xaw==
[]:1999,[]:1999 ssh-rsa AAAAB3Nza...vguvx+81N1xaw==

A slightly different approach may be to validate the port: validatePort()

port, err := validatePort(SSHport)
if err != nil {
    // handle error

Then pass hostname & port into a slightly modified ExampleHostKeyCheck function: checkHostKey()

hostKey, err := checkHostKey(hostname, port)
if err != nil {
    // handle error

Initialize ssh.ClientConfig and set HostKeyCallback with ssh.FixedHostKey(hostKey)

// this is an example
conf := &ssh.ClientConfig{
    User: username,
    Auth: []ssh.AuthMethod{
    HostKeyCallback: ssh.FixedHostKey(hostKey),
    Timeout: 2 * time.Second,

Once the bits and pieces are in place attempt to connect to the remote server and perform an SSH handshake

client, err := ssh.Dial("tcp", hostname+":"+port, conf)

At each step prior to ssh.Dial() errors can be handled gracefully.