Installing and Hardening an Ubuntu Server: Difference between revisions

From Stiles Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
This guide will help you install, configure, and secure a golden image for your Ubuntu servers.
This guide will help you install, configure, and secure a golden image for your Ubuntu servers.
==Requirements==
==Requirements==
This guide assumes you know the basics of installing an operating system on a computer.
This guide assumes you know the basics of installing an operating system on a computer.
==Installing the Ubuntu Server==
==Installing the Ubuntu Server==
This should be a pretty standard answer the questions and follow the directions on screen. If you want a static IP address you can set it here, but I like to set a static address through DHCP instead of on the actual server. I also like to use LVM for the disk set ups.
This should be a pretty standard answer the questions and follow the directions on screen. If you want a static IP address you can set it here, but I like to set a static address through DHCP instead of on the actual server. I also like to use LVM for the disk set ups.
==Update and Configure==
==Update and Configure==
After you've finished installing the OS, it's time to connect to the server and begin updates and a base configuration. I connect through SSH, but you can do it the physical box if you want. I've found that if you don't make any changes to the default disk settings, you fill up the disk very quickly. Let's change that first, we need to resize the logical volume to use all the existing and free space of the volume group.


After you've finished installing the OS, it's time to connect to the server and begin updates and a base configuration. I connect through SSH, but you can do it the physical box if you want.
===Fix Disk Size===
I've found that if you don't make any changes to the default disk settings, you fill up the disk very quickly. Let's change that first, we need to resize the logical volume to use all the existing and free space of the volume group.
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
sudo lvm
sudo lvm
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="lvm">
<syntaxhighlight lang="lvm">
lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
exit
exit
</syntaxhighlight>
</syntaxhighlight>
And then, we need to resize the file system to use the new available space in the logical volume. After that's done, we should make sure that it shows the new disk size.
And then, we need to resize the file system to use the new available space in the logical volume. After that's done, we should make sure that it shows the new disk size.
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
Line 23: Line 25:
</syntaxhighlight>
</syntaxhighlight>


===Update the Server===
Next, let's get the latest updates for the server and remove any space wasters.
Next, let's get the latest updates for the server and remove any space wasters.
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
sudo apt update && sudo apt -y upgrade && sudo apt -y autoremove
sudo apt update && sudo apt -y upgrade && sudo apt -y autoremove
</syntaxhighlight>
</syntaxhighlight>


===Timezone, Charset, Unattended Upgrades===
Now we need to configure the timezone and our charset. If you want to enable unattended upgrades, now is a good time to do that as well.
Now we need to configure the timezone and our charset. If you want to enable unattended upgrades, now is a good time to do that as well.
<syntaxhighlight lang="bash">
sudo dpkg-reconfigure tzdata && locale-gen en_US.UTF-8 && dpkg-reconfigure locales && dpkg-reconfigure -plow unattended-upgrades
</syntaxhighlight>


===Hostname===
Check your hostname to make sure it's set correctly.
<syntaxhighlight lang="bash">
hostnamectl
</syntaxhighlight>
If the previous command returned the wrong hostname, you can run the following command to change it permanently. Change <hostname> to what you want the new hostname to be, without the <>.
<syntaxhighlight lang="bash">
sudo hostnamectl set-hostname <hostname>
</syntaxhighlight>
If you change the hostname, it's a good idea to update the hosts file with the new hostname.
<code>
/etc/hosts
</code>
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
sudo dpkg-reconfigure tzdata && locale-gen en_US.UTF-8 && dpkg-reconfigure locales && dpkg-reconfigure -plow unattended-upgrades
127.0.0.1 <FQDN> <hostname> localhost
...
</syntaxhighlight>
</syntaxhighlight>


