Logging into remote systems with SSH implementations is secure by default — but those connections are secured only in that they use the TLS protocol to encrypt network protocol exchanges. SSH can be made even more secure by using it to authenticate communicating hosts through the exchange of public keys — keys that are created using the ssh-keygen command.
This tutorial shows how to use the ssh-keygen command to create a new public key and how to use that key to do the following:
- upload the public key to a remote server to enable automated and authenticated logins;
- use the same public key on multiple remote servers; and
- use multiple public keys for different functions on the same server.
GUI versions of SSH usually include the same functionality as the command-line versions. For example, the PuTTYgen program is a GUI version of ssh-keygen for use with PuTTY, a GUI implementation of SSH for Windows. However, modern OSes, including Windows 10 and later, Linux and macOS, include command-line versions of the OpenSSH implementation of SSH.
This tutorial uses examples from OpenSSH in Windows PowerShell and in Linux Bash (Bourne Again Shell) command-line interfaces (CLIs), but they also should apply to the macOS version of OpenSSH. The advantage of using a CLI version of SSH is that commands are consistent across OSes, unlike with GUI versions that may implement commands using a variety of GUI techniques.
Why generate SSH keys?
SSH can be used without a prior exchange of public key pairs, and those uses can be reasonably secure. The best approach for securely authenticating SSH sessions, however, is to create a public key pair for the local computer and copy the public key file to the remote SSH server. Only a user with authenticated permission should be able to copy files to the server. If local users do not have sufficient permission, they can request that a system administrator of the remote host copy the files for them.
Putting a public key file on an SSH server enables the user associated with the public key to securely log in to the SSH server. This is done by having users authenticate their ownership of the public key by demonstrating they control the private key of the public key pair.
This tutorial addresses three use cases:
- Configuring an SSH server to recognize the SSH client by copying the public key file from the user’s local computer to the remote server.
- Copying a single user’s public key file to multiple remote servers. This enables the user to remotely access multiple systems via SSH using the same login ID and is particularly useful for system administrators doing remote system maintenance, for example.
- Copying multiple public keys associated with different user accounts, each with varying levels of permission to a remote server. In this case, the user employs one public key to authenticate when logging in to terminal emulation sessions with the remote server and another public key with higher permissions for doing system administration.
The procedures outlined in this tutorial are best applied to individual clients and servers and to demonstrate how SSH keys can be generated and used. Centralized key management systems are preferred for more general use in large organizations where many different users need to be accredited for access to many different servers. Those key management systems are able to automate the processes explained here, however.
How SSH works
SSH depends on public key authentication to negotiate a secure connection between an SSH client and an SSH server. SSH is often used to make an ad hoc connection between the client and the remote server without a previously created public key pair, for example, with a command like this:
PS C:Userspeter.ssh> ssh 192.0.2.44 -l peter
In this case, the ssh command, issued at the Windows PowerShell command prompt, includes the IP address of the remote server and the -l option, which specifies a valid user account on the remote server. Once the SSH connection is established, users are prompted to enter the password for their user accounts, in this case, the password for user peter.
In this example, the client and server can’t yet authenticate to each other using public keys, so the user is prompted:
The authenticity of host '192.0.2.44' can't be established.
This prompt is followed by the fingerprint of the server and a prompt to continue connecting. The fingerprint is a secure hash of the server’s public key, which is stored in a file in the SSH directory. On Linux systems, the default location for SSH keys is in the user’s personal directory in the file ~/.ssh/known_hosts. On Windows systems, the default file location is in the user’s personal directory in the file C:Usersusername.sshknown_hosts.
In this example, an SSH connection is initiated between the SSH client and the SSH server on the same host using the loopback address, 127.0.0.1. This address is often used for testing purposes and directs all network traffic to client and server software running on the local computer. The default client connection in this example uses an Elliptic Curve Digital Signature Algorithm (ECDSA) key.
The best security practice for SSH calls for the user to copy that fingerprint and authenticate it against the public key of the remote server. In practice, this step is often skipped when the user is confident that the remote server is known to be a trusted server. Once the user accepts the authenticity of the remote server, that server and its fingerprint are added to the known hosts file, and subsequent connections can be made directly.
This ad hoc approach can be adequately secure when the user is connecting to a server inside a protected network, but it can be riskier for connecting to other remote servers. This is where ssh-keygen can streamline the exchange of public key authentication.
Generating a new SSH key
The ssh-keygen command is a component of most SSH implementations used to generate a public key pair for use when authenticating with a remote server. In the typical use case, users generate a new public key and then copy their public key to the server using SSH and their login credentials for the remote server.
By default, ssh-keygen creates an RSA key pair and stores the public key in a public key file named .ssh/id_rsa.pub and a private key file named .ssh/id_rsa.
Key generation begins with something like the following command:
$ ssh-keygen -t rsa
In this basic example, ssh-keygen is invoked to generate a new SSH key pair using the RSA public key algorithm.
This screenshot shows what happens when the ssh-keygen command runs with the -t option to specify an RSA key. The ssh-keygen command then does the following:
- Generates a public key pair.
- In response to the prompt “Enter passphrase,” the user can enter a key passphrase to protect access to the private key. Using a passphrase enhances security, and a passphrase is recommended for sensitive applications. If a key is not passphrase-protected, an attacker who gains access to the user’s system would also gain direct access to possibly sensitive remote systems. In some cases, it may be acceptable to press enter for no passphrase in response to this prompt.
- The private key, also known as identification, is stored in a file named id_rsa in the .ssh directory of the user’s home directory — this is designated as HOME$/ in Windows, and as ~/ in Linux and other Unix-based OSes.
- The public key is saved in a file with the same name as the private key but with the extension .pub producing a file named pub in the same directory.
- The key fingerprint is created and displayed. The fingerprint is a short sequence of bytes generated with a cryptographic hash function applied to the generated key. SSH implementations can use fingerprints to authenticate the public key. The fingerprint includes any comments applied to the key pair. The fingerprint also identifies the hashing algorithm used to create the public key. In this case, the algorithm is Secure Hash Algorithm 256, or SHA-256, with a digest composed of 256 bits.
- A randomart image is displayed. This is an image consisting of American Standard Code for Information Interchange, or ASCII, characters based on the data in the key fingerprint. The key’s randomart image is intended to enable humans to visually determine whether fingerprints for different servers are identical or not. The bits in the fingerprint are treated like instructions for an algorithm that outputs the randomart image.
The ssh-keygen command creates two files, one public and one private, for the local computer. In this case, the two files are named:
- id-rsa contains the private key of the pair. This file should never be shared or copied to any remote system unless it is a system under the key pair holder’s control.
- id-rsa.pub contains the public key of the pair. This file can be shared and copied to other systems, especially when the user plans to log in to those systems using SSH.
The file name for other key types use, by default, the form of ~/.ssh/id_[key type] — specified to be in the .ssh directory of a user’s Unix-based account — so the default file names for each different type of key include the following:
|Key type||Public key file name||Private key file name|
Ed25519 (Edwards-curve DSA)
Copying the public key file to a server — or to multiple servers — is the next step to getting automatic strong authentication when connecting to remote SSH servers.
Copying a public key to a server
The next step in streamlining the login process is to copy the user’s newly generated public key from the user’s local system to the remote SSH server. When both systems are running the OpenSSH implementation on a Unix-based OS, including Linux or macOS, the ssh-copy-id command can be used to install an SSH key as an authorized login key. The new public key is then appended to the authorized_keys file, which the SSH implementation running on the remote server checks when a connection is requested from the local computer — for example:
$ ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]/home/peter/.ssh/authorized_keys
In this example, the public key file is copied into the authorized_keys file.
However, the ssh-copy-id command may not always be available, for example, when working with Windows systems. To copy a public key to a server from a Windows PowerShell command line, use the following command:
PS c:> type $env:USERPROFILE.sshid_rsa.pub | ssh [email protected] "cat >> .ssh/authorized_keys"
This compound command uses the PowerShell type command to output the contents of the public key file. The contents are then piped — using the | symbol — to a new SSH connection. The final quoted section of this command uses the cat command on the remote server to append the new public key file to the end of the authorized_keys file. This part of the command is necessary to avoid overwriting the authorized_keys file, which would overwrite any existing keys previously added to that file.
Now, the public key resides on the remote server and is stored in the .ssh/authorized_keys file. The next time an SSH connection is attempted from the local computer, the session is initiated without the need to manually enter the user ID and password.
The ability to log in to an SSH server on a remote server without the need to reenter one’s password every time may be a convenience, but this is not the primary reason to use a public key for SSH authentication. When SSH connections can be completed without needing the user to enter a passphrase, repetitive actions on the remote server can be accomplished without human intervention — for example:
- Incorporate SSH connections in batch files or shell scripts to automate repetitive actions, like copying log files or accessing remote email servers.
- Schedule repetitive actions that require authentication but that occur when the local computer is unattended.
- Provide convenience to users, which should not be discounted, as properly implemented public key authentication with SSH can be more secure than forcing users to rely on complicated passwords for systems that may be accessed infrequently.
Public key authentication with SSH is not sufficient for securing access to sensitive systems. While it may improve security, users and enterprises must take even more care to prevent unauthorized access to the local computers used to access remote SSH servers.
Copying a public key to multiple servers
System administrators, network managers and network security professionals who use the same login ID across an enterprise network often need to connect to many different remote servers. For especially large organizations, this type of access can be mediated through the use of SSH key management systems that can distribute public keys to the remote servers, as well as manage assignment of public key pairs to individuals who need them.
In practice, system administrators could manually copy the same public key to all of the servers they need access to. In that case, the sys admin issues the same command to copy the public key for each remote server — for example:
PS c:> type $env:USERPROFILE.sshid_rsa.pub | ssh [email protected] "cat >> .ssh/authorized_keys"
This command can be used in PowerShell to send the public key file id_rsa.pub to associate the public key to the user ID peter on the server with the hostname of ssh.example.org.
Copying multiple public keys to a server
Network and security professionals may need to use different identities, each of which has different sets of permissions, to access the same remote server. This approach compartmentalizes access and can be useful for different reasons, including the following:
- To comply with the principle of least privilege, multiple public key pairs can be assigned to identities that have different levels of privilege on a system for different functions. One key pair might be used to give limited access for testing, while another key pair might be used to gain administrative access to the system for managing user accounts.
- This approach enables tracking different functions performed by the same user. For example, an IT professional might use different public keys when working for different internal clients.
When adding multiple public keys to the same remote server, the public key file names are different and should be specified when running the ssh command — for example:
$ ssh -i ~/.ssh/id_Alice [email protected]
This command uses the -i option to specify an identity file, ~/.ssh/id_Alice, for the remote host to use to authenticate the connection.