voidcruiser.nl/content/rambles/ssh-configuration.md

266 lines
10 KiB
Markdown
Raw Normal View History

2022-09-27 14:31:43 +02:00
---
title: "SSH Configuration"
date: "2022-09-27T11:40:31+02:00"
author: "$HUMANOID"
2022-09-30 16:28:57 +02:00
tags: ["ssh"]
description: "An article on configuring SSH from the ground up to something that can grow out into something like my monster of a config file"
toc: true
2022-09-27 14:31:43 +02:00
---
# Introduction
If you're anything like me, you'll have at least a hand full of servers you'll log into (at least) every now and then using SSH.
These servers don't all have the same key.
And on top of that, I frequently have multiple keys per host.
Managing this by hand is a pain in the arse.
Thankfully there are a few tools that make it a breeze.
I will be going through what I have done to both my local configuration and what I tend to do with my server configuration.
# Generating keys
In order to do anything with SSH in a secure way, you'll need to make use of public and private keys.
These keypairs are generated using `ssh-keygen`.
I typically generate mine using:
```sh
ssh-keygen -t ed25519 -f ~/.ssh/<new-key>
```
Without any parameters, it will generate an rsa3072 key.
This form of cryptography isn't recommended as it's become a bit flimsy with computers becoming stronger.
Instead I recommend at least adding the `-t ed25519` flag to generate a ed25519 key.
2022-09-27 14:31:43 +02:00
When prompted for a passphrase, **_always_** give it one.
The only situation where _not_ using a passphrase is acceptable is when you are planning on using the key for a [forced command](#forced-commands).
2022-09-27 14:31:43 +02:00
# Server Configuration
This is all done under the assumption that the you use the OpenSSH implementation on your server.
2022-09-27 14:31:43 +02:00
If you use something like Dropbear, I can't help you as haven't properly dug through it's configuration file (yet).
2022-09-29 20:17:33 +02:00
The things I see _way_ to often on the internet are...
2022-09-27 14:31:43 +02:00
* People not disabling password authentication.
2022-09-29 20:13:10 +02:00
* People not changing the default port<!--or only allowing a range of IPs to log in-->.
* People not disabling root login and never using it.
2022-09-27 14:31:43 +02:00
So lets go through these steps one by one.
## Password Authentication
Password authentication is _the_ most basic thing every server should have disabled.
Otherwise, it is possible to brute force a connection into your server.
> "But my server is not exposed to the internet."
I guess you _could_ get away with not disabling password authentication, but it's still not a good idea in case, say, your network gets compromised.
On top of that, it's less convenient to have to type in a password every time you want to log into your server (more in that in the SSH Agent section).
In order to disable password authentication, open your SSH daemon configuration file: `/etc/ssh/sshd_config` and look for the following lines...
```sshd_config
...
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
...
```
...uncomment `PasswordAuthentication` and replace "yes" for "no".
Make sure you still have a way into your server before restarting the daemon.
2022-09-29 20:17:33 +02:00
If you're not planning on logging in as the root user, uncomment and set the following setting to "no".
2022-09-27 14:31:43 +02:00
```sshd_config
...
#PermitRootLogin prohibit-password
...
```
Be aware of the fact that you can still utilise the root account using `sudo su -` (assuming you're using `sudo` on your server, else use whatever other privilege escalation tool you have at hand).
Restarting the daemon on modern systems is usually done using:
```sh
systemctl restart sshd
```
If you're not using systemd, I'm sure you know what command to use instead.
## Adding keys to `authorized_keys`
When going through `/etc/ssh/sshd_config` you've probably come across a few lines resembling:
```sshd_config
...
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
...
```
This means that the SSH daemon will check in `.ssh/authorized_keys` in the home directory of the user as whom you're trying to log in for authorized keys.
2022-09-27 14:31:43 +02:00
So the next step is to append your public key to this file in the home directory of the user as whom you want to be able to log in.
This can be done in a few ways.
The proper way is by using:
```sh
ssh-copy-id -i ~/.ssh/<key-file> <user>@<host>
```
2022-09-29 20:17:33 +02:00
I'm usually too lazy to remember there is a proper way and just open the file in `vi` paste and it in there by hand during the same initial login when I'm disabling password authentication.
2022-09-27 14:31:43 +02:00
Either way works fine.
## Changing the port
The advantage to this is that your logs will be a lot cleaner if your host is exposed to the internet.
There are large amounts of bots hammering port `22` on every IP address they can find with common usernames and passwords like "root" and "admin".
A solution next to this is to use `fail2ban` along side changing the port.
> "Won't this mean I have to add the port to my login command every time I go to this server?"
No, more in this in [the client configuration](#client-configuration) section
2022-09-27 14:31:43 +02:00
2022-09-29 20:17:33 +02:00
In `/etc/ssh/sshd_config` look for...
2022-09-27 14:31:43 +02:00
```sshd_config
...
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
...
```
2022-09-29 20:17:33 +02:00
...and change the `Port` to your liking, I tend to change this to something like 6969 or some other meme number.
2022-09-27 14:31:43 +02:00
Another thing I tend to do is not open a port in my firewall, thus preventing any normal outside connections all together.
Instead opting to only connect over Yggdrasil and/or Tor.
2022-09-27 14:31:43 +02:00
# Client configuration
If people tend not to think much about their server configuration, their client configuration is probably not even touched at all.
## The `~/.ssh/config` file
The very first thing I do after setting up a server, is add an entry to my `~/.ssh/config` in order to manage its key, the user, the port and possibly subdomain should the need arise.
A basic configuration section looks like the following:
```ssh_config
Host <host> # this is something you can easily identify
Host <hostname> # this does need to be an IP address or DNS record pointing to an IP address
2022-09-27 14:31:43 +02:00
IdentityFile ~/.ssh/<key-file>
User <user-name>
Port <meme-number>
2022-09-27 14:31:43 +02:00
```
This allows you to log into host `<host>` with on port `<meme-number>` with key `~/.ssh/<key-file>` as user `<user-name>` without by typing:
2022-09-27 14:31:43 +02:00
```sh
ssh <user-name>@<hostname> -p <meme-number> -i ~/.ssh/<key-file>
2022-09-27 14:31:43 +02:00
```
Instead the following command will work:
```sh
ssh <host>
```
More information on the SSH config file can be found in the `ssh_config` manpage.
2022-09-27 14:31:43 +02:00
Some other frequently used settings for me are:
* `AddKeysToAgent`
* `IdentitiesOnly`
* `ProxyCommand`
### `AddKeysToAgent`
Automatically adds the key to your SSH agent if you have one running.
This is useful if you frequently log in and out of a certain host and don't want to take the time to add it's key to your agent manually.
### `IdentitiesOnly`
Ignore whatever keys your agent has and only use the contents of `IdentityFile`.
Useful for when you want to be able to log into the same host using multiple keys while using an SSH agent session.
2022-09-27 14:31:43 +02:00
### `ProxyCommand`
Always connect to your host using a proxy, using a given command.
2022-09-27 14:31:43 +02:00
Useful for when you can only access a host through a certain proxy.
I use this for my Tor hosts:
```ssh_config
Host tor-<host>
Hostname <lengthy-56-character-string>.onion
# this is dependent on the netcat implementation of the OpenBSD project, often packaged as "netcat-openbsd"
2022-09-27 14:31:43 +02:00
ProxyCommand nc -X 5 -x localhost:9050 %h %p # this assumes you are running a tor proxy on your local system and attempts to make a connection through that
Identityfile ~/.ssh/<key-file>
User <user>
```
# The SSH Agent
If you're using SSH keys with passphrases, it will very quickly get annoying to type in the passphrase every time you use a certain key.
To alleviate this tedium, the SSH agent exists.
If you're using a full desktop environment, chances are that you already have an SSH agent running in the background.
You can check this by seeing if `$SSH_AGENT_PID` is set to anything.
```sh
echo $SSH_AGENT_PID
```
If this isn't set to anything, you can start an agent session by running:
```sh
eval $(ssh-agent)
```
Now you can add keys to your agent with:
```sh
ssh-add </path/to/key-file>
```
You can also have it automatically drop keys after a specified amount of time with the `-t` flag.
I tend to do this with my root keys as a security precaution.
```sh
ssh-add -t 1h ~/.ssh/<root-key>
```
Starting an SSH agent every time you open a new shell session gets quite annoying quite quickly.
There are a few things you can automate this.
The simplest is to add `eval $(ssh-agent)` to your `~/.profile`.
Another option, the one I prefer, is to use [keychain](https://www.funtoo.org/Funtoo:Keychain) from the Funtoo project.
It checks whether there's an agent running every time you start a new login session.
If there is, it sets the SSH agent environment variables to the existing ones from some other session.
If there isn't a running SSH session, it will start one.
I have the following in my `~/.profile`:
```sh
...
eval $(keychain --agents 'gpg,ssh' --eval)
...
```
As you can see, it can also keep track of your GPG agent.
# Forced Commands
Another amazing feature of SSH is forced commands.
The name is relatively self explanatory.
You give a public key the privilege to execute a single command and nothing else.
This is really useful if there is something that you frequently do on a server which is simple enough that it can be automated but still requires interaction from device.
I make use of a forced command to open NCMPCPP on my MPD server.
Logging in every time and typing `ncmpcpp` every time I wanted to add or remove some songs from the current playlist got annoying really fast.
On my client machines I have an entry in my `~/.ssh/config` with roughly the following:
```ssh_config
Host <host>-radio
Hostname <hostname>
User <mpd-user>
Port <meme-number>
Identityfile ~/.ssh/<host>-radio
IdentitiesOnly yes # here's where forcing it to ignore the ssh agent comes in useful
```
On my MPD server, I have the following in `~/.ssh/authorized_keys`:
```authorized_keys
command="ncmpcpp" ssh-ed25519 <contents of <host>-radio.pub>
```
When I `ssh` to `<host>-radio`, all I get is an NCMPCPP session.
On one of my Raspberry Pis, I make use of a forced command to toggle my desk lamp using a little wrapper I wrote around the Pi's GPIO interface.
It has the following line in `~/.ssh/authorized_keys`:
```authorized_keys
no-pty,command="/path/to/script/lamp toggle" ssh-ed25519 <contents of lamp-key.pub>
```
The `no-pty` option prevents any sessions opened with this key from starting an interactive shell session.
Documentation of the `authorized_keys` file can be found in the `sshd` manpage under the `AUTHORIZED_KEYS FILE FORMAT` section.