SSH with Leopard

November 29th, 2008

I recently set-up a secure shell account for a DreamHost shared hosting account that I intend to use for automating deployment and backup tasks from a Mac OS X Leopard client. While not overly complicated there were a couple of gotchas that I ran into. This post consolidates my findings and gives you a brief background for what's going on when you set up SSH access. The information applies to Mac OS X 10.5.1 or greater.

Secure Shell Access

The first step is to make sure you have SSH and/or SFTP access for one of your hosting service accounts. How you accomplish this will vary from one service to another. For DreamHost it's very easy, go to the Manage Users > Users section of your DreamHost web panel, select Add A New User or Edit an existing user and fill in the account information. Be sure the User Account Type is set to Shell account, which includes support for both SSH and SFTP. If you have a shared hosting account then you'll need to make sure the Username is unique. The error messages should lead you through any issues. If you want more detail check out the DreamHost Enabling Shell Access Wiki.

For the rest of this post I'll assume your domain is called mydomain.com and you have an SSH user account named mydom_user. Now open Terminal in OS X and try using SSH. Here's the typical format for the ssh command:

[mac]$ ssh mydom_user@mydomain.com

You should be prompted for your password. If you aren't prompted then check your hosting service documentation to see if you need to use something other than the user@hostname format to connect. If you are prompted and you enter your password correctly then you should see a greeting followed by the command prompt from your server. At this point you have secure shell access working. The main limitation is that the password gets in the way for automated tasks such as deployment scripts and client initiated cron jobs. If you don't mind being prompted for a password when you use SSH and you either don't have automation needs or don't mind setting up your password in automation scripts then congratulations, you're done!

Digital Signature Setup

Assuming you don't want to deal with your SSH password then the solution is to use a public/private key pair for authentication. The first step is to create a directory to hold your Mac's public key on your domain server. For SSH to work this directory must be named .ssh and it must have owner only read, write and execute privileges. If you logged out then log back in to your shell account and type:

[dh]$ mkdir .ssh
[dh]$ chmod 700 .ssh
[dh]$ logout

That's it from the server side. You should be back to your regular OS X prompt. Unless you already have an existing private/public key pair you'll need to create one and copy the public key to your server. First check to see if any keys are already defined:

[mac]$ ls -l ~/.ssh

If you see an id_rsa and id_rsa.pub file or an id_dsa and id_dsa.pub file then you have a key pair already defined. For example, I have:

...
-rw-------@  1 Rob  Rob  1743 Nov 11 15:16 id_rsa
-rw-r--r--@  1 Rob  Rob   405 Nov 11 15:16 id_rsa.pub
...

The file without the extension contains the private key; the file with the .pub extension is the public key that can be shared. They don't have to be named id_rsa or id_dsa but those are the default names. ID is used because the keys establish an identity, while RSA and DSA are associated with the two public key signature algorithms that SSH supports. I'll describe how to generate a key pair later but first I want to cover the situation that I had with existing keys.

In my case an RSA key pair already existed but I didn't remember creating it. At this point creating a new set of keys or overwriting the existing pair may have been a good idea but I didn't want another identity and I didn't want to break something that I'd set up previously but couldn't remember at the moment. So, I decided to try to use the existing key pair. The first issue I had was with the privilege settings on my private key. The file should only have owner read, write privileges ( -rw-------). Initially, the permissions were wrong on my file. I have no idea why but at some point they got messed up. When I tried using the key it was ignored and I got the following warning:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0622 for '/Users/Rob/.ssh/id_rsa' are too open.
It is recommended that your private key files are NOT accessible by others.
This private key will be ignored.
bad permissions: ignore key: /Users/Rob/.ssh/id_rsa
If your private key file has -rw-r--r-- or any permissions other than -rw-------, you'll need to fix it:

[mac]$ chmod 600 ~/.ssh/id_rsa

The next issue I had was that I was prompted for my "passphrase" and I couldn't remember it. You can think of a passphrase as a password that's used to protect your private key. The difference is that spaces and tabs are allowed in passphrases. If you have a key pair and remember the passphrase you used when you created it then your set. Since I didn't remember mine, I decided to open the Keychain Access application in the Applications/Utilities folder to see if I could find it. If you're in the same situation checking your keychain is probably worth a try. If the passphrase is there you'll find it in the Passwords/Application Category of the login Keychains. It'll have a name starting with SSH:, but don't be surprised if you don't find it. Passphrases were not stored in the keychain until OS X 10.5.1 and even then only if you chose to store it when you used the key. You also won't find passphrases in your keychain if you're using the MacPorts OpenSSH implementation. I'll get to MacPorts later but if you don't find your passphrase and want to try a few guesses at it then you can use the ssh-keygen command with the change password option:

[mac]$ ssh-keygen -f ~/.ssh/id_rsa -p

Ultimately, if you can't remember or find your passphrase then you'll need to generate a new key pair or overwrite your existing pair. Generating new keys or overwriting existing keys can be accomplished the same way:

[mac]$ ssh-keygen

