Quick Look
- Generate SSH key pair. This will create 2 files:
~/.ssh/id_ed25519
and~/.ssh/id_ed25519.pub
ssh-keygen -C "user@example.com"
- Upload the public key to ssh server.
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
- Connect to ssh server.
ssh user@host
What is SSH?
An intuitive understanding of SSH is buried somewhere within the Wikipedia definition:
“The Secure Shell Protocol (SSH) is a cryptographic network protocol for operating network services securely over an unsecured network.” wikipedia
If you are a student, this answer will probably be enough to satisfy your professor when he’s marking your exams. But if want to use SSH in practice, you’ll probably need something more than an academic answer. You’ll actually need an understanding. And some understandings are easier to build when you are given analogies. My analogy is thinking of SSH as similar to a student looking for someone interesting to be his roommate. A good place to start understanding something is understanding what problem it’s trying to solve.
Roommates
Matteo is an Italian University student looking forward to the next academic year. His friends can really tell how excited he is by the way he’s passionately narrating his summer vacation in Cebu, Philippines. The people. The language. The region. He wished he could return there some day. So you can imagine his surprise when one of his friends who has been keenly listening tells him, “My classmate…Angelo. He’s mum is from Cebu.” Matteo was practically begging for an introduction.
“My name is Matteo Costa. But my friends call me Matteo”, said Matteo as he shook Angelo’s hand. After a pleasant chat. Matteo thought about asking Angelo to be his roommate for the year. If he’d be interested, he’d have someone to share stories with, in the local language he had learnt to love. All he needed to know is if Angelo spoke the language. He asked Angelo a question, in broken Cebuano, about a certain town in Cebu that only a person who’s been there would know. And to his delight, Angelo responded correctly in native Cebuano. Angelo, spotting the glee on Matteo’s face, asked, “First of all, that sound like the most Google Traslate answer, if there was ever one. Second of all, why did you ask that?” Matteo tells him that he actually lived their for 3 months. “You don’t say,” said Angelo as it was now his turn to ask the questions. He asked Matteo another question about the same town that only a person who’s lived there would know. And to Angelo’s pleasant surprise, Matteo answered correctly, albeit with the same broken Cebuano he asked his question with. “Have you found a roommate yet?” asked Matteo.
Recap
In this story, we have most of the things needed to understand SSH. We have a student (Client) who wants a roommate who reminds them of a good time he had in the Philippines (use case of SSH), and he asks a potential candidate (Server) a question (public key) that only a person from that town in Cebu would know the answer to (private key). The candidate also wants to know if the student is who he says he is (authentication, either key-based or password-based) by asking the student a question that the candidate already knows the answer to. And if all this goes well, they’ll share a secure living space (SSH session) for the academic year (session duration) where they’ll both have the same house key (shared session key).
Check out this article for more information on how the SSH connection process works.
Bringing it all together
So you can say that Matteo wants to be able to walk from school and spend time with Angelo in a private place that only the 2 of them can access. Pause. A Client wants to be able to reach out to a Server and privately chat back and forth with it without letting anyone else know what they are chatting about. Wait…isn’t starting to sound like the definition of SSH?
Technical definition
SSH - Secure Shell - is an open network protocol that allows a client to securely connect to a server over an insecure network. That’s it.
Usage
By being an open protocol, SSH lends itself to multiple implementations with a popular implementation being OpenSSH, available on a Linux, Mac or Windows device near you. And with that being said, all the commands used to show the practical usage of SSH will all be based on the OpenSSH implementation of SSH. OpenSSH is an OpenBSD project that provides a suite of cli tools, but we’ll only delve into 9 of the most common ones here in order to show how you can use them for secure connection, key management, and performing operations on remote machines.
The 9 tools we’ll be using are:
Background Services | Managing Keys | Remote Operations |
---|---|---|
sshd, ssh-agent | ssh-keygen, ssh-copy-id, ssh-add, ssh-keyscan | ssh, scp, sftp |
Additionally, some of the tools above make use of certain files depending on whether it’s the client or the server. Clients make use of:
~/.ssh/known_hosts
~/.ssh/config
- key pairs found in
~/.ssh
Servers make use of:
~/.ssh/authorized_keys
/etc/ssh/sshd_config
- key pairs found in
/etc/ssh
Clients store the public keys of remote servers it intends to communicate with (and keep communicating with in future) in the ~/.ssh/known_hosts
file, while remote servers store the public ssh keys of clients, allowed to connect to it without a password, in ~/.ssh/authorized_keys
. Client-specific configuration is stored in ~/.ssh/config
, while server-specific configuration is stored in /etc/ssh/sshd_config
.
Background Services
1. sshd
- The OpenSSH server
The sshd
is a daemon process that acts as the server for the SSH protocol. It listens for connections from clients and provides secure connection between it and the client.
sshd
is usually started and managed by a service manager such as systemd
, and it’s behaviour is configured by editing the /etc/ssh/sshd_config
file.
The most common configurations are:
- Setting
PermitRootLogin
tono
. By default, it’s set toyes
as root is the only user created during installation. But once you create a non-root user, it’s recommended to set it tono
. - Setting
PasswordAuthentication
tono
. By default, it’s set toyes
as SSH key authentication has not been set up yet. However, once you set it up, you can set it tono
. - It’s recommended to combine the above two configurations, i.e. set both
PermitRootLogin
andPasswordAuthentication
tono
, to further enhance the security of the server. This is done after creating a non-root user, and setting up SSH key authentication between the client you want to connect from and that user on the server.
Note that you can still access root by switching to root once you’ve logged in as a non-root user. For this, use the command
su -i
. Alternatively, you can create a non-root user withsudo
privileges.
2. ssh-agent
- The “Login With Google” of OpenSSH
The ssh-agent
is a tool that runs as a background process in the current shell session that stores unencrypted private keys and encrypted private keys that have been unencrypted with by a passphrase in memory.
The main utility of ssh-agent
is that you can add keys to it once (during the shell session) and you login in to several servers configured to use those keys. This eliminates once of the main excuses of not creating private keys encrypted with passphrases - trying in the passphrase each time you log in to a server. Of course this doesn’t eliminate the need to memorize the passphrase. You still have to remember that.
Unlike sshd
, ssh-agent
is not started by default, although some Linux systems do start it for you. Since ssh-agent
is not a system-wide service, but a shell-session-specific process, it has to be started for each shell session you open e.g. opening a terminal window.
To start ssh-agent
on your system, run the following command:
eval $(ssh-agent)
# returns
# Agent pid [ppid]
When the agent is started, it creates a Unix-domain socket and stores the path to it in $SSH_AGENT_SOCK
environment variable. It also stores the process id of the agent in $SSH_AGENT_PID
environment variable. These environment variables provide an easy way to know if the agent is running or not, by outputting it’s values in the terminal e.g. echo $SSH_AGENT_SOCK
.
Managing Keys
1. ssh-keygen
- You can skip this, but it’ll be a pain
The ssh-keygen
command is used to create a key pair for public key authentication. It accept multiple arguments, but the 2 main ones are -t
and -C
.
-t
specifies the key type, although leaving it blank makes it default to the most secure one (ed25519 as of September 2024). They key types supported by OpenSSH are: RSA, DSA, ECDSA and ED25519.
-C
specifies the comment which is a human-readable string that you can use to identify the key. If you don’t specify -C
, the default comment is the account user’s name and hostname.
ssh-keygen
run’s in an interactive mode, and one of the options you’ll have to choose is whether or not you’ll want a passphrase for your private key. The passphrase is used to encrypt the private key, and this adds a layer to security for your key if it ever leaks or get stolen.
# Simple
ssh-keygen -C "your_email@example.com"
# Specify key type
ssh-keygen -t ed25519 -C "your_email@example.com"
2. ssh-copy-id
- If you skipped ssh-keygen
, you can skip this too
The ssh-copy-id
command is used to install a local public key into a remote server’s authorized keys. It installs it for the user specified in the command.
ssh-copy-id -i ~/.ssh/custom_key.pub user@host
3. ssh-add
- If you skipped ssh-keygen
, you know the drill
The ssh-add
command adds keys to the ssh-agent
service running in the current shell session. By default, running the command with no args adds the default identities, i.e. id_rsa, id_dsa, id_ecdsa and id_ed25519, if they exist.
ssh-add ~/.ssh/custom_key
You can also use it to list the keys that are already stored by the agent:
# Lists fingerprints of all identities in the agent
ssh-add -l
# or
# Lists the actual public keys in the agent
ssh-add -L
4. ssh-keyscan
- It just has one practical use
The ssh-keyscan
command is used to gather the public SSH keys of remote servers. The server stores a key pair for each key type in /etc/ssh/
to give a client flexibility to generate keys with any supported key type they want. However, some hosts only support certain key types, and you can use ssh-keyscan
to get a list of those keys in the server. GitHub for example doesn’t support dsa
key type (as of September, 2024):
ssh-keyscan github.com
# returns
# github.com:22 SSH-2.0-babeld-fdcea1d49
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
# github.com:22 SSH-2.0-babeld-fdcea1d49
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
# github.com:22 SSH-2.0-babeld-fdcea1d49
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
# github.com:22 SSH-2.0-babeld-fdcea1d49
# github.com:22 SSH-2.0-babeld-fdcea1d49
Performing Remote Operations
1. ssh
- What you think of when you think of SSH
Basics
The ssh
command is a client use for logging into a remote server. This is the command that most people think of when they say that they want to learn about SSH. The simplest usage is just specifying the domain or ip address of the remote server. It will assume that you want to log in as the current user.
ssh host
But if the remote user is different from the current user, you can specify the user name as well:
ssh user@host
Either way, once you’ve authenticated yourself (whether by passphrase or ssh key), you’ll be dropped into an interactive shell where you anything you type are sent as commands to the server.
Running Single Commands
But if all you want to do is just run a single command or a single script, it’s easier to just append the name of the command or the script to the end of the ssh
command:
# Run single command
ssh user@host ls
# Run single script
ssh user@host bash < script.sh
Using Custom SSH Keys
By default, the ssh
command will use the default private keys, i.e. ~/.ssh/id_rsa
, ~/.ssh/id_dsa
, ~/.ssh/id_ecdsa
and ~/.ssh/id_ed25519
to connect to the server, and if none of them matches, it will result in a “permission denied” error. There are cases where you want to create an SSH key pair with a specific (non-default) name for a specific purpose, or are sent an SSH key pair with a specific name or one with a standard name but has a name that’ll clash with your other keys, or the key is in a non-standard location on your file system, etc. Regardless of the reason, there are 2 solutions for this:
- Use the
-i
option to specify a path to a specific key
ssh -i ~/.ssh/custom_key user@host
- Add the custom key to
ssh-agent
usingssh-add
:
eval $(ssh-agent)
ssh-add ~/.ssh/custom_key
ssh user@host
Adhoc-configuration of the ssh
command
The behaviour of the ssh
command can be modified by changing the options in the ~/.ssh/config
file. However this file isn’t generated by default and thus ssh
command is wholly controlled by the global /etc/ssh/ssh_config
file.
To modify the behaviour of the ssh
command at runtime, you’ll need to pass the -o
option to ssh
specifying the configuration option you want to override. The most common configuration option overrides are:
- Skipping host verification for hosts you trust by setting
SkipHostKeyChecking
tono
. Note that you only do this if you trust the host you’re connecting to. This is commonly used in CI/CD environments and in building Docker images.
ssh -o StrictHostKeyChecking=no user@host
- Keeping SSH sessions alive: by default, the
ssh
command will close the connection after a period of inactivity set bysshd
. This can be overridden by settingServerAliveInterval
to a value in seconds or settingTCPKeepAlive
to1
. However,ServerAliveInterval
might be more appropriate asTCPKeepAlive
may not work in cases where the remote sever firewall is configured to drop empty TCP ACK packets.
ssh -o TCPKeepAlive=1 user@host
# or
ssh -o ServerAliveInterval=5 user@host
2. scp
- Have you wanted to use the cp
command, but across the internet?
The scp
command is used to securely copy files between a client and server over unsecure internet in a non-interactive way.
# put file on server
scp /path/to/file user@host:/path/to/file
# get file from server
scp user@host:/path/to/file /path/to/file
# copy entire directories
scp -r user@host:/path/to/dir .
3. sftp
- FileZilla, but in the command line
The sftp
command is used to securely copy files between a client and server over unsecure internet both in an interactive and non-interactive way.
# get file from server
sftp user@host:/path/to/file /path/to/file
# put file on server
sftp user@host
sftp> put /path/to/file
# copy entire directories
sftp user@host
sftp> put -r /path/to/local/dir
# or
sftp> get -r /path/to/remote/dir