267 lines
10 KiB
Markdown
267 lines
10 KiB
Markdown
---
|
|
title: "SSH Configuration"
|
|
date: "2022-09-27T11:40:31+02:00"
|
|
author: "$HUMANOID"
|
|
tags: ["ssh", "technology"]
|
|
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
|
|
---
|
|
|
|
# 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.
|
|
|
|
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).
|
|
|
|
# Server Configuration
|
|
|
|
This is all done under the assumption that the you use the OpenSSH implementation on your server.
|
|
If you use something like Dropbear, I can't help you as haven't properly dug through it's configuration file (yet).
|
|
|
|
The thing I see way to often on the internet is
|
|
|
|
* People not disabling password authentication.
|
|
* 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.
|
|
|
|
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.
|
|
|
|
If you're not planning on logging in as the root user, uncomment and set the following setting to "no"
|
|
```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.
|
|
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>
|
|
```
|
|
I'm usually too lazy to use the proper way and just open the file in `vi` paste it in there by hand during the same initial login where I'm disabling password authentication.
|
|
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
|
|
|
|
In `/etc/ssh/sshd_config` look for
|
|
```sshd_config
|
|
...
|
|
#Port 22
|
|
#AddressFamily any
|
|
#ListenAddress 0.0.0.0
|
|
#ListenAddress ::
|
|
...
|
|
```
|
|
and change the `Port` to your liking, I tend to change this to something like 6969 or some other meme number.
|
|
|
|
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.
|
|
|
|
# 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
|
|
IdentityFile ~/.ssh/<key-file>
|
|
User <user-name>
|
|
Port <meme-number>
|
|
```
|
|
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:
|
|
```sh
|
|
ssh <user-name>@<hostname> -p <meme-number> -i ~/.ssh/<key-file>
|
|
```
|
|
Instead the following command will work:
|
|
```sh
|
|
ssh <host>
|
|
```
|
|
|
|
More information on the SSH config file can be found in the `ssh_config` manpage.
|
|
|
|
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.
|
|
|
|
### `ProxyCommand`
|
|
|
|
Always connect to your host using a proxy, using a given command.
|
|
|
|
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"
|
|
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.
|