Work

Proper use of SSH client in Mac OS X

by ,


Historical background

Back in the days when I started learning SSH, I used Windows and Putty.

When I got more familiar with the use of SSH keys for password-less login, I became a happier SSH user.

A few years later, I started using OS X and initiating SSH connections from it felt awkward without Putty, until I discovered iTerm.

But getting more familiar with the OS X system itself, I found myself really hooked up to it for mainly one reason – it’s built from FreeBSD. Working with CLI in OS X feels much like Linux. And the native OpenSSH client is the killer feature.

Fast forward to 2019, and my failure to build a proper Hackintosh using high-end PC components, rendered it useful only for mostly one thing at present – watching movies on Windows. I still prefer to use my MacBook Air for work, just because I can type ssh web and start working with my server right away.

Could it be even better in regards to SSH? Just when I could definitely answer “No”, I got an email from a client, who was asking for instructions on how to generate SSH key for use with FileZilla to connect to their server.

After trying to recap the proper instructions for them, I found how I could improve my own use of SSH in OS X, and also make it more secure.

Let’s walk through the proper setup of your native SSH client in OS X.

Generating SSH key

To generate the SSH key, you will run ssh-keygen in Terminal app. To construct the correct arguments for it, we need to first…:

Choose passphrase

In many tutorials online, they’d say it is OK to specify an empty passphrase. Surely enough, you think it’s a sane choice because then you save yourself a lot of time. With empty passphrase, you don’t have to enter it every-time, and with long passphrase, you have to? Fear not!

With OS X, you can have the convenience of password-less login to a server even when your key is passphrase-protected. The magic of it is achieved by the Keychain and SSH agent components of the operating system.

So make sure that you choose a very strong passphrase for protecting your SSH key. And don’t worry, you won’t be bothered to enter it every time you use SSH / SFTP.

Choose comment

A good SSH key has a good comment. To be nice to others, and simply for housekeeping purpose, make sure that the key’s comment includes:

  • Your email address, where people can reach you
  • An (arbitrary) identifier of the machine or device where you intend to use the key

Following these rules a good comment might look like this:

info@example.com (MacBook Air)

By default, ssh-keygen will try to be smart in generating the comment, but not smart enough: the comment will include your machine’s hostname and folks who find your key added to their system, will not know how to reach you if there’s a need to collaborate about server tasks or your key. So you may want to adjust the command before you run by passing your good comment in the -C switch:

ssh-keygen -t rsa ~/.ssh/id_rsa -C "info@example.com (MacBook Air)"

Make sure to actually change the command to include your email and device name. Now it is OK to run it.

Don’t put an empty passphrase!

Now you have your key generated and stored in ~/.ssh/id_rsa. Remember, this file should never be shared with anyone. It is the public key you’ll need to share or add to servers.

Share your public key

When you generated the SSH key, you have actually generated 2 files: the private key ~/.ssh/id_rsa and the public key ~/.ssh/id_rsa.pub.

The public key is what you will share to server admins, or add yourself to remote servers, in order to be able to login to those systems without a password.

The command to copy contents of your public key to clipboard is simple:

cat ~/.ssh/id_rsa.pub | pbcopy

We’ll leave out the details on how to add your key to remote servers for the next time.

Provided that the public key was already authorized on the server you want to work with, how do you make sure that OS X won’t ask you for the key’s passphrase every time you log in?

Configure OS X SSH client

OS X ships with an actual OpenSSH client. And standard as it is, it can be configured by editing ~/.ssh/config file.

The most relevant configuration directives for proper SSH setup are:

UseKeychain    yes
AddKeysToAgent yes

Simply including those to your ~/.ssh/config will ensure that the SSH client will use operating system’s Keychain to store the password of your SSH key files, and also the keys will be loaded to SSH agent for later reuse.

There is controversial information on how these directives actually work. So I thought I should elaborate:

  • Upon reboot/login to your system, your SSH agent will have no keys loaded. This can be verified with ssh-add -L
  • When you SSH to a server, via ssh username@example.com, the SSH client will attempt to use ~/.ssh/id_rsa
  • The SSH client will talk to the Keychain and ask it for the passphrase. If the passphrase is already stored in the Keychain, then the key is loaded to the SSH agent without any passphrase prompts. If the passphrase is not yet present in the Keychain, it will prompt you for the passphrase, and store it in the Keychain after you provide it.