==Securing the Server==
==Securing the Server==
===ICMP Requests===
Now we can begin securing the server, first we should block ICMP requests.
<code>
/etc/sysctl.d/50-ip-sec.conf
</code>
<syntaxhighlight lang="bash">
# Disable Source Routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# Disable acceptance of all ICMP redirected packets on all interfaces
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Disable send IPv4 redirect packets
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Set Reverse Path Forwarding to strict mode as defined in RFC 3704
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Block pings
net.ipv4.icmp_echo_ignore_all = 1
# Syn flood help
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Log suspicious martian packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians=1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Disable IPv6 auto config
net.ipv6.conf.default.accept_ra=0
net.ipv6.conf.default.autoconf=0
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.all.autoconf=0
net.ipv6.conf.eth0.accept_ra=0
net.ipv6.conf.eth0.autoconf=0
# Disable TCP Timestamps
net.ipv4.tcp_timestamps=0
</syntaxhighlight>
===Spoofing Attacks===
Next we should block spoofing attacks.
<code>
/etc/sysctl.conf
</code>
<syntaxhighlight lang="bash">
...
# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# _or_
# Accept ICMP redirects only for gateways listed in our default
# gateway list (enabled by default)
net.ipv4.conf.all.secure_redirects = 0
#
# Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0
#
# Do not accept IP source route packets (we are not a router)
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
#
# Log Martian Packets
net.ipv4.conf.all.log_martians = 1
...
</syntaxhighlight>
==Configuring the Firewall==
==Configuring the Firewall==
Next we should set up a firewall. Ubuntu comes with UFW, which is what I'll be using. If you're using SSH, make sure to open that port before you enable the firewall.
<syntaxhighlight lang="bash">
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw enable
</syntaxhighlight>
We can check the status of the firewall, and see what we're allowing through by running the following.
<syntaxhighlight lang="bash">
sudo ufw status
</syntaxhighlight>
Now we'll drop all ICMP connections at the firewall as well.
<code>
/etc/ufw/before.rules
</code>
<syntaxhighlight lang="bash">
...
# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP
...
</syntaxhighlight>
==Installing Fail2Ban==
==Installing Fail2Ban==
We'll want to set up a way to ban IP addresses that attempt to connect to your server but fail repeatedly.
<syntaxhighlight lang="bash">
sudo apt install fail2ban
</syntaxhighlight>
The default settings work for most set ups, but make any changes you feel necessary.
Run the following to see who is currently blocked.
<syntaxhighlight lang="bash">
sudo fail2ban-client status
sudo fail2ban-client status sshd
</syntaxhighlight>
==Securing SSH==
==Securing SSH==
 
===Creating a RSA Key Pair===
I use an RSA key pair  to connect to my servers through SSH. If you’ve never set up a RSA key pair, continue from here. If you have, skip ahead to copy the RSA key. On the machine you connect from, run the following to generate an RSA key pair.
<syntaxhighlight lang="bash">
ssh-keygen -b 4096
</syntaxhighlight>
===Copy the Key to the Server===
Next we need to copy the pubic key to the server. I like to use ssh-copy-id if it's available, but that won't be possible through PowerShell if you're using Windows.
<code>
Bash/Terminal
</code>
<syntaxhighlight lang="bash">
ssh-copy-id <username>@<hostname_or_ip_address>
</syntaxhighlight>
<code>
Windows Powershell
</code>
<syntaxhighlight lang="bash">
cat ~/.ssh/id_rsa.pub | ssh <username>@<hostname_or_ip_address> "mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod -R go= ~/.ssh && cat >> ~/.ssh/authorized_keys"
</syntaxhighlight>
You should now be able to connect to your server with your key.
===Disable Password Authentication===
You should now be able to ssh into your server without being prompted for your password. If you set up a passphrase for your key, you will be prompted for it.
We now should disable password authentication for ssh entirely. Locate the following line and change it.
<code>
/etc/ssh/sshd_config
</code>
<syntaxhighlight lang="bash">
...
PasswordAuthentication no
...
</syntaxhighlight>
All that's left is to restart the SSH service. Please note that you will be disconnected if you are currently connected to your server over ssh.
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
sudo systemctl restart ssh
</syntaxhighlight>
</syntaxhighlight>
I know that it’s also a good idea to change the default port that ssh runs on, but I don’t since I don’t let that port talk to anything outside my network. You can if you want though.
I also like to restart a fresh server after this whole process, but that's not always necessary.

Latest revision as of 20:00, 12 December 2020

This guide will help you install, configure, and secure a golden image for your Ubuntu servers.

Requirements

This guide assumes you know the basics of installing an operating system on a computer.

Installing the Ubuntu Server

This should be a pretty standard answer the questions and follow the directions on screen. If you want a static IP address you can set it here, but I like to set a static address through DHCP instead of on the actual server. I also like to use LVM for the disk set ups.

Update and Configure

After you've finished installing the OS, it's time to connect to the server and begin updates and a base configuration. I connect through SSH, but you can do it the physical box if you want.

Fix Disk Size

I've found that if you don't make any changes to the default disk settings, you fill up the disk very quickly. Let's change that first, we need to resize the logical volume to use all the existing and free space of the volume group.

sudo lvm
lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
exit

