hjr265.me / blog /

Generate SSH Known Hosts in Terraform

I manage Toph’s infrastructure with Terraform. The setup is as multi-cloud as it gets. Beyond Terraform, I have several Ansible Playbooks for configuring and upkeeping the infrastructure.

Something that I wanted to do with Terraform was to generate an SSH known_hosts file ahead of time as any changes are applied to the infrastructure. There isn’t a straightforward way to do that in Terraform. But the workaround is simple too.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
locals {
  ssh_hosts = merge(
    [for i, v in vultr_instance.servers : { host = v.main_ip, port = 22 }],
    [for i, v in linode_instance.servers : { host = v.ip_address, port = 22 }],
    # ...
  )
}

resource "null_resource" "known_hosts" {
  provisioner "local-exec" {
    command = <<EOT
  rm -f known_hosts;
%{ for i, host in local.ssh_hosts }
  ssh-keyscan -p ${host.port} ${host.host} >> known_hosts;
%{ endfor ~}
EOT
    interpreter = ["/bin/bash", "-c"]
  }
}

All you need to do is put all your SSH hostnames/addresses and ports in a local variable. And, then use a local-exec provisioner in a null_resource to run ssh-keyscan for each host, appending the output to a “known_hosts” file.

Note that our local ssh_hosts variable is a list of objects. Each object has the key host and port. We use these values as a part of our ssh-keyscan command:

ssh-keyscan -p ${host.port} ${host.host} >> known_hosts;

We loop over all the hosts and run this command once for each host.

Terraform uses /bin/sh as the interpreter on Linux. But in this case, we need to use Bash or equivalent to be able to run this script.


This post is 21st of my #100DaysToOffload challenge. Want to get involved? Find out more at 100daystooffload.com.


comments powered by Disqus