Skip to main content

SSH (Secure Shell)

SSH (Secure Shell) is an encrypted network protocol used for secure communication between devices. It allows remote access to another computer's or server's terminal as if you were physically present. It is widely used by system administrators, developers, and users who need secure remote access.

A key feature of SSH is its ability to encrypt all transmitted data, ensuring the security of passwords and commands. It supports asymmetric key authentication, further increasing connection security.

The SSH service typically runs on port 22 by default, and to access a server via SSH, you use the ssh command followed by the username and the server's IP address or domain name.

Let's imagine we have the user david on the machine we want to access and the machine's IP is 192.168.0.10. As long as you can reach the destination machine, we can execute

ssh [email protected]

# Pointing to a specific port on which the machine's SSH service is running.
ssh -p 2222 [email protected]

The commands above will ask for david's password when trying to log in as david.

The recommended practice is to disable SSH access via password and instead use public key authentication. This means that instead of typing a password when connecting, you authenticate your identity with a private key corresponding to a public key stored on the server.

This means we need two keys, one public and one private. Everything encrypted with the private key will only be decrypted with the public key. Not even the private key itself could decrypt what it encrypted. Likewise, everything encrypted with the public key will only be decrypted with the private key. These keys work in pairs. This encryption method is known as asymmetric encryption.

It's worth noting that even when using a password for authentication, communication will be encrypted by the SSH protocol. In the case of using the public and private key pair, these are only used for authentication.

Once authenticated, the SSH protocol will negotiate a symmetric key generated by it and common to both client and server to encrypt the data.

The use of keys for authentication offers several significant advantages compared to password-based authentication:

  • Enhanced security: SSH keys are much more secure than passwords, as they are more difficult to guess by brute force attacks.

  • Elimination of passwords: With the use of SSH keys, you can eliminate the need to enter passwords when connecting to remote servers. This simplifies the login process and eliminates the risk of passwords being intercepted or compromised.

  • Audit and centralized management: SSH keys can be managed centrally and audited more effectively than passwords. Administrators can control which keys have access to which servers and revoke compromised keys quickly and easily.

  • Ability to use two-factor authentication (2FA): SSH keys can be combined with two-factor authentication (such as passwords or token-based authentication) to provide an additional layer of security. This requires users to provide not only the SSH key but also another authentication factor to access the server.

Creating SSH Keys​

To configure public key authentication, you need to generate an SSH key pair (one public and one private) on your local machine and then add the content of the public key to the ~/.ssh/authorized_keys file on the remote server for the user you want to access. If we have the user david on the server and it's with him that we want to authenticate, it will be in /home/david/.ssh/authorized_keys.

If the server contains the public key and it can only decrypt what came from its pair, the private key, then we guarantee that whoever has the private key is who they say they are.

First, let's generate a key pair for use with SSH. We have several encryption algorithms we can use, but I'll only cover the two considered most secure.

The SSH key pair does not have an expiration time like a certificate. The private key should not be shared.

The RSA algorithm is from 1977 and more widely used than Ed25519 which is from 2011, although the latter is better. Let's see the differences.

CharacteristicRSAEd25519
TypeAsymmetricAsymmetric
Key SizeGenerally 2048 bits or more256 bits
Computational EfficiencyMore computationally intensiveMore computationally efficient
Key GenerationSlowerFaster
Signed Data SizeTends to be largerTends to be smaller
Resistance to Brute Force AttacksLess resistantMore resistant
Support and AdoptionWide adoption and support in many systems and protocolsGaining popularity, still in adoption process
Key Storage on ClientNeeds to store private key on clientNeeds to store private key on client
Key Storage on ServerNeeds to store public key on serverNeeds to store public key on server
Use in Current ApplicationsStill widely used in many scenariosGaining popularity, especially in environments where efficiency is a priority
SecurityRSAEd25519
VulnerabilitiesVulnerable to integer factorization attacksMore resistant to various types of attacks
Mathematical BasisBased on the integer factorization problemBased on the discrete logarithm problem in elliptic curves
Resistance to Brute Force AttacksLess resistantMore resistant
Known AttacksKnown attacks, such as factorization attacks and private key compromise attacksFewer known attacks due to its more recent nature

To create a key pair.

# The command below uses the RSA algorithm as default
# Uses 2048 bits and generates the id_rsa files for the private key and id_rsa.pub in ~/.ssh
ssh-keygen
# We can increase the number of bits to strengthen the algorithm's security.
# -N "" is to not pass a password for this key.
# -f is the name we will give to the key. We can already pass the path to where the minha_chave_rsa file will be.
ssh-keygen -t rsa -b 4096 -f ~/Desktop/minha_chave_rsa -N ""

# Using the Ed25519 algorithm and using a password (not mandatory) for the private key.
# The size of ed25519 is always 256 so if we pass the command -b 4096 it will be ignored
ssh-keygen -t ed25519 -f ~/Desktop/minha_chave_ed25519 -N "minha!senha"

Now we have the key pair, put the public key content inside .ssh/authorized_keys of the user we want to log in. I have a machine where the user is ubuntu and I have the public key in the right place.

