JMM’s notes on

SSH

Get the fingerprint of the current machine

Sometimes you get the following warning when trying to connect to a machine:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░.

If you have physical access to that machine, you may wonder, “What is the fingerprint of this machine?”. If it has a /etc/ssh/ssh_host_ed25519_key.pub (for example) you’d run:

$ ssh-keygen -E sha256 -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ root@░░░░░ (ED25519)

Add the -v flag if you want the visual ASCII art fingerprint.

SSH Agent

Add an identity, but only for 8 hours:

ssh-add -t 8h ~/.ssh/id_rsa

SSH agent things to check out

  • You can limit where SSH agent allows keys to be used, see the “-h” option in man ssh-add.

GNOME Keyring

GNOME Keyring loads its own SSH agent that automatically loads all files in ~/.ssh/ (see this article on GNOME Wiki). I kinda don’t like this behavior and would prefer only loading certain keys explicitly. The reason being I’ve got a lot of keys, and if SSH tries everything I end up getting authentication failures for trying too many keys.

I think SSH agent is getting split out of GNOME keyring in the future (a commit from October 2023 shows ssh agent being disabled by default in builds of gnome-keyring).

Running commands on remote host

Here’s an example of running pg_dump to make a backup of the data in a PostgreSQL table:

ssh somehost pg_dump --format=plain --table=public.sometable --dbname=somedb --data-only --inserts --on-conflict-do-nothing > mybackup.sql

Running a restricted single-user SSH daemon

I wanted to rsync some files on my server that were under a system user. I probably should have just added a way to log in to this user, but instead I thought I’d run SSH with CAP_DAC_READ_SEARCH capabilities so I could read everything. I’m sure this is pretty insecure, so don’t do this yourself.

Anyway, here’s some code to do this:

SOMEUSER=$(whoami)
sudo mkdir /var/lib/ssh2
sudo chown $SOMEUSER /var/lib/ssh2
mkdir /var/lib/ssh2/authorized_keys.d/

ssh-keygen -f /var/lib/ssh2/ssh_host_ed25519_key -N '' -t ed25519

# Copy your ssh key into /var/lib/ssh2/authorized_keys.d/$SOMEUSER

cat <<EOF > /var/lib/ssh2/config
HostKey /var/lib/ssh2/ssh_host_ed25519_key
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile /var/lib/ssh2/authorized_keys.d/%u
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM no
StrictModes no
PidFile none
LogLevel VERBOSE
EOF

And here are a couple ways of running the SSH daemon:

# Here we use -d to debug a single connection
systemd-run --wait -t -p User=$SOMEUSER sshd -D -d -p 2222 -f /var/lib/ssh2/config -e

# WARNING: CAP_DAC_READ_SEARCH lets the user read basically anything.
systemd-run --wait -t -p User=$SOMEUSER -p ProtectHome=read-only -p AmbientCapabilities=CAP_DAC_READ_SEARCH sshd -D -p 2222 -f /var/lib/ssh2/config -e

Then on your local machine (or wherever you want to receive files):

rsync -Phazrv -e "ssh -p 2222" --ignore-existing some-server:/var/lib/whatever/ ~/backups/whatever/

Setting up sshd on Debian

Usually I use NixOS, but some things (like my Librem 5) have a Debian-based OS. So I’m just documenting to myself here how to minimally set that up so I can later use Ansible or whatever.

I’m going to call the computer that we want to install the SSH server on the “host” and the computer we want to connect from the “client”. So if you’re using a laptop and trying to install on a server, the laptop is the client and the server is the host.

  1. On the host, install openssh-server using sudo apt install openssh-server
  2. You can check the status of OpenSSH on the host using systemctl status sshd.
  3. On the client, copy your SSH key (say ~/.ssh/id_rsa.pub) using:
    ssh-copy-id -i ~/.ssh/id_rsa.pub -o PreferredAuthentications=password -o PubkeyAuthentication=no user@host

    You’ll probably be prompted to accept the host’s public key.

  4. On the client, you may want to configure how you connect to the host. Edit your ~/.ssh/config to have a block like:
    Host 			host
         User		somehostuser
         IdentitiesOnly	yes
         IdentityFile  	/home/yourclientuser/.ssh/id_rsa
         PasswordAuthentication no
         HostName		192.168.0.108

    You may be using a different key than id_rsa. Edit variables as needed.

  5. Now that you can SSH in to the host, you can edit the /etc/ssh/sshd_config remotely. I do this using Emacs’s TRAMP by navigating to the file: /ssh:host|sudo:host:/etc/ssh/sshd_config

    Most of the lines there will be commented.

  6. Disable password authentication by adding or uncommenting the lines:
    PasswordAuthentication no
    PermitEmptyPasswords no
    KbdInteractiveAuthentication no
    

    If you’re editing this file with Emacs, you may wish to do M-x add-file-local-variable RET mode RET conf-space-mode RET.

  7. You can reload sshd on the host using systemctl reload sshd.
  8. Check that you can’t use password authentication anymore by trying to connect on the client using
    ssh -v -o PreferredAuthentications=keyboard-interactive,password -o PubkeyAuthentication=no -o PasswordAuthentication=yes user@host

Misc commands

In case I forget. Which I will.

# Remove a host key from known_hosts
ssh-keygen -R 192.168.0.108

# Connect using password
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no nixos@192.168.0.108

# Add a key
ssh-copy-id -i ~/.ssh/id_rsa.pub  -o PreferredAuthentications=password -o PubkeyAuthentication=no nixos@192.168.0.108