A sysadmin talks OpenSSH tips and tricks
Posted on Tuesday, 7 February 2012
My take on more advanced SSH usage
I've seen a few articles recently on sites like HackerNews which claimed to cover some advanced SSH techniques/tricks. They were good articles, but for me (as a systems administrator) didn't get into the really powerful guts of OpenSSH.
So, I figured that I ought to pony up and write about some of the more advanced tricks that I have either used or seen others use. These will most likely be relevant to people who manage tens/hundreds of servers via SSH. Some of them are about actual configuration options for OpenSSH, others are recommendations for ways of working with OpenSSH.
Generate your ~/.ssh/config
This isn't strictly an OpenSSH trick, but it's worth noting. If you have other sources of knowledge about your systems, automation can do a lot of the legwork for you in creating an SSH config. A perfect example here would be if you have some kind of database which knows about all your servers - you can use that to produce a fragment of an SSH config, then download it to your workstation and concatenate it with various other fragments into a final config. If you mix this with distributed version control, your entire team can share a broadly identical SSH config, with allowance for each person to have a personal fragment for their own preferences and personal hosts. I can't recommend this sort of collaborative working enough.
Generate your ~/.ssh/known_hosts
This follows on from the previous item. If you have some kind of database of servers, teach it the SSH host key of each (usually something like /etc/ssh/ssh_host_rsa_key.pub) then you can export a file with the keys and hostnames in the correct format to use as a known_hosts file, e.g.:
server1.company.com 10.0.0.101 ssh-rsa BLAHBLAHCRYPTOMUMBOYou can then associate this with all the relevant hosts by including something like this in your ~/.ssh/config:
Host *.mycompany.comThis brings some serious advantages:
UserKnownHostsFile ~/.ssh/generated_known_hosts
StrictHostKeyChecking yes
- Safer - because you have pre-loaded all of the host keys and specified strict host key checking, SSH will prompt you if you connect to a machine and something has changed.
- Discoverable - if you have tab completion, your shell will let you explore your infrastructure just by prodding the Tab key.
This seems like it ought to be more obvious than it perhaps is... the private halves of your SSH keys are very privileged things. You should treat them with a great deal of respect. Don't put them on multiple machines (SSH keys are cheap to generate and revoke) and don't back them up.
Know your limits
HashKnownHosts no
Host *
GSSAPIAuthentication no
ForwardAgent no
- Known hosts hashing is good for keeping your hostnames secret from people who obtain your known_hosts file, but is also really very inconvenient as you are also unable to get any useful information out of the file yourself (such as tab completion). If you're still feeling paranoid you might consider tightening the permissions on your known_hosts file as it may be readable by other users on your workstation.
- GSSAPI is very unlikely to be something you need, it's just slowing things down if it's enabled.
- Agent forwarding can be tremendously dangerous and should, I think, be actively and passionately discouraged. It ought to be a nice feature, but it requires that you trust remote hosts unequivocally as if they had your private keys, because functionally speaking, they do. They don't actually have the private key material, but any sufficiently privileged process on the remote server can connect back to the SSH agent running on your workstation and request it respond to challenges from an SSH server. If you keep your keys unlocked in an SSH agent, this gives any privileged attacker on a server you are logged into, trivial access to any other machine your keys can SSH into. If you somehow depend on using agent forwarding with Internet facing servers, please re-consider your security model (unless you are able to robustly and accurately argue why your usage is safe, but if that is the case then you don't need to be reading a post like this!)
Host *
PermitLocalCommand yes
LocalCommand /home/user/bin/ssh-notify.sh %h
Host server1.company.com
IdentityFile /some/rarely/used/ssh.key
IdentitiesOnly yes
Host *.company.com management-rack-??.company.com
User root
PreferredAuthentications password
Host server-??.company.com
IdentityFile /some/path/id_rsa-%h
Host port-forwards-site1.company.com
Hostname server1.company.com
LocalForward 1234 10.0.0.101:1234
Use an SSH jump host
Rather than have tens/dozens/hundreds/etc of servers holding their SSH port open to the Internet and being battered with brute force password cracking attempts, you might consider having a single host listening (or a single host per network perhaps), which you can proxy your SSH connections through.
If you do consider something like this, you must resist the temptation to place private keys on the jump host - to do so would utterly defeat the point.
Instead, you can use an old, but very nifty trick that completely hides the jump host from your day-to-day usage:
Host jumphost.company.comYou might wonder what on earth that is doing, but it's really quite simple. The first Host stanza just means we won't use any special commands to connect to the jump host itself. The second Host stanza says that in order to connect to anything ending in .company.com (but excluding jumphost.company.com because it just matched the previous stanza) we will first SSH to the jump host and then use nc(1) (i.e. netcat) to connect to the relevant port (%p) on the host we originally asked for (%h). Your local SSH client now has a session open to the jump host which is acting like it's a socket to the SSH port on the host you wanted to talk to, so it just uses that connection to establish an SSH session with the machine you wanted. Simple!
ProxyCommand none
Host *.company.com
ProxyCommand ssh jumphost.company.com nc -q0 %h %p
For those of you lucky enough to be connecting to servers that have OpenSSH 5.4 or newer, you can replace the jump host ProxyCommand with:
ProxyCommand ssh -W %h:%p jumphost.company.comRe-use existing SSH connections
Some people swear by this trick, but because I'm very close to my servers and have a decent CPU, the setup time for connections doesn't bother me. Folks who are many milliseconds from their servers, or who don't have unquenchable techno-lust for new workstations, may appreciate saving some time when establishing SSH connections.
The idea is that OpenSSH can place connections into the background automatically, and re-use those existing secure channels when you ask for a new ssh(1), scp(1) or sftp(1) connections to hosts you have already spoken to. The configuration I would recommend for this, would be:
Host *
ControlMaster auto
ControlPath ~/.ssh/control/%h-%l-%p
ControlPersist 600
- ControlMaster auto will cause OpenSSH to establish the "master" connection sockets as needed, falling back to normal connections if something is wrong.
- The ControlPath option specifies where the connection sockets will live. Here we are placing them in a directory and giving them filenames that consist of the hostname, login username and port, which ought to be sufficient to uniquely identify each connection. If you need to get more specific, you can place this section near the end of your config and have explicit ControlPath entries in earlier Host stanzas.
- ControlPersist 600 causes the master connections to die if they are idle for 10 minutes. The default is that they live on as long as your network is connected - if you have hundreds of servers this will add up to an awful lot of ssh(1) processes running on your workstation! Depending on your needs, 10 minutes may not be long enough.
Host power-device-1.company.com
HostkeyAlgorithms ssh-rsa,ssh-dss
Those are the most useful tips and tricks I have for now. Hopefully someone will read this and think "hah! I can do much more advanced stuff than that!" and one-up me :)
Do feel free to comment if you do have something sneaky to add, I'll gladly steal your ideas!
Here's a couple of lines for your .ssh/config when you're on a network that likes to close ssh sessions that aren't sending enough traffic.
ReplyDeleteServerAliveInterval 30
ServerAliveCountMax 4
Nice job on the article. I don't think I've seen all these options in one place before.
permitrootlogin yes
ReplyDelete;) kidding
nice write up - thx!