(This was originally on my old website, I have resurrected it here.)
Here we do some basic server setup, hardening it in preparation for whatever we want to use it for, in my case, hosting this website.
I am using a DigitalOcean Ubuntu 14.04 instance.
The plan is to disable root login, and only allow login to a new user using ssh keys.
We start with a freshly spun-up droplet.
ssh root@<SERVER_IP>
Create a new user, and add it to the sudo group.
adduser <USERNAME>
gpasswd -a <USERNAME> sudo
Back on our client machine generate an SSH key pair, and upload our public key to the server.
ssh-keygen -t rsa -b 4096
ssh-copy-id <USERNAME>@<SERVER_IP>
Over on the server, in /etc/ssh/sshd_config
, we want PermitRootLogin no
and PasswordAuthentication no
. This will disable logging in as root, and disable logging in using a password (so key only login).
service ssh restart
Now exit and ssh in as the new user.
We will drop all incoming connections except TCP connections for HTTP and HTTPS. SSH will be concealed using SPA (single packet authorisation). As a matter of practice make sure out-of-band management is in place in case you lock yourself out.
Make sure the default policy is to accept before we flush, so we are not kicked off
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -F
Drop invalid packets
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
Allow loopback connections
sudo iptables -A INPUT -i lo -j ACCEPT
Allow packets that are part of an established connection, and those that are associated with it
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Allow TCP connections to ports 80 and 443
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Change back to the default drop policy
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
Now, iptables rules do not persist restarts, to remedy this
sudo apt-get install iptables-persistent
Next we set up SPA using fwknop. This allows us to send an encrypted packet that is passively sniffed by a daemon running on the server, if we successfully authenticate then a temporary firewall rule is added exposing a service to only our IP for a predefined time period. This obviates the need for tools such as Fail2ban. We will use this to conceal the SSH service.
On the client
sudo apt-get install fwknop-client
We will use AES128-CBC+HMAC-SHA256, since 4096 bit RSA keys are protecting actual login, but if required, fwknop can be configured to use OpenPGP key pairs instead.
Generate the config stanza used when knocking at our server
fwknop -n <NAME> -A tcp/22 -R -D <SERVER_IP> --use-hmac --hmac-digest-type=SHA256 --key-gen --key-len=16 --hmac-key-len=64 --save-rc-stanza
This gets written to ~/.fwknoprc
.
When we want to knock do
fwknop -n
But we still have the server to do, so on the server
sudo apt-get install fwknop-server
Copy thy keys from ~/.fwknoprc
on the client into /etc/fwknop/access.conf
on the server, and add which port to open
SOURCE ANY
OPENPORTS tcp/22
KEY_BASE64 <KEY_BASE64 from client>
HMAC_KEY_BASE64 <HMAC_KEY_BASE64 from client>
Now, fwknop uses timestamps so it is best to keep our server time synced
sudo apt-get install ntp
We can see everything works by knocking from the client then checking an extra rule has been added to iptables
sudo iptables -S
We now have a secure base to build upon, make sure to back up your .ssh
, and .fwknop
directories. Some further improvements may include using OpenPGP keys for both SSH authentication and SPA, and storing the keys on an OpenPGP card, meaning only pointers to the keys are stored on the client, so we are required to insert the card when we want to login.