And then, we need to resize the file system to use the new available space in the logical volume. After that's done, we should make sure that it shows the new disk size.

sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
df -h

Update the Server

Next, let's get the latest updates for the server and remove any space wasters.

sudo apt update && sudo apt -y upgrade && sudo apt -y autoremove

Timezone, Charset, Unattended Upgrades

Now we need to configure the timezone and our charset. If you want to enable unattended upgrades, now is a good time to do that as well.

sudo dpkg-reconfigure tzdata && locale-gen en_US.UTF-8 && dpkg-reconfigure locales && dpkg-reconfigure -plow unattended-upgrades

Hostname

Check your hostname to make sure it's set correctly.

hostnamectl

If the previous command returned the wrong hostname, you can run the following command to change it permanently. Change <hostname> to what you want the new hostname to be, without the <>.

sudo hostnamectl set-hostname <hostname>

If you change the hostname, it's a good idea to update the hosts file with the new hostname. /etc/hosts

127.0.0.1 <FQDN> <hostname> localhost
...

Securing the Server

ICMP Requests

Now we can begin securing the server, first we should block ICMP requests. /etc/sysctl.d/50-ip-sec.conf

# Disable Source Routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0 
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

# Disable acceptance of all ICMP redirected packets on all interfaces
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0 
net.ipv6.conf.default.accept_redirects = 0

# Disable send IPv4 redirect packets
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Set Reverse Path Forwarding to strict mode as defined in RFC 3704
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Block pings
net.ipv4.icmp_echo_ignore_all = 1

# Syn flood help
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5

# Log suspicious martian packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians=1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Disable IPv6 auto config
net.ipv6.conf.default.accept_ra=0
net.ipv6.conf.default.autoconf=0
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.all.autoconf=0
net.ipv6.conf.eth0.accept_ra=0
net.ipv6.conf.eth0.autoconf=0

# Disable TCP Timestamps
net.ipv4.tcp_timestamps=0

Spoofing Attacks

Next we should block spoofing attacks. /etc/sysctl.conf

...
# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# _or_
# Accept ICMP redirects only for gateways listed in our default
# gateway list (enabled by default)
net.ipv4.conf.all.secure_redirects = 0
#
# Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0
#
# Do not accept IP source route packets (we are not a router)
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
#
# Log Martian Packets
net.ipv4.conf.all.log_martians = 1
...

Configuring the Firewall

Next we should set up a firewall. Ubuntu comes with UFW, which is what I'll be using. If you're using SSH, make sure to open that port before you enable the firewall.

sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw enable

We can check the status of the firewall, and see what we're allowing through by running the following.

sudo ufw status

Now we'll drop all ICMP connections at the firewall as well. /etc/ufw/before.rules

...
# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP
...

Installing Fail2Ban

We'll want to set up a way to ban IP addresses that attempt to connect to your server but fail repeatedly.

sudo apt install fail2ban

The default settings work for most set ups, but make any changes you feel necessary. Run the following to see who is currently blocked.

sudo fail2ban-client status
sudo fail2ban-client status sshd

Securing SSH

Creating a RSA Key Pair

I use an RSA key pair to connect to my servers through SSH. If you’ve never set up a RSA key pair, continue from here. If you have, skip ahead to copy the RSA key. On the machine you connect from, run the following to generate an RSA key pair.

ssh-keygen -b 4096

Copy the Key to the Server

Next we need to copy the pubic key to the server. I like to use ssh-copy-id if it's available, but that won't be possible through PowerShell if you're using Windows. Bash/Terminal

ssh-copy-id <username>@<hostname_or_ip_address>

Windows Powershell

cat ~/.ssh/id_rsa.pub | ssh <username>@<hostname_or_ip_address> "mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod -R go= ~/.ssh && cat >> ~/.ssh/authorized_keys"

You should now be able to connect to your server with your key.

Disable Password Authentication

You should now be able to ssh into your server without being prompted for your password. If you set up a passphrase for your key, you will be prompted for it. We now should disable password authentication for ssh entirely. Locate the following line and change it. /etc/ssh/sshd_config

...
PasswordAuthentication no
...

All that's left is to restart the SSH service. Please note that you will be disconnected if you are currently connected to your server over ssh.

sudo systemctl restart ssh

I know that it’s also a good idea to change the default port that ssh runs on, but I don’t since I don’t let that port talk to anything outside my network. You can if you want though. I also like to restart a fresh server after this whole process, but that's not always necessary.