DEV Community

Eugene Zimin
Eugene Zimin

Posted on • Edited on

Configuring SSH to Access Remote Server

Earlier in another article, we provided a detailed description of how to create and set up a Virtual Machine (VM) instance in the Google Cloud Platform (GCP) using Google Compute Engine (GCE). It is accessible here - Google Cloud: Provisioning a Virtual Machine and Accessing it via SSH.

Provisioning a GCP VM allows us to create our own powerful computing environment to serve as a sandbox or workspace for our further testing and experiments. Having successfully deployed a VM in GCP, the next crucial step is to establish a secure remote connection to this virtual machine. It is required by many reasons, starting from efficient administration and management up to the monitoring and observing it. Google Cloud Platform provides a straightforward method to configure SSH access to Compute Engine instances, facilitating an encrypted communication channel. In this article, we will outline the steps required to set up SSH access to a Google Compute Engine (GCE) virtual machine.

Few Words About SSH

Secure Shell (SSH) is a cryptographic network protocol and the de facto standard for secure remote login and command execution on Unix-like operating systems. SSH provides a secure encrypted channel over an unsecured network, preventing potential eavesdropping, packet sniffing, or man-in-the-middle attacks that could compromise login credentials or sensitive data. By leveraging strong encryption algorithms and authenticated key exchange, SSH ensures data integrity and confidentiality, making it an essential tool for securely administering remote servers, transferring files, and managing networked systems over insecure networks such as the internet.

SSH operates through the use of encrypted key pairs - a public key that gets placed on the remote server, and a private key that is kept secure by the client. The keys are very large numbers derived via a one-way mathematical function, making them virtually impossible to derive if intercepted during transmission.

When initiating an SSH connection, the client and server negotiate a secure symmetrical encryption cipher and session keys to use. This key exchange utilizes the private/public keys for authentication and protection against man-in-the-middle attacks. Once the secure tunnel is established, all subsequent commands, file transfers, and communications are encrypted between the client and server.
Figure 1. Communication schema for SSH exchangeFigure 1. Communication schema for SSH exchange

SSH supports several strong modern encryption algorithms such as AES, Blowfish, 3DES, and ciphers like ChaCha20. The specific algorithms used can be configured on both ends based on policy and requirements. SSH also provides data integrity verification through cryptographic message authentication codes like HMAC-SHA1 to detect tampering.

By default, SSH operates on TCP port 22, but can be configured to use any port. It supports various user authentication mechanisms like passwords, public keys, security keys, and more. SSH key-based authentication is considered more secure than basic password authentication.

Configuring SSH on Local Machine

Before initiating an SSH connection to our Google Cloud VM instance, we'll need to have SSH configured and set up on our local machine. The steps vary slightly depending on the operating system, as Linux and macOS usually have preinstalled SSH client which requires minimal configuration, whereas Window requires a bit more steps to make initial setup ready.

Linux and macOS

Most Linux distributions and macOS come pre-installed with OpenSSH, a free open source SSH client and server utility. To check if it's installed, we can open a terminal and run:

ssh -V

# Response should be something like the line below
# OpenSSH_9.6p1, LibreSSL 3.3.6
Enter fullscreen mode Exit fullscreen mode

This should display the installed OpenSSH version. If not installed, we can get it through the operating system's package manager, for Linux it may be usually apt or yum for macOS brew is very popular.

Windows

Windows 11 has pre-installed SSH client. To check it we need to open cmd application (a.k.a Command Prompt) and run the same command:

ssh -V
Enter fullscreen mode Exit fullscreen mode

If we will see a similar output we saw for Linux and macOS (some names may vary), it means we have installed SSH client and we are good to go.

A little bit more complicated situation happens if Windows doesn't have preinstalled client. In that case we may use one of the following 3rd party applications to run it:

Generating Key Pairs

To establish secure SSH connections, we need to generate cryptographic key pairs consisting of a public and private key. The ssh-keygen utility allows us to create these key pairs locally on our machine. Before we start creating a key pair it may worth to overview file schema for the it.
Figure 2. Schema of SSH key pairsFigure 2. Schema of SSH key pairs

We can run ssh-keygen in a terminal/command prompt and follow the prompts. Some common options include:

  • -t to specify the key type (e.g. rsa, ecdsa, ed25519)
  • -b to set the key length in bits (e.g. 2048, 4096)
  • -C to add a comment to identify the key

For example:

ssh-keygen -t ecdsa -b 521
Enter fullscreen mode Exit fullscreen mode

will give us the following output:

Generating public/private ecdsa key pair.
Enter file in which to save the key (~/.ssh/id_ecdsa): ~/.ssh/id_ecdsa_gce
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_ecdsa_gce
Your public key has been saved in ~/.ssh/id_ecdsa_gce.pub
The key fingerprint is:
SHA256:Utwi6b8NzdJSFT5RlH6HOvr7y5HvNJiw08YB7wxAaQU user@laptop.local
Enter fullscreen mode Exit fullscreen mode

There are various key types we may use. Here are the most popular ones we may want to generate:

  • RSA - One of the oldest and most widely used key types. Recommended minimum key length is 2048 bits, with 4096 bits being more secure.
  • ECDSA (Elliptic Curve Digital Signature Algorithm) - This key type is based on elliptic curve cryptography which provides equal security strength with smaller key sizes compared to RSA.
  • Ed25519 - A modern EdDSA (Edwards-curve Digital Signature Algorithm) key type that provides better performance and security than RSA/ECDSA. Ed25519 uses elliptic curve cryptography with a 256-bit key length.

While RSA is the most widely compatible, Ed25519 keys are considered more secure and efficient for modern systems. We can check which key types our SSH server and client support using ssh -Q key.

During key generation, we have the option to protect the private key with a passphrase. While providing a passphrase enhances security, we need to enter it every time the key is used.

After generating, both keys - private and public - will be saved in the local SSH configuration folder. Usually (for Linux and macOS systems) this folder is under the following path - ~/.ssh/. Both keys by default use their name pattern as id-<algorithm-name>[.pub] , where extension .pub is used only for public key from the pair. As an example, user may get id-rsa and id-rsa.pub if there was RSA algorithm used, or id-ed25519 and id-ed25519.pub there was Ed25519 algorithm in use during key pair generation.

Next step would be to copy the content of the public key (which has .pub extension) to the remote server, in accordance with the Figure 2. We may copy the content of the public key and paste it on the new line of the ~/.ssh/authorized_keys file for the user which we will be connecting to. We can do that by many ways, but usually we should have access to the remote server via screen sharing or through the web interface, like with Google Compute Engine in GCP, where we can paste our public key.

NOTE FOR GCP
GCP requires to add at the end of the key userName and expireOn in form of JSON. We should do that manually to get the ready for pasting. Eventually we should have something like that:

ecdsa-sha2-nistp521 AAAAE2...== user@laptop.local {"userName":"<user@yourgcp.email>","expireOn":"2024-05-06T08:43:20+0000"}

At the same time private key (without .pub extension) remains securely stored on our local machine. We must keep the private key safe and never share it.

With our key pair ready, we can now proceed to configure server to use key pair only and disallow further access using username and password.

Configuring Server Side

While using SSH keys provides a much more secure authentication mechanism compared to passwords, many cloud providers, including Google Cloud Platform, enable password-based logins to SSH servers by default. However, relying solely on password authentication for SSH connections introduces potential security risks and is considered a poor practice, so we should consider to disable it and keep it disabled.

Main reasons why we should do that lay in the security considerations. Having password authentication enabled we allow anyone to try to connect to remote server and try out to brute force the password. Sometimes password are not that strong and such an attack might be successful.

That being said the advantages of disabling Password authentication for the remote server are as follows:

  1. Enhanced Security: SSH keys utilize strong encryption algorithms and prevent brute-force and dictionary attacks that are common threats to password-based authentication. Keys are virtually impossible to guess or decrypt.
  2. Eliminate Weak Passwords: Enforcing key-based authentication eliminates the risk of users setting weak or easily guessable passwords, which is a common vulnerability.
  3. Audit Trail: SSH key pairs provide better audit trails and monitoring capabilities, as each key can be associated with a specific user or system.
  4. Compliance: Many security standards and best practices, such as PCI-DSS, HIPAA, and NIST, recommend or mandate the use of key-based authentication over passwords for remote access to servers.

At the same time nothing comes without price. If any of the parts for the key pair would be lost or corrupted, it means we may also lost the access to the server, thus we should be very careful and keep generated key pair as good as possible.