will generate an RSA key and prompt you for a passphrase. It will also prompt for a file name, defaulting to ~/.ssh/id_rsa. If you have an existing key pair with the same name it'll make sure it's OK with you before overwriting an existing key pairs. RSA is the default, if you want DSA then add the -t dsa option when you run ssh-keygen.

The passphrase is optional and if you just hit enter twice when prompted for it then you won't set one. Don't do that. It may seem that having a passphrase gets you back to square one with a password prompt but that's an easy limitation to get around, especially with Leopard. For now take my word for it and enter a passphrase. You should also pick something different than your password. I don't want to get too sidetracked with why a passphrase is so important but keep in mind that your private key is stored in a text file on disk and without a passphrase for protection anyone who gets your key could access anything that key is used for.

At this point you should have a private/public key pair and a known passphrase. I'll assume your private key is named id_rsa but you can make substitutions if you chose another name. Now you need to copy the public key to your server. You should also make sure it just has owner read, write privileges if it's a new file:

[mac]$ cat ~/.ssh/id_rsa.pub | ssh mydom_user@mydomain.com \
> "cat >>  ~/.ssh/authorized_keys; chmod 600 .ssh/authorized_keys"

If you enter your password correctly then the copy should work. I should note that instructions from other sites will often say to use authorized_keys2 instead of authorized_keys, that's fine but authorized_keys2 has been depreciated so I went with authorized_keys. You'll also see a lot of instructions using the secure copy (scp) command to move the file but I like the cat with the pipe and redirection format because it makes it clear how to append new public keys. Now it's time to give your public key signature a try:

[mac]$ ssh mydom_user@mydomain.com

If you're luckly you'll be prompted for your passcode with a dialog prompt like this:
Leopard SSH Prompt
If you get the dialog just enter the passphrase and check the box to save it in your keychain. From now on you should be able to use SSH without being prompted. You're done!

Don't Blame Apple

If you're still reading then I'm assuming things didn't go according to plan. Perhaps you got the following error:

percent_expand: NULL replacement 

or, instead of being prompted by a GUI dialog box you get prompted for your passphrase on the command line:

Enter passphrase for key '/Users/Rob/.ssh/id_rsa':

These issues typically occur because you're not using the Leopard version of the ssh program. First, verify that's the problem:

[mac]$ which ssh

If you get back /usr/bin/ssh then you're using the Leopard version of ssh and I don't know what's wrong so you'll need to look elsewhere for a solution. On the other hand, if you get back/opt/local/bin/ssh then you're running the MacPorts version of ssh and I'll walk you through a solution. If you get a different path then there's still a good chance you're using the MacPorts ssh but it was installed somewhere other than the default location. The following instructions will probably still work but you'll need to adjust the paths.

OK, at this point I'm assuming you're using the OpenSSH implementation from MacPorts and your either getting the percent_expand: NULL replacement error or your continuing to see passphrase prompts when you use ssh. If so, the easiest solution is just to switch to Leopard's SSH commands. Just renaming the MacPorts SSH commands so the Leopard version is found instead will work but I like this technique taken from from github better:

[mac]$ sudo -s # To get a root prompt
bash-3.2# cd /opt/local/bin
bash-3.2# mv ssh{,_macports}
bash-3.2# ln -s /usr/bin/ssh ssh
bash-3.2# exit

It renames ssh and leaves a symbolic link behind allowing any software that looks specifically for the program in the MacPorts directory to find them. The github guide, and every other Internet post I've seen, renames scp as well but as far as I can tell that's not necessary. At least on my Mac only ssh has problems, scp and sftp don't exhibit the NULL replacement problem and the Leopard version of ssh-agent is automatically launched to take care of the passphrases. That said, you could also use the same renaming technique for scp, sftp and any other SSH commands that you want. For example, the Leopard version of ssh-add has additional options for keychain support that don't exist in the MacPorts version. Anyway, after you're done with renaming then when you use the ssh command you should get the desired Leopard dialog box and behavior described above.

Other Ideas and Resources

While I prefer switching to the Leopard ssh, if for some reason you want to stick with the MacPorts version then you may be able to solve the percent_expand: NULL replacement error by updating to the "openssh 5.0p1_0+darwin_9" version of MacPorts SSH (see bottom of this). I haven't tried the update so I'm not sure if it works. Even if it doesn't you can definitely work around the problem by creating/updating your ~/.ssh/config file (see here). To avoid the continuous passphrase prompting, you could just run sftp or the Leopard version of ssh once to cause Leopards ssh-agent to save it in your keychain. I suppose it would also be possible to switch over to the MacPorts ssh-agent and use it along with a utility such as SSHChain or SSHKeychain. You can also find plenty of generic Unix passphrase prompting solutions by googling for ssh-agent. Many of them aren't Mac compatible but I'm sure you can find something that works.

If you want to dig more into SSH on the Mac then Dave Dribin's has a couple of great blogs. As a starting point take a look at his ssh-agent on Mac OS X 10.5 (Leopard) article where he describes, among other things, how the Leopard version of ssh-agent is automatically launched as necessary.

Sorry, comments are closed for this article.