Secure Shell without Passwords

Something you know, Something you have, ...


SSH concepts

With remote access via ssh, there are 2 user accounts to consider :
luser@local ---becomes---> ruser@remote

Although both accounts can have the same account name (e.g. jdoe@local, jd@remote), and although ssh assumes that you will use the same username on both local and remote system, they are 2 distinctive user accounts, on separate machines.

objective : while logged in at 'local' as 'luser', do one of the following :

Those are the basic ssh operations. Advanced ssh usage, e.g. ssh secure tunnels (link), follow the same logic. The problem we will deal with in this mini-howto is that you are, obviously, already logged in as luser@local, but will need to authenticate as ruser@remote for any of the basic ssh operations mentioned above. The default method is password authentication, i.e. you supply the account of the remote user in your ssh statement, and are prompted for ruser's password.

	luser@local:~$ ssh ruser@remote
	ruser@remote's password: 

	ruser@remote:~$
	ruser@remote:~$ pwd
	ruser@remote:~$ /home/ruser

If you don't supply an account, ssh will assume you use the same username on remote as on local. Still, you'll be prompted for a password, and that's not necessarily the same password as for luser@local. Like we said, these are 2 distinct accounts

shh is secure in that the password is sent encrypted, so that it can not (easily) be intercepted on the network - contrary to less secure protocols such as telnet, ftp, ... However, the password can be cracked by brute force (which is trivial for weak passwords). Using passwordless authentication enhances security.
Passwordless ssh also allows for scripting remote sessions or file transfers so you can create scripts for remote management or file transfers over shh without having the script stop and wait for a password each time it has to initiate an ssh connection.

This howto assumes you're using ubuntu 8.10 clients and debian 4.x servers, but should be applicable to any other Linux system, possibly with minor modifications in file names and paths and such.


Key pairs and host-based authentication.

we're obviously dealing with 4 entities : 2 user accounts : luser, ruser 2 computers (hosts) : local, remote

we'll look into private/public key pairs for user authentication, and authentication based on the host that initiates the ssh session (host-based authentication).

I assume you have created the relevant user accounts, installed openssh-server on the remote system, and are capable of using ssh with password authentication, so this article only describes how to make it passwordless.

Public Key authentication

This is rather straightforward : you create a key pair (private key, public key). The public key is stored on the remote system. The remote system uses this key to authenticate you : Public Key Authentication works on the assumption that if a message (i.c. a request to log on) can be read using luser's public key, it must have been generated using luser's private key, and therefore can only be coming from luser, so luser is authenticated.

Keys can be protected by a pass-phrase. This will cause a prompt for the pass phrase when the key is used. It adds security (in case someone else has gained access to your private key) but makes scripting more difficult again. You can use ssh-agent to manage the pass phrases and make it all scriptable again. It is advisable to use a passphrase, because a private key file is equivalent to writing down your account names and passwords in a file in your home directory. If your login account on the local machine gets compromised, all your accounts on remote systems are accessible/

setting up Public Key Authentication

