Centralized and reliable SSH client configuration
SSH'ing into several VMs in a daily basics can be challenging and error-prone. In most cases you have to remember a bunch of different options: ips/domains, users, ports, ciphers… It’s hard to be updated when servers are added/removed and the SSH tunneling commands are easy to forget. At Zaleos we try to minimize errors by adopting good practices or well-defined strategies. In this blog post, we’re going to share the solution we adopted to efficiently sharing SSH client configuration within our team.
1. The SSH Config file
Is the key of our setup. You can configure the SSH options you want to use using the SSH Config file, which is usually stored in your home folder. At Zaleos, we use the config.d
folder: ~/.ssh/config.d/
. This allows the user to have more than one config.This great tutorial explains pretty well the main magic behind the SSH Config file. In our case, we have a strict naming convention which we all follow. It starts with zaleos
and then it covers the networking logic based on subnets (dev, qa, …). This categorization helps to quickly trigger BASH autocompletion and start typing where you want to SSH into.SSH Basic Configuration
Zaleos file
- This is a basic Zaleos SSH Configuration item.
- Stored at:
~/.ssh/config.d/zaleos.config
Host zaleos_dev_git1*
HostName git1.dev.zaleos.net
Port 1111
Host zaleos_dev_git1_ROOT
Host zaleos_dev_git2*
HostName git2.dev.zaleos.net
Port 2222
Host zaleos_dev_git2_ROOT
Host zaleos_dev_git2_ATLSTASH
Host zaleos_*_ATLSTASH
User atlstash
Host zaleos_*_ROOT
User root
As you may already know, this configuration makes two following two set of commands identical:
$ ssh -p 1111 root@git1.dev.zaleos.net
$ ssh -p 2222 root@git2.dev.zaleos.net
$ ssh -p 2222 atlstash@git2.dev.zaleos.net
$ ssh zaleos_dev_git1_ATLSTASH
$ ssh zaleos_dev_git2_ROOT
$ ssh zaleos_dev_git2_ATLSTASH
Personal
- This is a basic Personal SSH Configuration item.
- Stored at:
~/.ssh/config.d/zzz.personal.config
Host solete_nas*
ForwardAgent yes
Host solete_nas1_*
HostName 192.168.0.10
Host solete_nas1_BAR
Host solete_nas1_FOO
Host solete_nas2_*
HostName 192.168.0.20
Host solete_nas2_BAR
Host solete_nas2_FOO
Host solete_*_BAR
User bar
Host solete_*_FOO
User foo
Host *
Port 22
Compression yes
CompressionLevel 9
Ciphers aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
ConnectionAttempts 1
TCPKeepAlive no
ServerAliveCountMax 500
ServerAliveInterval 10
This configuration has a default wildcard (*), which actually sets the defaults to be applied.
2. Sharing the SSH config file
It’s very important this file to be centralized and version controlled. We store it in a internal git repo with the proper permissions. In our case, just the admins can edit this file. We all have a predefined functions in our .bashrc
,
update_ssh_config() {
conf_file_dir="http://git.zaleos.net/projects/myrepo/ssh/zaleos.config?raw"
mkdir -p ~/.ssh/config.d
curl -o ~/.ssh/config.d/zaleos.config ${conf_file_dir}
cat ~/.ssh/config.d/* > ~/.ssh/config
chmod 600 ~/.ssh/config
}
This function:
- Gets the latest
zaleos.config
from the repo and stores it in the~/.ssh/config.d/
folder. - Generates a new
~/.ssh/config
file from all the files stored in the~/.ssh/config.d/
folder (alphabetical order).
3. Complex SSH requirements
Let’s imagine we don’t reach a server called unaccessible, but we can get into a server called accessible which reaches the unaccessible one.
3.a) SSH Proxying
We need to SSH into the unaccessible one. In this case we can easily configure a ProxyCommand as follows:
Host zaleos_accessible*
HostName accessible.zaleos.net
Host zaleos_accessible_ROOT
Host zaleos_unaccessible*
HostName unaccessible.zaleos.net
Host zaleos_unaccessible_MYCOOL_BRIDGE_ROOT
Host zaleos_*_MYCOOL_BRIDGE*
ProxyCommand ssh zaleos_accessible_ROOT nc %h %p
Host zaleos_*_ROOT
User root
$ ssh zaleos_accessible_ROOT
$ # this gets us into the accessible server
$ ssh zaleos_unaccessible_MYCOOL_BRIDGE_ROOT
$ # this gets us into the unaccessible server (through the accessible one)
3.b) SSH Forwarding
We need reach the port 80
of the unaccessible as if it were local port 40080
. In this case we can easily configure a LocalForward as follows:
Host zaleos_tunnel_accessible_FOOBAR
HostName accessible.zaleos.net
LocalForward localhost:40080 unaccessible.zaleos.net:80
Host zaleos_*_FOOBAR
User foobar
$ ssh zaleos_tunnel_accessible_FOOBAR
$ # don't close this SSH connection until done
$ telnet 127.0.0.1 40080
$ # Or open the browser 127.0.0.1:40080 ;-)
4. Conclusions
This post shares the knowledge and technique used at Zaleos to be better. The mix of simple configuration files with the complex ones commented is a very powerful tool to SSH into boxes.
As you can see, launching our SSH config BASH function and then typing ssh <TAB>
is a very efficient way to reach our destination. Happy SSHing! ;-)
$ update_ssh_config # just when network changes
$ # Open new terminal or source file
$ ssh <TAB>
solete_nas1_BAR
solete_nas1_FOO
solete_nas2_BAR
solete_nas2_FOO
zaleos_dev_git1_ROOT
zaleos_dev_git2_ATLSTASH
zaleos_dev_git2_ROOT
zaleos_accessible_ROOT
zaleos_tunnel_accessible_FOOBAR
zaleos_unaccessible_MYCOOL_BRIDGE_ROOT
...