[ Team LiB ] Previous Section Next Section

Recipe 6.8 Authenticating by Trusted Host

6.8.1 Problem

You want to authenticate between an OpenSSH client and server using hostbased or "trusted host" authentication.

6.8.2 Solution

Suppose you want to allow the account [email protected] access to [email protected]. Then:

  1. Make sure hostbased authentication enabled in on server.foo.net:

    /etc/ssh/sshd_config:
    HostbasedAuthentication yes
    IgnoreRhosts no

    and optionally (see "Discussion"):

    HostbasedUsesNameFromPacketOnly yes

    and restart sshd.

  2. Ensure that the ssh-keysign program is setuid root on the client machine. The file is usually located in /usr/libexec or /usr/libexec/openssh:

    $ ls -lo /usr/libexec/openssh/ssh-keysign
    -rwsr-xr-x   1 root   222936 Mar  7 16:09 /usr/libexec/openssh/ssh-keysign
  3. Enable trusted host authentication in your system's client configuration file: [Recipe 6.12]

    /etc/ssh/ssh_config:
    Host remotehost
            HostName remotehost
            HostbasedAuthentication yes
  4. Insert the client machine's host keys, /etc/ssh/ssh_host_dsa_key.pub and /etc/ssh/ssh_host_rsa_key.pub, into the server's known hosts database, /etc/ssh/ssh_known_hosts , using the client host's canonical name (supplicant.foo.net here; see "Discussion"):

    /etc/ssh/ssh_known_hosts on server.foo.net:
    supplicant.foo.net ssh-dss ...key...
  5. Authorize the client account to log into the server, by creating the file ~/.shosts:

    ~whosthere/.shosts on server.foo.net:
    supplicant.foo.net nocnoc

    If the account names on the client and server hosts happen to be the same, you can omit the username. (But in this case the usernames are different, nocnoc and whosthere.)

  6. Make sure your home directory and .shosts files have acceptable permissions:

    $ chmod go-w ~
    $ chmod go-w ~/.shosts
  7. Log in from supplicant.foo.net:

    $ ssh -l whosthere server.foo.net

6.8.3 Discussion

This recipe applies only to SSH-2 protocol connections. OpenSSH does support an SSH-1 type of trusted-host authentication (keyword RhostsRSAAuthentication) but as we've said before, we strongly recommend the more secure SSH-2.

Before using hostbased authentication at all, decide if you truly need it. This technique has assumptions and implications unlike other SSH user-authentication mechanisms:

Strong trust of the client host

The server must trust the client host to have effectively authenticated the user. In hostbased authentication, the server does not authenticate the user, but instead authenticates the client host, then simply trusts whatever the client says about the user. If the client host is compromised, all accounts on the server accessible via hostbased authentication are also immediately vulnerable.

Weak authorization controls

Individual users on the server can override hostbased restrictions placed by the sysadmin. This is why the server's IgnoreRhosts option exists.

If all you want is automatic authentication (without a password), there are other ways to do it, such as public-key authentication with ssh-agent [Recipe 6.9] or Kerberos. [Recipe 4.14]

If you decide to use hostbased authentication for an entire user population, read the relevant sections of SSH, The Secure Shell: The Definitive Guide (O'Reilly), which detail various subtleties and unexpected consequences of this mechanism.

Speaking of subtleties, the issue of the client's canonical hostname can be tricky. The SSH server will look up the client's host key by this name, which it gets from the client's IP address via the gethostbyname library function. This in turn depends on the naming service setup on the server side, which might consult any (or none) of /etc/hosts, NIS, DNS, LDAP, and so on, as specified in /etc/nsswitch.conf. In short, the client's idea of its hostname might not agree with the server's view.

To learn the client's canonical hostname as sshd will determine it, run this quick Perl script on the server:

#!/usr/bin/perl
use Socket;
print gethostbyaddr(inet_aton("192.168.0.29"), AF_INET) . "\n";

where 192.168.0.29 is the IP address of the client in question. You can also run this as a one-liner:

$ perl -MSocket -e 'print gethostbyaddr(inet_aton("192.168.0.29"),AF_INET)."\n"'

You might be tempted to run the host program instead (e.g., host -x 192.168.0.29) on the server, but the output may be misleading, since host consults only DNS, which the server's naming configuration might not use. If the SSH server cannot get any name for the client's address, then it will look up the client's host key in its known-hosts file by address instead.

And that's not all. The canonical hostname issue is further complicated, because the client independently identifies itself by name within the SSH hostbased authentication protocol. If that name does not match the one determined by the SSH server, the server will refuse the connection. There are many reasons why these names may not match:

  • The client is behind a NAT gateway

  • Names are simply not coordinated across the hosts

  • Your SSH connection is going through a proxy server

  • The SSH client host is multi-homed

If this problem occurs, you'll see this server error message in your syslog output:

userauth_hostbased mismatch: client sends name1.example.com,
but we resolve 192.168.0.72 to name2.example.com

The configuration keyword HostbasedUsesNameFromPacketOnly will relax this restriction in the SSH server:

/etc/ssh/sshd_config:
HostbasedUsesNameFromPacketOnly yes

This means that sshd uses only the self-identifying hostname supplied by the client in its hostbased authentication request, to look up the client's public host key for verification. It will not insist on any match between this name and the client's IP address.

The client-side, per-user configuration files in ~/.ssh may be used instead of the global ones, /etc/ssh/ssh_config and /etc/ssh/ssh_known_hosts. There is no harm in placing keys into the global list: it does not by itself authorize logins (an authorization task), but only enables authentication with the given client host.

You can authorize hostbased authentication globally on the server by placing the client hostname into /etc/shosts.equiv. This means that all users authenticated on the client host can log into accounts with matching usernames on the server. Think carefully before doing this: it implies a high level of inter-host trust and synchronized administration. You should probably customize the shosts.equiv file using netgroups to restrict hostbased authentication to user accounts; see the sshd manpage.

Lastly, note that earlier versions of OpenSSH required the ssh client program to be setuid for hostbased authentication, in order to access the client host's private key. But in the current version, this function has been moved into a separate program, ssh-keysign; the ssh program itself need no longer be setuid.

6.8.4 See Also

sshd(8), sshd_config(5), gethostbyname(3).

    [ Team LiB ] Previous Section Next Section