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 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
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
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 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 rsa -b 4096 -C "user@example.com"
This generates an RSA key pair with 4096 bits length associated with the user@example.com email.
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 keyuserName
andexpireOn
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:
- 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.
- Eliminate Weak Passwords: Enforcing key-based authentication eliminates the risk of users setting weak or easily guessable passwords, which is a common vulnerability.
- Audit Trail: SSH key pairs provide better audit trails and monitoring capabilities, as each key can be associated with a specific user or system.
- 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
On the remote server open the SSH daemon configuration file as a superuser
:
sudo nano /etc/ssh/sshd_config # may be changed to vim
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)
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.
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 (3)
Great article! I appreciate the detailed breakdown of SSH setup and security best practices, especially the emphasis on key-based authentication and disabling password logins for enhanced security. One suggestion would be to include a troubleshooting section for common SSH connection issues, as beginners often face challenges with key permissions or firewall configurations. Overall, a very informative guide—well done!
Thank you Danish! Troubleshooting will be the next in line, please stay tuned
Continuance is here Debugging SSH connections: A Comprehensive Guide