check that you have a private and public RSA key
most linux distributions will create keypairs for you during setup, while you install the ssh client package. Check your (luser's) home directory for ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub.
to create a key should you need a (new) one :
			luser@Local01:~$ ssh-keygen -t rsa
			

Next, the public key (id_rsa.pub) needs to be added to the list of authorized keys on the remote system. You could simple copy the .pub file, but that would overwrite any existing authorized keys. It's better to append the contents of /home/luser/.ssh/id_rsa.pub to .ssh/authorized_keys in the home directory of the remote user you want to log in as.

		luser@Local01:~$ scp /home/luser/.ssh/id_dsa.pub ruser@Remote:luser.pub.tmp
		luser@Local01:~$ ssh ruser@Remote <<EOF
		 mkdir .ssh
		 chmod 700 .ssh
		 cat luser.pub.tmp >> .ssh/authorized_keys
		 chmod 600  .ssh/authorized_keys
		 rm luser.pub.tmp
		EOF
	

You could also just do all this in one go with ssh-copy-id -i ~/.ssh/id_rsa.pub ruser@Remote

luser@Local01 can now do ssh ruser@Remote and will be logged on as ruser on Remote, without being prompted for a password. Any other user ssh-ing into ruser on remote will still be prompted for ruser's password, and ssh'ing into any other account on remote (eg root@Remote) will also require a password. Of course, you can repeat the passwordless ssh configuration for any combination of local and remote user accounts.

If you've set up public key authentication for all users that need ssh access to "Remote", you can configure Remote to only allow public key authentication, so that any attempts to log on with password authentication will be denied.

remote:/etc/sshd/sshd_config
			PasswordAuthentication  no
			

Troubleshooting

In case things don't work right-a-way, these are some relevant configuration settings, both local and remote :

remote:/etc/sshd/sshd_config
			RSAAuthentication yes
			PubkeyAuthentication yes
			
See man 5 sshd_config
local: /etc/ssh/ssh_config [ and ~/.ssh/config ]
/etc/ssh/ssh_config is system-wide client-side configuration, which can be overridden by per-user settings in ~/.ssh/config. See man 5 ssh_config.
Define which authentication methods will be tried by the client, in the order given. You want publickey to appear in the list, before password (or remove password alltogether) :
			PreferredAuthentications hostbased,publickey,keyboard-interactive,password
			

On Debian and Ubuntu, all of these are the default values.


Host-Based authentication

Host-based "or "trusted host" authentication resembles Public Key (user-)authentication, so what follows may get a bit confusing.

In trusted-host authentication, the SSH server does not directly authenticate a user based on something he knows or has (e.g. password or private key). Rather, it authenticates the client host, and then trusts that host to say who the user is (i.e., which client-side account he has already been authenticated to use). It then consults server-side configuration (e.g. /etc/shosts.equiv or ~/.shosts) to determine which account names on the client host are allowed access to which server accounts. So, this mechanism actually delegates responsibility for user authentication to the client host — and hence, compromise of a client means immediate transitive compromise of corresponding accounts on the server. (http://www.snailbook.com/faq/trusted-host-howto.auto.html)

ssh with hostbased authentication closely mimics the behavior of the now depreciated r(emote)-commands (rlogin, rcp, ...). the assumption is that a user on local also has an account on remote (with the same username), and when he's authenticated on local, no further authentication is required :

	jdoe@local:~$  ssh remote
	jdoe@remote:~$
	

The authentication method is a public key authentication but the keys belong to the host (so-called "host keys"), not a user. We'll look in the (functional, conceptual) difference between public key user authentication and host based authentication later. First, let's set it up and see what it looks like.

check that your local system has private and public RSA host-keys
most linux distributions will create keypairs for you during setup, while you install the ssh client package. Check /etc/ssh for ssh_host_rsa_key and ssh_host_rsa_key.pub. Use [sudo] ssh-keygen -t rsa to generate a key and save them as (Local:)/etc/ssh/ssh_host_rsa_key[.pub].

copy the public key over to remote so you have it available their later :
			scp /etc/ssh/ssh_host_rsa_key.pub root@remote:/etc/ssh/temp.local02.rsa.pub
		
make sure name resolution works
the remote system will check the local system's hostname based on its IP address. This requires you to have a working name resolution system in place, such as DNS (reverse lookup), or an entry for the local system(s) in the remote system's /etc/hosts file. The IP address must resolve to a fully qualified domain name. Check this by doing nslookup, dig, host from the server (Remote). You may need to install the package dnsutils to get these commands available.
		
		remote:~# host 192.168.11.222
		222.11.168.192.in-addr.arpa domain name pointer Local01.mydomain.yx
		

On Remote:

add the local hostkey to the remote /etc/ssh/ssh_known_hosts
as with user-based public key authentication, it's best to append to the known hosts file in stead of overwriting it. The format for a key entry is
<hostname> <key>

The /etc/ssh/ssh_known_hosts and ~/.ssh/known_hosts files contain host public keys for all known hosts. The (system-wide) /etc/ssh/ssh_known_hosts file should be prepared by the administrator (optional), the per-user file is maintained automatically: whenever the user connects from an unknown host its key is added to the per-user file.
		cd /etc/ssh
		echo -n "Local02.mydomain.yx " |cat - temp.local02.rsa.pub >> /etc/ssh/ssh_known_hosts
		rm temp.local02.rsa.pub
			
in /etc/ssh/sshd_config
enable Host-based authentication:
      HostbasedAuthentication yes
			
If you changed this, you must restart the ssh daemon for the changes to take effect.
/etc/hosts.equiv
create this file if it doesn't exist, and add the hostname (FQDN) of local to it

On Local

ssh-config
		HostBasedAuthentication		yes
		PreferredAuthentications	hostbased,publickey,keyboard-interactive,password
		EnablesSSHKeysign 		yes
			

Any user that is authenticated on Local can connect (with ssh) to Remote, provided there is an account with the same name on Remote, and the user will log in with that account.

FIXME: This doesn"t seem to work for root, maybe because ubuntu's root account is locked (although whoami returns root after sudo -i ), or else because it requires additional configuration on remote (PermitRootLogin yes).

Adding a username (from local) in /etc/hosts.equiv gives that account (from local) access to any account on remote (including system accounts that may have or be capable of escalated privileges, possibly to user accounts that can su or sudo, but not to the root account directly). This is considered a security hazard.
a minus ( - ) sign can be used to exclude a username from using hostbased authentication
see man 5 hosts.equiv

To let a specific account from local (e.g. jrandom), as opposed to all users on local, log in to remote using host-based authentication, you do not use the system-wide ssh_known_hosts file, but a .ssh/know_hosts in the home directory of the account that should be made accessible. This still only works between identically named accounts on local and remote.

To have an account on remote accessible by a differently named account on Local, create a .shosts file in that account's home directory, listing the accounts that should have access to it. The .shosts file must be owned by the user and should have mode 0400. Also make sure that the user's's home directory is owned by that user and is not writable by anyone but that user.

FIXME
I haven't gotten this account switching to work when using host based authentication. I suspect it involves the use of usernames in /etc/hosts.equiv in combination with .shosts and known_hosts in the target account's home,and possibly loosening up some settings in sshd_config (IgnoreRhosts no ?).

It may be more trouble than it's worth, since public key user authentication is a viable, and maybe preferable, alternative.


Comparing Host-based with user authentication

Hostbased authentication is simple and straightforward once you"ve set it up, especially if you use identical usernames on the systems involved. Once hostbased authentication is set up, it suffices to create users on local, and accounts on remote with identical usernames as those on local, to have all users from Local be able to ssh into remote - that is, you don't have to set up and manage per-user keypairs for every user anymore. You do have to trust the authenticating host, however. If it allows users to login with weak or blank passwords, those weak accounts have direct access to your server.

Host-based authentication can possibly also be interesting in combination with a centralised user database, eg OpenLDAP or WinBind - but didn't go in to that (yet).

At first sight, Hostbased authentication looks easier in the case where 1 account (luser@local) needs access to multiple servers. However, if this involves different user names on the remote systems, then each target account needs to be set up to allow access. It is then just as easy, or easier, to set up user authentication with these accounts.

Hostbased authentication with switching of user accounts could be useful if all users of a given host need access to the same account of a remote host. It would suffice to create a user account on the local system, and be done with it. This means you need to have total trust in the originating host : any account created there will automatically gain access. Depending on what the server and the target account are, user authentication may be preferable.


Other authentication mechanisms

Other authentication mechanisms supported by ssh are

Certificate Authentication :
uses certificates that contain a public key. Certificates add a hierarchy of trusted authorities and the remote system checks that the user certificate was issued by a trusted CA. In addition, certificate authentication is more convenient because no local database of user public keys is required on the server.
http://www.ssh.com/support/documentation/on line/ssh/adminguide/32/Certificate_Authentication-2.html
Kerberos Authentication :
authentication based on Kerberos tickets, e.g. for single-sign-on configurations
http://www.ssh.com/support/documentation/on line/ssh/adminguide/32/Kerberos_Authentication.html
Authenticate through PAM :
When PAM is used, SSH Secure Shell transfers the control of authentication to the (Linux) PAM library. PAM handles the authentication, and tells SSH Secure Shell whether or not the authentication was successful.
http://www.ssh.com/support/documentation/on line/ssh/adminguide/32/Pluggable_Authentication_Module__PAM_.html

Server authentication

All of the above is about client authentication : the remote system checks whether it should allow you access, by asking a login name +password, checking a key, checking what host you connect from, etc.

You don't want to be sending this sort of security-related information to or initiate transactions with a rogue server (man-in-the-middle attack, hijacking, spoofing, ...). Therefore, it is possible to have the server authenticate itself while you set up the connection. This tells you you're actually talking to the server you think you're talking to, so you can be comfortable in telling it your password, sending your files to it, etc.

The remote host can authenticate itself using either

http://www.ssh.com/support/documentation/on line/ssh/adminguide/32/Server_Authentication.html


Other security measures

As such, ssh is only secure in that it provides a secure (encrypted) channel over which to transfer data, such as passwords or confidential files. Client / user authentication is a standard feature of any multi-user or networked system. Server authentication adds a level of security in that you can trust that your not sending confidential data to a rogue host.

When using user or host-based authentication based on "something you have" (a private/public key), it is important that you can trust those, i.e that noone but the intended user has access to the private key. As the key is stored in the user's home directory, this means access to that home directory or to the user's original login account compromises the key, and grants access to all remote accounts you've set up to use that key. It's best to protect your keys with a passphrase, and use ssh-agent and ssh-askpass to manage them in a user-friendly way.

In addition, you should build security into your network to prevent unauthorized access to your ssh servers. Good security is layered, and progressively more granular. This allows for easy measures to block the bulk of undesirable connections and provides a safety net should one of the measures be circumvented. Here's an example of some additional measures

firewall
configure your perimeter firewall to allow access to ssh ports from only those hosts (ip addresses) that need it.
In addition, you can also install iptables on the servers to further filter incoming connections from within the network
tcpwrapper
configure /etc/hosts.allow and hosts.deny on the server(s) to restrict access to your daemons (may include ssh), based on host names, ip addresses, network segments, user accounts, and groups. see man 5 hosts_access
/etc/sshd_config
use the AllowUsers AllowGroups DenyUsers DenyGroups in sshd_config to define which users are allowed to initiate a connection, and block unwanted attempts even before the authentication procedure starts. see man 5 sshd_config
decide if you want to allow remote logins from root, and consider using su or sudo in stead or disable password authentication for root (PermitRootLogin)
decide whether or not to trust user-specific files (writable by that user account) such as ~/.ssh/.shosts or ~/.ssh/known_hosts
... and consider any other configuration option that may have its place in a security policy : number of authentication attempts, time-outs, encryption algorithms, ... see man 5 sshd and man 5 sshd_config.
authentication
implement passwordless authentication in a manner that suits your needs but limited to those users and hosts that really need it. When you allow an account to (automatically) log in to another account on a different system, think of the consequences if that account falls in the wrong hands
limited use
the known_hosts or authorized_keys files can be used to specify what command(s) the user is allowed to execute and can contain other values (for corresponding sshd_config directives) that may limit what the ssh user can do (eg. don't create ssh tunnels), so you can fine-tune your configuration on a per-user basis and link it to an authentication method.
/etc/nologin
if the file /etc/nologin exists, all users except root are prevented from logging in (including via an ssh session). see man 5 nologin

references

openssh

The Snail Book, or SSH: The Secure Shell - The Definitive Guide,by Daniel J. Barrett, Ph. D., Richard E. Silverman, and Robert G. Byrnes. (O'Reilly)

ssh.com is (the website of a distributor of) a commercial implementation of ssh. There are some differences between ssh and openssh, especially in file names and paths, but it's a useful resource to gatjher the general principles : SSH Admin Guide


Koen Noens
August 2008