Upgrading SSH accounts from password-based authentication (PAM) to key-based authentication
April 30, 2009 (as amended)

Using password-based authentication means IP addresses should be specified in sshd_config's AllowUsers line, or the account is vulnerable to brute-forcing. However, if IP addresses are specified in the AllowUsers line, users cannot login from any other IP address. This may be problem if the user is on a dynamic IP.

Using key-based authentication allows you to remove the IP address restriction, while still protecting the account from brute-forcing. Using keys means it doesn't matter which IP address is used - if the keys validate, then the user is authenticated.

Note that retaining an IP address restriction while also using keys is possible, this configuration will prevent an attacker who has stolen a password-less private key from using it. However password-less keys are not recommended, except for automated tasks.

This article assumes:

  1. you are using password-based authentication (PAM), but you want to use key-based authentication
  2. your server is running FreeBSD, and you're using SSHD
  3. you login to the server remotely using PuTTY
  4. you're familiar with FreeBSD, security, SSH, PuTTY, and PKI principles

The process

First, configure the server to accept key-based authentication. This only needs to be done once:

  1. login to the FreeBSD server as root
  2. vi /etc/ssh/sshd_config
  3. uncomment the lines:
    RSAAuthentication yes
    PubkeyAuthentication yes
    AuthorizedKeysFile     .ssh/authorized_keys
  4. save and exit the editor
  5. restart the SSH daemon: /etc/rc.d/sshd restart

Next, for each user, create a keypair:

  1. on a workstation, open PuttyGen
  2. either load an existing key, or create a new key:

    1. select SSH2-DSA
    2. enter a keylength in bits - 2048 is good
    3. click the button: Generate

  3. login to the FreeBSD server as root
  4. mkdir /usr/home/username/.ssh
  5. vi /usr/home/username/.ssh/authorized_keys
  6. press i to put vi into Insert mode
  7. using PuTTYGen, select the public key and copy it into the clipboard
  8. paste the public key into the vi session (right-click anywhere on the PuTTY session screen)
  9. press Esc to exit Insert mode
  10. save and exit the editor
  11. chmod 600 /usr/home/username/.ssh/authorized_keys
  12. chown username /usr/home/username/.ssh/authorized_keys
  13. if you were creating a new key:

    1. using PuttyGen, enter a passphrase and confirm it (the user will need to enter this each time they login - note it down for future reference)
    2. using PuttyGen, click the button: Save private key
    3. save the key onto the local system, and close PuttyGen

Note: in the sample commandlines above, substitute username for the name of the user being configured

Note: permissions on the authorized_keys file MUST be set to 600 (-rw-------), and the file must be owned by the user (not by root)

Note: PuTTY uses its own key format (PPK). You cannot simply copy-and-paste between Putty's keyfile and keyfiles generated by ssh-keygen. You must use the load/save functions in PuttyGen if you generate keys with ssh-keygen. The recommended method is to use PuttyGen to generate the keys.

Next, for each user, add the key to the user's PuTTY configuration:

  1. on the user's workstation, open PuTTY
  2. select the correct session, then click the Load button
  3. in Connections.. SSH.. Auth, click Browse
  4. locate the private key file, and double-click it
  5. click Session.. Save
  6. close PuTTY

The key should now be available for use. If you see a "server refused our key" error when you try and login, this may happen for any of the following reasons:

The last job, if applicable/desired, is to remove the IP address restriction in the /etc/ssh/sshd_config file. Do this once key-based authentication is known to work correctly. To remove an IP address restriction:

  1. login to the FreeBSD server as root
  2. vi /etc/ssh/sshd_config
  3. comment out or delete the AllowUsers line that contains the relevant UserName and IP address
  4. save and exit the editor
  5. restart the SSH daemon: /etc/rc.d/sshd restart

This will allow the user to login from any IP address, as long as they are in possession of their key.

Once all users are using key-based authentication, password-based authentication should be disabled (see below).

Disabling PAM

Note: the process above adds key-based authentication capability to the SSH server. It does NOT remove password-based authentication capability. To remove password-based authentication capability for ALL users:

Warning: ensure to test that key-based authentication is working, before disabling PAM. If PAM is disabled but key-based logins aren't working, all users will be locked out of the system.

  1. login to the FreeBSD server as root
  2. vi /etc/ssh/sshd_config
  3. set these lines as follows:
     PasswordAuthentication no
     ChallengeResponseAuthentication no
  4. save and exit the editor
  5. restart the SSH daemon: /etc/rc.d/sshd restart

Verify this change has taken effect by temporarily removing the private key from a PuTTY profile used to access the server. PuTTY will attempt to use PAM and if it is correctly configured, the server will refuse the connection. PuTTY will show a nasty error, "Disconnected: No supported authentication methods available" and the session will become inactive.

Other notes

This article does NOT create a password-less login. Users must still enter a password, although it's actually the passphrase for their private key, rather than the password to their account. To create a password-less login, don't set a passphrase on the private key. Doing this still permits key-based authentication, however it allows anyone who gets a copy of the private key to login.

A passphrase-protected private key is still subject to a brute-force attack, but the key must be obtained first (eg. an attacker requires access to the computer hosting the key before they can try to brute-force it).

PuTTY has the ability to save the username and provide it automatically. We don't recommend using this, except for unprivileged accounts. The username is the last bit of info that an attacker will need, assuming he has your private key, and the passphrase that is associated with it.