Host-based authentication allows hosts to authenticate on behalf of all or some of the system's users. It can apply to all users on a system or a subset using the Match directive. This type of authentication can be useful for managing computing clusters and other fairly homogenous pools of machines.
In all, three files on the server and two on the client must be modified to prepare for host-based authentication.
Client Configuration for Host-based Authentication
On the client or source host, two files must be configured in addition to at least one host key existing:
- /etc/ssh/ssh_known_hosts - global file for public keys for known hosts
- /etc/ssh/ssh_config - allow clients to request host-based authentication
The remote server's host key must be stored on the client, either in the global client configuration file, /etc/ssh/ssh_known_hosts, or the relevant users' configuration files in ~/.ssh/known_hosts.
Then the OpenSSH client's configuration must request host-based authentication when connecting, either for all hosts or for specific ones. Also, the OpenSSH client configuration file must be set to enable ssh-keysign(8). It is a helper application to access the local host keys and generate the digital signature required for host-based authentication. The EnableSSHKeysign configuration must be done globally in /etc/ssh/ssh_config. The program ssh-keysign(8) itself must be SUID root, but that was probably set when it was installed and no changes there are needed.
Here is an excerpt from /etc/ssh/ssh_config on the client trying host-based authentication to all machines:
Host * HostbasedAuthentication yes EnableSSHKeysign yes
Note that the Host directive in ssh_config(5) can be used to further constrain access, and other configuration specifics, to a particular server or group of servers.
Host *.pool.example.org HostbasedAuthentication yes EnableSSHKeysign yes
If the home directory of the client host is one that is shared with other machines, say using NFS or AFS, then it may be useful to look at the NoHostAuthenticationForLocalhost directive, too.
The global hosts file, /etc/ssh/ssh_known_hosts, must contain a valid public key for the target machine. This is to avoid having to add the key to each user's known_hosts file individually.
Finally, at least one of the following files must exist and contain the appropriate private key. The private key used should match the public key stored in the server or target host's ssh_known_hosts file. Any of the four types can be used, RSA, DSA, ECDSA, or Ed25519. Although use of DSA might be considered deprecated at this time.
The program ssh-keysign(8) needs to read the client host's private keys in /etc/ssh/. It is enough to have the keys by themselves, or at least one key. If the client host's private key does not exist, it will be necessary to add one manually before host-based authentication will work. An easy way to add the key is to install the OpenSSH server. These keys are then created automatically when the package containing sshd(8) is installed. Note that the client's machine does not have to have an SSH server actually running in order to use host-based authentication. So it is entirely feasible to install but then disable or uninstall the SSH server on the client's machine just to get the host keys in place.
Server Configuration for host-based authentication
Three files on the server or target host must be modified to get host-based authentication working:
- /etc/shosts.equiv - same syntax as old rhosts.equiv, can point to netgroups
- /etc/ssh/ssh_known_hosts - hold the identities of the clients
- /etc/ssh/sshd_config - turn on host-based authentication
This file resides in the directory /etc/ in OpenBSD which this book uses for the reference system when possible. On other systems the file might be found in the directory /etc/ssh/. Either way, the shosts.equiv file identifies which addresses are allowed to try authenticating. The file can contain hostnames, IP addresses, or netgroups. It is best to keep this file simple and oriented to just the list of hosts, either by name or IP number. It provides only the first cut, anyway. For fine tuning, use sshd_config(5) to set or revoke access for specific users and groups.
client1.example.org 192.0.2.102 client8.example.org -bull @statcluster
Two more files may optionally be modified, if they are referred to from within shosts.equiv. Each line in the netgroup file consists of a net group name followed by a list of the members of the net group, specifically host, user, and domain.
/etc/netgroup default netgroup list /etc/netgroup.db netgroup database, build from netgroup
However, these are mostly legacy from the old rhosts and can be avoided.
Again, on some systems the location may vary. Some will put shosts.equiv in /etc/ and others in /etc/ssh/. Check the manual page for sshd(8) for the actual system to be sure.
Those hosts listed in the server's shosts.equiv must also have their public keys in /etc/ssh/ssh_known_hosts on the server to be acknowledged. There are three required data fields per line. First is the host name or IP address or comma separated list of them, corresponding to those from shosts.equiv. Next is the key type, either ssh-rsa for RSA keys or ssh-ed25519 for Ed25519 keys. Third is the public key itself. Last, and optionally, can be a comment about the key.
desktop,192.0.2.102 ssh-rsa AAAAB3NzaC1yc2EAAAABIw ... qqU24CcgzmM=
There are many ways of collecting the public key information. It can be copied using sftp(1), copied from ~/.ssh/known_hosts or it can be grabbed using ssh-keyscan(1). Though the latter two only work if the client host also has an SSH server running.
$ ssh-keyscan -t rsa client.example.org >> /etc/ssh/ssh_known_hosts
If it is not possible for there to be a valid DNS entry resolving the hostname and address of the client, then it might be necessary to use a work-around to make up for that lack. One choice is to use or set up a local name service using dnsmasq or some other easy option. Or another choice is to set sshd(8) to accept the hostname information provided in the connection itself as being what it claims to be. See the HostbasedUsesNameFromPacketOnly directive for sshd_config below.
The third file that must be changed on the server is sshd_config. It must be told to allow host-based authentication. That is done using the HostbasedAuthentication directive, either for all users or just some users or groups.
Host-based authentication can be limited to specific users or groups. Here is an example excerpt from sshd_config allowing allow any user in the group cluster2 to let the hosts authenticate on their behalf:
Match Group cluster2 HostbasedAuthentication yes
Certain types of host keys can be whitelisted using HostbasedAcceptedKeyTypes with a comma-delimited list of acceptable key types. All the key types allowed must be listed because those not listed are not allowed, but patterns can be used in the whitelist. Below, Ed25519 and ECDSA keys are allowed, but others, such as RSA and DSA are not.
HostbasedAuthentication yes HostbasedAcceptedKeyTypes ssh-ed25519*,ecdsa-sha2*
If the client machine is not listed in DNS, then the server might have trouble recognizing it. In that case you might have to tell sshd(8) not to do reverse lookups in DNS for connecting hosts. Excerpt from /etc/ssh/sshd_config to work around lack of DNS records for the client using the HostbasedUsesNameFromPacketOnly directive. This can be important on informal LANs.
HostbasedAuthentication yes HostbasedUsesNameFromPacketOnly yes
Sometimes the host trying to connect gets identified to the target host as something other than what was expected. So make sure that the configuration files match what the host is actually calling itself.
Local user host-based authentication
The list of allowed hosts can be either local for the user or global. Individual users can have a local .shosts containing a list of trusted remote machines, or user-machine pairs, which are allowed to try host-based authentication.
.shosts must not writable by any group or any other users. Permissions set to 0644 should do it. The usage and format of .shosts is exactly the same as .rhosts, but allows host-based authentication without permitting login by insecure, legacy tools rlogin and rsh. The list is one line per host. The first column is obligatory and contains the name or address of the host permitted to attempt host-based authentication.
The second column is optional contains either a user name or netgroup name. But the user name checks using this method are not secure and restricting which specific users or groups may authenticate should be configured in sshd_config instead by using the Match Group directive.
See the manual page hosts.equiv(5) for more details on .shosts.
Configuration should be quite straight forward, with small changes in only three files on the server and two on the client to manage. If there are difficulties, be prepared to run sshd(8) standalone at debug level 1 (-d) to 3 (-ddd) and ssh(1) at debug level 3 (-vvv) a few times to see what you missed. The mistakes have to be cleared up in the right order, so take it one step at a time.
If the server produces the message debug3: auth_rhosts2_raw: no hosts access file exists turns up, the shosts.equiv file is probably in the wrong place or missing and no ~/.shosts lies in reserve on that account.
If the server cannot find the key for the client despite it being in known_hosts and if the client's host name is not in regular DNS, then it might be necessary to add the directive HostbasedUsesNameFromPacketOnly. This uses the name supplied by the client itself rather than doing a DNS lookup.
Here is a sample excerpt from a successful host-based authentication for user fred from the host at 192.0.2.102, also known as desktop1, using an Ed25519 key. The server first tries looking for an ECDSA key and does not find it.
# /usr/sbin/sshd -ddd debug2: load_server_config: filename /etc/ssh/sshd_config ... debug3: /etc/ssh/sshd_config:111 setting HostbasedAuthentication yes debug3: /etc/ssh/sshd_config:112 setting HostbasedUsesNameFromPacketOnly yes ... debug1: sshd version OpenSSH_6.8, LibreSSL 2.1 ... debug1: userauth-request for user fred service ssh-connection method hostbased [preauth] debug1: attempt 1 failures 0 [preauth] debug2: input_userauth_request: try method hostbased [preauth] debug1: userauth_hostbased: cuser fred chost desktop1. pkalg ecdsa-sha2-nistp256 slen 100 [preauth] ... debug3: mm_answer_keyallowed: key_from_blob: 0x76eede00 debug2: hostbased_key_allowed: chost desktop1. resolvedname 192.0.2.102 ipaddr 192.0.2.102 debug2: stripping trailing dot from chost desktop1. debug2: auth_rhosts2: clientuser fred hostname desktop1 ipaddr desktop1 debug1: temporarily_use_uid: 1000/1000 (e=0/0) debug1: restore_uid: 0/0 debug1: fd 4 clearing O_NONBLOCK debug2: hostbased_key_allowed: access allowed by auth_rhosts2 debug3: hostkeys_foreach: reading file "/etc/ssh/ssh_known_hosts" debug3: record_hostkey: found key type ED25519 in file /etc/ssh/ssh_known_hosts:1 debug3: load_hostkeys: loaded 1 keys from desktop1 debug1: temporarily_use_uid: 1000/1000 (e=0/0) debug3: hostkeys_foreach: reading file "/home/fred/.ssh/known_hosts" debug1: restore_uid: 0/0 debug1: check_key_in_hostfiles: key for host desktop1 not found Failed hostbased for fred from 192.0.2.102 port 10827 ssh2: ECDSA SHA256:CEXGTmrVgeY1qEiwFe2Yy3XqrWdjm98jKmX0LK5mlQg, client user "fred", client host "desktop1" debug3: mm_answer_keyallowed: key 0x76eede00 is not allowed debug3: mm_request_send entering: type 23 debug2: userauth_hostbased: authenticated 0 [preauth] debug3: userauth_finish: failure partial=0 next methods="publickey,password,keyboard-interactive,hostbased" [preauth] debug1: userauth-request for user fred service ssh-connection method hostbased [preauth] debug1: attempt 2 failures 1 [preauth] debug2: input_userauth_request: try method hostbased [preauth] debug1: userauth_hostbased: cuser fred chost desktop1. pkalg ssh-ed25519 slen 83 [preauth] debug3: mm_key_allowed entering [preauth] debug3: mm_request_send entering: type 22 [preauth] debug3: mm_key_allowed: waiting for MONITOR_ANS_KEYALLOWED [preauth] debug3: mm_request_receive_expect entering: type 23 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 22 debug3: mm_answer_keyallowed entering debug3: mm_answer_keyallowed: key_from_blob: 0x7e499180 debug2: hostbased_key_allowed: chost desktop1. resolvedname 192.0.2.102 ipaddr 192.0.2.102 debug2: stripping trailing dot from chost desktop1. debug2: auth_rhosts2: clientuser fred hostname desktop1 ipaddr desktop1 debug1: temporarily_use_uid: 1000/1000 (e=0/0) debug1: restore_uid: 0/0 debug1: fd 4 clearing O_NONBLOCK debug2: hostbased_key_allowed: access allowed by auth_rhosts2 debug3: hostkeys_foreach: reading file "/etc/ssh/ssh_known_hosts" debug3: record_hostkey: found key type ED25519 in file /etc/ssh/ssh_known_hosts:1 debug3: load_hostkeys: loaded 1 keys from desktop1 debug1: temporarily_use_uid: 1000/1000 (e=0/0) debug3: hostkeys_foreach: reading file "/home/fred/.ssh/known_hosts" debug1: restore_uid: 0/0 debug1: check_key_in_hostfiles: key for desktop1 found at /etc/ssh/ssh_known_hosts:1 Accepted ED25519 public key SHA256:BDBRg/JZ36+PKYSQTJDsWNW9rAfmUQCgWcY7desk/+Q from fred@desktop1 debug3: mm_answer_keyallowed: key 0x7e499180 is allowed debug3: mm_request_send entering: type 23 debug3: mm_key_verify entering [preauth] debug3: mm_request_send entering: type 24 [preauth] debug3: mm_key_verify: waiting for MONITOR_ANS_KEYVERIFY [preauth] debug3: mm_request_receive_expect entering: type 25 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 24 debug3: mm_answer_keyverify: key 0x7e49a700 signature verified debug3: mm_request_send entering: type 25 Accepted hostbased for fred from 192.0.2.102 port 10827 ssh2: ED25519 SHA256:BDBRg/JZ36+PKYSQTJDsWNW9rAfmUQCgWcY7desk/+Q, client user "fred", client host "desktop1" debug1: monitor_child_preauth: fred has been authenticated by privileged process ...
Note any warnings or error messages and read them carefully.