It is important to understand that keys in SSH agent do not persist across reboots. The SSH keys are added to the agent dynamically, as in – upon connection to a server. Then they are reused on further (second, third and so on) connection.

After a reboot, the agent will have no keys loaded again!

So keys do not persist (which is fine!), but their pass-phrases persist in the Keychain. You will only have to provide the SSH passphrase once in a lifetime. And the added benefit is that the passphrase will be synced to your iCloud Keychain if you’re using it.

To add the key’s passphrase to the Keychain now, simply run:

ssh-add -K

The case of horrible FileZilla

By simply following the above recommendations you have the properly configured SSH client in OS X.

But what about FileZilla? Surely we want it to use the SSH agent and we don’t want to put any passphrase / keys explicitly there.

FileZilla apparently knows how to talk with the SSH agent and use keys from it. This is better than importing the key to FileZilla, since this way you can keep the file password protected.

But there is one major flaw in FileZilla – it would appear not use ~/.ssh/config and it won’t load the key to the SSH agent for you. Remember, as we described earlier, the native SSH client loads the keys to the SSH agent upon connection. But FileZilla doesn’t.

So your SFTP connection in FileZilla will only work after you first establish SSH connection manually.

I thought that FileZilla comes from the open source world. But not that only – it comes from many worlds and it is primarily an inhabitant of the Windows ecosystem. And it brings a bag of compatibility issues from there.

To counter the issue we’re facing, you could make FileZilla use the manually specified SSH key in its settings. But that sucks for many reasons:

  • Filezilla prefers / and converts to Putty PPK format.. to much of its shame, because OpenSSH is de-facto standard SSH implementation (and so are its keys)
  • Your SSH configuration is less centralized, in case you use different keys for different servers. Instead of just using ~/.ssh/config for everything …

I tried to see if any other SFTP clients address this “flaw”. Cyberduck doesn’t seem to use the SSH agent at all, but at least it does support directly specified OpenSSH key, without having to convert to PPK format.

Panic’s Transmit uses ~/.ssh/id_rsa by default and it is capable of using the options you have defined in ~/.ssh/config but does not seem to use the SSH agent either.

So now we are back with Filezilla. Either we have to invoke ssh-add -A manually before connecting in Filezilla, or automatically add our key to the SSH agent upon login.

What ssh-add -A does is load only the keys which already have passphrase stored in the Keychain.

Convenience sometimes wins and this is the time 🙂 Create file ~/Library/LaunchAgents/ssh.add.a.plist with contents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>ssh.add.a</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/ssh-add</string>
        <string>-A</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

This makes your Mac run ssh-add -A every-time you login, so FileZilla will happily use the key from SSH agent.

So we’re fixing Filezilla, because it does not know how to use ~/.ssh/id_rsa by default and thus won’t load it to the SSH agent. We told OS X to always load keys, whereas ideally we would stick to the default behavior (load keys into agent dynamically, after first use).

Caveats

Multiple SSH keys

If you have multiple keys’ pass-phrases in your Keychain, then ssh-add -A maybe not desired. Loading all keys will make your SSH client try them all during a connection until it finds the one that works.

This may not be taken lightly by some security hardened servers. So you can specify the mapping between the remote server and your keys like this:

Host foo.example.com
  IdentityFile ~/.ssh/another_rsa
  IdentitiesOnly yes 

That said, FileZilla does not read your ~/.ssh/config so this is applicable only to the SSH client. So not much luck if you use FileZilla and many keys – the chances of getting banned for key enumeration will increase.

Partial automation

To setup your OS X SSH client you can try this nifty script I made:

bash <(curl -Ls http://bit.ly/osx-ssh)

What it does is walk you through the SSH key setup:

  • generates SSH key, if there is none
  • helps you to convert to an encrypted key, in case existing key is not an encrypted one
  • ensures that ~/.ssh/config has same configuration as outlined in this post (only if there was no ~/.ssh/config file)
  • optionally, “fixes” Filezilla by auto-loading keys to SSH agent (otherwise only option is to run “ssh-add” manually or connecting to the server in SSH first)

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.