To disable password authentication for the SSH server we need to modify the SSH daemon (sshd) configuration file. To do that we need to connect to the VM instance over SSH. We will use our new generated private key to connect to the server (don't forget to replace username and address of the server).

ssh -i ~/.ssh/id_ed25519 remote-user@server-ip-address
Enter fullscreen mode Exit fullscreen mode

On the remote server open the SSH daemon configuration file as a superuser:

sudo nano /etc/ssh/sshd_config # may be changed to vim
Enter fullscreen mode Exit fullscreen mode

In the file editor find the line #PasswordAuthentication yes and change it to PasswordAuthentication no and save the file and exit the editor.

Finally we need to restart the SSH daemon to make our changes take effect:

sudo systemctl restart sshd # (or command for your OS)
Enter fullscreen mode Exit fullscreen mode

 
After making this change, the SSH server will only allow key-based authentication, and password logins will be disabled.

It's important to note that we should have at least one authorized SSH key added to the VM instance before disabling password authentication. Otherwise, we may get locked out of the system.

By enforcing key-based authentication and disabling password logins, we significantly enhance the security of our SSH server and remote access to our Google Cloud virtual machines, aligning with industry best practices for secure system administration.

Simplifying Connections with SSH Client Configuration File

While we can directly specify options when invoking the ssh command, using a configuration file allows us to set persistent options, create aliases, and simplify the process of connecting to remote hosts. This is particularly useful when managing multiple SSH connections to different servers or cloud instances.

On Unix-based systems (Linux and macOS), the SSH client refers to the configuration file located at ~/.ssh/config location. On Windows systems using the OpenSSH client, the file is located at %UserProfile%.ssh\config.

The ~/.ssh/config file supports a wide range of configuration options and settings that can be applied globally or to specific hosts. Here are some common use cases:

Creating Aliases

We can define aliases or shorthand names for hosts, making it easier to connect without having to type out the full hostname or IP address every time.

Host remote_server
    HostName remote_host.com
    User ubuntu
Enter fullscreen mode Exit fullscreen mode

Instead of remote_host.com it is possible to use IP address of the remote server directly. Now we can use:

ssh remote_server
Enter fullscreen mode Exit fullscreen mode

to reach remote server instead of using its name remote_host.com or direct IP address. It's clear that aliases might be different and their usage makes it easier to set up connections.

Setting Default Options

We can set default options that will be applied to all SSH connections, such as the default user, identity file (private key), and forwarding settings.

Host *
    User ubuntu
    IdentityFile ~/.ssh/id_rsa
    ForwardAgent yes
Enter fullscreen mode Exit fullscreen mode

In this configuration instead of doing aliasing, we set default configuration which will be applied to all connections and hosts. 1. The asterisk (*) is a wildcard that matches any hostname.

User ubuntu sets the default user account to be used for SSH connections. In this case, it will attempt to log in as the ubuntu user on remote hosts.

IdentityFile ~/.ssh/id_rsa specifies the path to the default SSH private key file that should be used for authentication. Here, it is set to ~/.ssh/id_rsa, which is the standard location for an SSH private key on Unix-based systems. That's convenient way to use previously generated key pair.

ForwardAgent yes option enables SSH agent forwarding. When enabled, it allows authentication keys loaded into the local SSH agent to be automatically forwarded to the remote host, enabling single sign-on (SSO) functionality. This can be useful when you need to connect to additional hosts from the initial remote host without re-authenticating.

Host-Specific Settings

We can define settings specific to a particular host or group of hosts, such as using a different private key, enabling compression, or specifying a non-standard port.

Host *.example.com
    IdentityFile ~/.ssh/id_rsa
    Compression yes

Host gcp-instance
    HostName 34.123.45.67
    User user2
    Port 2222
Enter fullscreen mode Exit fullscreen mode

In this configurations we used 2 different values for Host key. In the first configuration option host entry applies settings to any host whose name matches the pattern *.example.com. The * acts as a wildcard, so this would include hosts like server1.example.com, web.example.com, or any other subdomain under the example.com domain.

IdentityFile ~/.ssh/id_rsa specifies that the private SSH key located at ~/.ssh/id_rsa should be used for authentication when connecting to hosts matching the *.example.com pattern.

Second configuration behaves differently and creates an alias for the only single IP address of 34.123.45.67 in form of the gcp-instance.

Proxying Through Bastion Hosts

If we need to connect to instances that are not directly accessible (e.g., behind a bastion host or a NAT gateway), we can configure SSH tunneling through a jump host.

Host gcp-instance
    HostName 10.0.0.5
    User user2
    ProxyJump bastion.example.com
Enter fullscreen mode Exit fullscreen mode

By leveraging the ~/.ssh/config file, we can streamline our SSH workflow, ensure consistent settings across connections, and simplify the management of multiple remote hosts, including our Google Cloud VM instances.

To get started, we can create or edit the file using a text editor, and refer to the ssh_config man pages (man ssh_config) for a comprehensive list of available options and their descriptions.

Continuance

The next article in the cycle is dedicated to the debugging and troubleshooting different connection errors happening during establishing SSH connections - Debugging SSH connections: A Comprehensive Guide

Top comments (0)