This manual is focused on asymmetric encryption. As the principles are more or less the same for all technologies, we will focus on the technical aspects that differs.
SSH¶
The SSH is a protocol for secure communication between two computers. The basic usage is to connect to a remote computer:
ssh <username>@<address>
To close the connection, type exit to the console and press enter.
If we do not want to establish a connection, but just run a single command, we can add the command at the end of the ssh command:
ssh <username>@<address> <command>
By default, ssh use the key authentication if configuared, and resort to password authentication if not. If we want to force password authentication, we can use the -o PreferredAuthentications=password parameter.
Authentication¶
There are two ways to authenticate to the server:
- password
- private key
Note that the server needs to be properly configured to accept your credentials. Specifically:
- for password authentication, the
PasswordAuthenticationoption in/etc/ssh/sshd_confighas to be set toyes. This is often disabled for security reasons. - for private key authentication, the public key has to be added to your user account on the server.
Generating a key pair¶
To generate a key pair, use the ssh-keygen command.
Setting up the private key to be used for ssh connection¶
To use a private key for ssh connection, two conditions have to be met:
- the private key has to have the right permissions:
- in Linux, the permissions have to be read/write only for the owner (
600)
- in Linux, the permissions have to be read/write only for the owner (
- you have to specify that the private key should be used for the connection. This can be done in multiple ways:
- using the
-iparameter of thesshcommand - specifying the key in the
~/.ssh/configfile - using ssh agent (see the SSH Agent section below)
- selecting the key in an application with GUI
- using the
SSH Tunneling¶
An SSH tunnel can be created by the ssh command. The usuall syntax is following:
ssh -L <local port>:<remote machine>:<remote port> <ssh server username>@<ssh server address>
The -L argument stands for local port forwarding, i.e., we forward a local port to some remote port.
Example:
ssh -L 1111:localhost:5432 fiedler@its.fel.cvut.cz
The local port (here 1111) is arbitrary, we can use any free port. The aplications using the tunnel should then be configured as:
- host=
localhost - port:=
1111
The remote machine is the address of the machine we want to access relative to the ssh server. If the ssh server is running on the computer we want to access through the tunnel, we can use localhost. Analogously, the remote port is the port we wan to use on the remote machine (here 5432 is a PostgreSQL db port).
The ssh server username and ssh server address are then the username/address of the remote machine. On top of that, we need password or priveta key to validate our identity. Note that the credential here are the credential for the server, not the credentials of the service we are accessing through the ssh connection. Those credentials has to be usually supplied by the application accessing the service through the ssh tunnel.
The connection can be canceled any time byping exit to the console.
Debugging a SSH tunnel¶
This guide suppose that the tunnel creation comman run without any error message.
- If the tunnel seems to not work, first use a command line tool to be sure:
- web browser for HTTP tunnels (remote port 80)
psqlfor postgeSQL tunnels (remote port 5432)telnetfor telnet tunnels (reote port 23)
- If the test is unsucessful, try to kill all ssh connections to the server by shutting down all applications with ssh connections tunnels, untill there will be only one connection at the server (the console). The number of ssh connections can be checked with:
sudo netstat -nap | grep :22
Enabnling SSH Access on Server¶
- install openssh:
sudo apt updatesudo apt install openssh-server
- configure password access
- open
/etc/ssh/sshd_config - set
PasswordAuothentication yes - after restrat you can log in with the user and password used in Ubuntu
- open
- restart the ssh server:
sudo service ssh restart
Enabling key authentication for a user¶
The user can only use a private key for authentication if the corresponding public key is assigned to the user on server. This is done by adding the public key to the ~/.ssh/authorized_keys file.
Note that the authorized_keys file has to have the right permissions, which is read/write only for the owner, and read only for the group and others (644).
With the authorized_keys file, we can also restrict the user by wrapping the commands he can execute with our own script. This restriction applies to a specific key. We configure the wrapping command by adding the following to the beginning of the key line:
command="<path to the command>" ssh-rsa AAAA...
WSL configuration¶
- port
22can be used on Windows, so change the port to2222 - when loging from Windows use
127.0.0.1as a host
To change the port:
- on older systems:
- change the port in the
/etc/ssh/sshd_configfile - restart the ssh server:
sudo service ssh restart
- change the port in the
- on newer systems:
mkdir /etc/systemd/system/ssh.socket.dvim /etc/systemd/system/ssh.socket.d/<some name>.conf- add the following content:
conf [Socket] ListenStream= ListenStream=2222 systemctl daemon-reloadsystemctl restart ssh.socket
SSH Agent¶
Normally, the SSH client process runs only while the SSH session is active, then, it is terminated. That means that we have to reenter the passphrase for the private key every time we want to connect to the server. To overcome this limitation, we can use the an SSH agent program.
An SSH agent is a process for storing decrypted SSH keys in memory. This means that we have to enter the passphrase only once per each OS login. The agent can be configured to automatically run on OS startup. The default SSH agent is ssh-agent, the rest of the section is dedicated to this agent.
To successfully use the agent, we need to:
- start the agent, either manually or automatically on OS startup
- add the keys to the agent (only once)
Starting the agent¶
The starting of the agent is different for each OS:
- Linux: the agent can be started manually by running:
bash eval `ssh-agent`We need to evaluate this command as it sets some environment variables. As the process cannot set the environment variables of the parent process due to security reasons, thessh-agentprints the necessary commands to the console. By using eval, thessh-agentis executed first, it prints the environment setup commands to stdout, which is captured by the eval command and executed. - Windows: we need to start the OpenSSH agent service. Consult the Windows Manual for more details.
Listing keys¶
To list the keys stored in the agent, run:
ssh-add -l
Adding keys¶
To add a key to the agent, run:
ssh-add <path to key>
Debuging¶
If the agent is running and the key is listed, the first thing to try is to connect via ssh to see whether it is an agent/ssh issue or an issue of the program using the SSH (like git, IDE, file manager...)
known_hosts file¶
To know that a connection leads to the desired server and not to some impersonator, the server sends its public key to the client. The client then checks the public key against the list of keys previously set as valid. This list is stored in the .ssh/known_hosts file. The format of the file is:
<server address> <key type> <key>
Each line contains one server record. What is confusing here is that each server can have multiple records, due to:
- different key type (e.g., RSA, ECDSA)
- key for both host name and IP address (e.g.,
github.comand140.82.121.3) It is important to delete/updete all of these recorsds in case the server change its keys.
More info is at this SO answer.
Screen: executing a long running process over SSH¶
When the SSH connection to a server is disconnected (either manually, or by network failure or timeout), the process running in the console is canceled. To overcome this limitation, we can use the screen command, which is especially usefull for long running processes.
A typical workflow can look like this:
- execute
screento start the screen session - run the long running command
- disconnect
- connect to the server again
- run
screen -rto recconect to the session and see the results of the command. - after the command is finished, exit the screen session with
exit
Sometimes, the server does not detect the connection failure and do not allow you to resume the session (step 5). In this way, we need to find the screen session ID and perform a detach and atach:
screen -ls- read the ID from the output and exec
screen -rd <ID>
SCP: Copying files over SSH using¶
The scp command is used to copy files over SSH. The syntax is:
scp <source> <destination>
The <source> and <destination> can be either local or remote. The remote files are specified using the <username>@<address>:<path> syntax.
Problems¶
protocol error: filename does not match request: This error is triggered if the path contains unexpected characters. Sometimes, it can be triggered even for correct path, if the local console does not match the remote console. In that case, the solution is to use the-Tparameter to disable the security check.file does not exists: This can happen if the path is incorrect, but also if we use some bad quotting. If the solution is not obvious, try the most simple path possible in command line.
List all active connections on a server¶
To list all active connections on a server, we can use the lsof command and filter the output for the ssh connections:
lsof -i -n | grep ssh
Debugging¶
If the server does not respond:
- check the ssh status with:
service ssh status - check the ssh port with
sudo netstat -tpln
If the key is not accepted:
Check the log file: sudo tail -c 5000 /var/log/auth.log
GNU Privacy Guard (GPG)¶
GPG is a second most popular tool for encryption, after the SSH keys. Apart from encryption capabilities, it offers also a management of subkeys, and a possibility to revoke the key. It can be downloaded from the GNU-PG website.
GPG comes with a build in key agent.
To list the keys added to the agent, use gpg --list-keys.
To import a key, call gpg --import <keyfile>.
Key expiration¶
There is a mechanism for key expiration in GPG. However, it is important to understand that the expiration date is mostly not a security feature! It can be useful in the following cases:
- you lose access to the key, and nobody else can access it as well. In that case, you cannot revoke the key, but you can just wait until the key expires.
- you set the expiration date for subkeys. For subkeys, the expiration date is a security feature, as it cannot be changed without the main key.
To prolong the expiration date, we can use the gpg --edit-key <key-id> command. After using it:
- choose the key you want to edit by number
- now the chosen key should be marked with an asterisk
*. Enterexpire - choose the new expiration date
- save the changes by
save
Troubleshooting¶
partial length invalid for packet type 63¶
This can happen if the private key has a wrong encoding. It can be fixed by cnverting the key file to ASCII encoding.
Storing passwords for the command line tools¶
Sometimes, we need to store passwords for the command line tools on the local machine. For non-sensitive passwords, we can just store them in a file that is not versioned. However, for sensitive passwords and authentication tokens, we should not store them in plain text. We have two options:
- Use a Credential Manager, or
- Encrypt the file where the passwords are stored.
Credential Managers¶
There are plenty of credential managers available for each OS. If we want to avoid the differences between the OS, we can use the python keyring package.
Python keyring¶
The keyring package is a Python library that provides a way to store passwords in a secure way. It uses a system-specific backend to store the passwords.
To manage the passwords, we can use the keyring command provided by the package. The basic usage is:
keyring set <service> <username> # set the password. After running this command, the password is prompted
keyring get <service> <username> # get the password
To use the keyring in a Python script, we use the keyring package:
import keyring
password = keyring.get_password("service", "username")
WebAuth (passkeys)¶
WebAuthn is a standard for passwordless authentication using a hardware key. It is a successor of the multifactor authentication.
The multifactor authentication typically consists of:
- a password, supplied by the user
- authentication by an external device, typically a smartphone
Contrary to that, WebAuthn does not require a password, but only a hardware key. Typically, the key is a smart phone, tablet or a laptop. The hardware key validates the user's identity either by a PIN code or by a biometric factor.
Web auth has two modes:
- Multi-factor mode: works like the traditional multifactor authentication: a password is supplied first and then only a confirmation (e.g., hitting enter) is required on the hardware key.
- Single-factor mode: only the hardware key is required, but user verification is required with the hardware key (e.g., a PIN code or a biometric).