2023-09-29
ssh (secure shell) is one of the programs I use most frequently. It’s pretty amazing. It’s like a remote desktop for your command line.
But since it’s text-only, you can script it quite easily. For example, to run uptime on another host:
$ ssh razzi@sdf.org uptime
11:56PM up 20:32, 53 users, load averages: 0.51, 0.46, 0.44
(This is running on the great SDF public access unix system. Create an account for free!)
Note that this guide is highly opinionated and a bit nonstandard. More than anything else I am using this to document my own practices.
I use ed25519 keys since they’re shorter and faster. I guess they’re supposed to be more secure too but the cryptography is a bit over my head to be honest.
I like to name my private key with a .priv extension and my public key with a .pub
extension. The .pub extension is standard, but the default is to have the private
key simply named id_ed25519
with no extension.
In my opinion this is a bad idea, since you are liable to access the private key by mistake since it is a prefix of the public key. I resolve this by naming them with different extensions, so you’ll see .priv if you’re ever dealing with the private key.
As far as I know there’s no way to tell ssh-keygen
to do this for you, so I generate my keys in the following 2-step process:
$ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519.priv
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /sec/root/.ssh/id_ed25519.priv
Your public key has been saved in /sec/root/.ssh/id_ed25519.priv.pub
The key fingerprint is:
SHA256:DliKsPkfG7us9vnnfKVYSlkkD7l97QyxFBfQd0Z+Es0 root@lsd-GloomSwear
The key's randomart image is:
+--[ED25519 256]--+
| . o++=.|
| + . o..oE|
|. . B . +.o+|
| + . + . + + ...|
|o . o . So . + |
| . oo . . o |
| . o ..+ o |
| .o * .+ o |
| ..oOo.oo. |
+----[SHA256]-----+
$ mv ~/.ssh/id_ed25519{.priv,}.pub
When it prompts for a password, I generate a new one from pass. The system I use for naming is $HOSTNAME-id_ed25519
. So for a computer with hostname darkglow
my pass entry is named darkglow-id_ed25519
.
The mv
command takes the .priv out of the public key name, so I’m left with:
$ ls ~/.ssh
id_ed25519.priv id_ed25519.pub
Then when I want to publish my public key, I copy it like so:
$ fish_clipboard_copy < ~/.ssh/id_ed25519.pub
and then I can paste the public key into the textarea of a service like sourcehut,
or a host’s ~/.ssh/authorized_keys
file.
ssh-copy-id is a nice convenience for putting your public key on a host that you can log in to using a username and password.
Using a username and password (and allowing it) is less secure, so it’s a good idea to make the first thing you do once you can connect to a host running ssh-copy-id
, and then disable password authentication.
Example usage:
$ ssh-copy-id razzi@45.79.9.183
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/razzi/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
razzi@45.79.9.183's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'razzi@45.79.9.183'"
and check to make sure that only the key(s) you wanted were added.
$ ssh razzi@45.79.9.183
Linux 45-79-9-183.ip.linodeusercontent.com 5.10.0-23-amd64 #1 SMP Debian 5.10.179-1 (2023-05-12) x86_64 [...]
If you’re curious, you can see how key installation is implemented by viewing ~/.ssh/authorized_keys
.
Once your public key is installed, disabling password login will make your system more secure.
Log in to your server and edit /etc/ssh/sshd_config.
$ sudo -e /etc/ssh/sshd_config
Find this config (it has a helpful description):
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes
Like it says, change the yes to no:
PasswordAuthentication no
Reload the sshd config:
$ sudo systemctl reload sshd
And test that password login is off as follows:
$ ssh -o PubkeyAuthentication=no youruser@xx.xx.x.xxx
youruser@xx.xx.x.xxx: Permission denied (publickey).
Often when you add a key, it’ll show just a hash of it, which it calls a fingerprint.
To generate a fingerprint for a key (public and private use the same fingerprint, but here I’m using public key since I don’t like to touch my private keys):
$ ssh-keygen -l -f ~/.ssh/id_ed25519.pub
256 SHA256:cN2rCu/BVEtqimzvxbhNIOejocHHMANh4HMrsXuLle0 razzi@DESKTOP-IFJ7AJU (ED25519)
However that’s hard to read, and a lot of places still use the legacy md5 hash function. This is probably a bad thing, seeing as md5 is not resistant to collisions. But checking an md5 hash is better than nothing…
$ ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub
256 MD5:bc:92:c0:8a:8f:6a:b1:8d:ec:8a:45:7f:4d:d9:4f:26 razzi@DESKTOP-IFJ7AJU (ED25519)
There’s one more cool way to identify your keys: randomart. This is displayed when you generate your keys (see above) and can be printed with the following command:
$ ssh-keygen -l -v -f ~/.ssh/id_ed25519.pub
256 SHA256:cN2rCu/BVEtqimzvxbhNIOejocHHMANh4HMrsXuLle0 razzi@DESKTOP-IFJ7AJU (ED25519)
+--[ED25519 256]--+
|+. |
|o. . . |
|.+ . . . + . |
| .= . o + . . |
| o+.. o S . . |
| .o*o= O . |
| .o+B.* * . |
| +=o+ O o |
| ....E+.= |
+----[SHA256]-----+
The idea here is that at a glance you can compare randomarts.
You can display the server key randomart with the -o VisualHostKey=yes
flag:
$ ssh -o VisualHostKey=yes xx.xx.x.xxx
The authenticity of host 'xx.xx.x.xxx (xx.xx.x.xxx)' can't be established.
ED25519 key fingerprint is SHA256:CirXgebEZ0xENb7SmPJE7xxWmjmSCZ/lmXv0Qu8sFa0.
+--[ED25519 256]--+
| .o.o |
| . . . |
| . o o . . |
| . B @ O . . |
| * ^ # S o |
| + O O B oE |
|. + o = o.o |
| o ..+ |
| .o |
+----[SHA256]-----+
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
You can set this option persistently in /etc/ssh/ssh_config
.