# On the local machine
cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXZQyz0KI35+Cay+p13+9DQs5R2twRojHIj3DHSC1DcRm9HEw0HpTQLunM181mtv6ElZXU5zKCrKRkXJUHTTAN5t7l7YVHTCJ3CoHbaDdZBTncZbXNBYRniRS+NV4uXuYVqzaDOK8mnytgQwKhbrwnA77vyHsDT4DZQM4FA3EiOpzHSKz7/uvgojOASEd6TTRHtLdLwXemqww9C060Gwg2wFTk9HbZI9kzJYVSBhK4Z4Fd5RsBiFsmz1GqSXTunncDLHgz1EtC+ShoRJ/ckEmfqZaGjBE2TiK4YGikXKul1RceSjsk9nROcxWt6uJdRAi0m/XsYat6E5UHP0IRwYcQt6Mcjj/3nPpGqSXjR6oNlondI+Pg7CffrKU+WhtVC5mwfLxg960B1PeSDsbnYJhg+vSGsXmmrgKZb6Xz8Qgl3o72d6gW1+2Lpnwtm6Q7lP5kzGpWCPMHjpzzTb41JHzAqM7vBFvfPw7YIUVgdbkMyjN/ap/BWApe1acbYMVNSTrE02HzdPtmI2FvJU8cy93PayEC9/SntNV1m9WcgxFZCoJQamDwOME4hfRMF/efgZ8haEJGXM2TqnBO3bsZI+m2nPwV85TpYU+uKZeNAEbxq7JoKMV6JInX+6+VBK4GfFXwElhFqG+6gzRXLB3Cvuv+I4BHFiuOXKmUq2k6ik3PLQ== david@david

# -i to pass the private key we want to log in with
ssh -i id_rsa [email protected]

# Once inside the system we can see the equivalent public key.
ubuntu@master1:~$ cat .ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXZQyz0KI35+Cay+p13+9DQs5R2twRojHIj3DHSC1DcRm9HEw0HpTQLunM181mtv6ElZXU5zKCrKRkXJUHTTAN5t7l7YVHTCJ3CoHbaDdZBTncZbXNBYRniRS+NV4uXuYVqzaDOK8mnytgQwKhbrwnA77vyHsDT4DZQM4FA3EiOpzHSKz7/uvgojOASEd6TTRHtLdLwXemqww9C060Gwg2wFTk9HbZI9kzJYVSBhK4Z4Fd5RsBiFsmz1GqSXTunncDLHgz1EtC+ShoRJ/ckEmfqZaGjBE2TiK4YGikXKul1RceSjsk9nROcxWt6uJdRAi0m/XsYat6E5UHP0IRwYcQt6Mcjj/3nPpGqSXjR6oNlondI+Pg7CffrKU+WhtVC5mwfLxg960B1PeSDsbnYJhg+vSGsXmmrgKZb6Xz8Qgl3o72d6gW1+2Lpnwtm6Q7lP5kzGpWCPMHjpzzTb41JHzAqM7vBFvfPw7YIUVgdbkMyjN/ap/BWApe1acbYMVNSTrE02HzdPtmI2FvJU8cy93PayEC9/SntNV1m9WcgxFZCoJQamDwOME4hfRMF/efgZ8haEJGXM2TqnBO3bsZI+m2nPwV85TpYU+uKZeNAEbxq7JoKMV6JInX+6+VBK4GfFXwElhFqG+6gzRXLB3Cvuv+I4BHFiuOXKmUq2k6ik3PLQ== david@david
ubuntu@master1:~$

Instead of passing which key we have to use every time using -i.

How to Manage Multiple SSH Keys?​

Sometimes it's necessary to use different SSH private keys to log into different servers. Key pair A is used on servers at company A and key pair B is used on company B's server, or we might even have our personal key to interact with our own repositories and another key to interact with the company's repositories.

We can use ssh-agent which is a program that manages SSH private keys used for authentication. It works as an intermediary that stores private keys in memory and uses them as needed. To know if it's working.

eval $(ssh-agent)
# If the pid is returned then it's available
Agent pid 35526

If you have a private key that needs a password to unlock, loading it using ssh-agent is interesting because it keeps the unlocked key in memory, avoiding having to type the password all the time. When adding a key, it asks for the password and then manages it alone.

# To add
ssh-add ~/.ssh/id_rsa
ssh-add ~/.ssh/id_rsa2

# To list
ssh-add -l

# Removes a specific key from the list
ssh-add -d ~/.ssh/id_rsa2

# Removes everything
ssh-add -D

The file at ~/.ssh/config is necessary to know which key to use. The simplest configuration for a single key is.

Host *
ForwardAgent yes

But we can define different keys for different hosts. Below we will have a more concrete example with GitLab.

Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_github

Multi GitLab Account with SSH and Git​

In GitLab, it's not possible to add the same public key to different accounts. We will certainly need to create more than one key. The tip is to create a configuration so that the key is selected based on the host.

In ~/.ssh let's imagine we have 2 keys; one for your personal GitLab and another for work GitLab.

So let's create a configuration in ~/.ssh/config.

Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/personal_key
Host gitlab.com-work
HostName gitlab.com
User git
IdentityFile ~/.ssh/work_key

When it is identified that the host is gitlab.com, it will use the personal_key private key and when identified as gitlab.com-work, it will use the work_key.

When executing the command git clone [email protected]... replace gitlab.com with gitlab.com-work when it's for a clone of the company's repository.

If a repository is already defined, just change its remote by setting a new URL if necessary.

# Example for a work GitLab repository
git remote set-url origin [email protected]:work/repository.git

In this case, an interesting detail to also do is to create a folder (work in the example below) that will have all the company's projects and change the git configuration to change the user and email only in that folder and keep the global one.


[user]
name = David Puziol
email = [email protected]
[includeIf "gitdir:~/Desktop/work/"]
path = ~/.gitconfig-work

And create a .gitconfig-work file to overwrite the user

[user]
name = David Puziol
email = [email protected]