Ubuntu 20.04 Full Disk Encryption (LUKS) on the Cloud

Author: Paul Sueno
Created: 5/27/2020 // Updated: 8/17/2020

 

Set up a LUKS encrypted Ubuntu server on the cloud. This is for 20.04 LTS. I chose Ubuntu due to regular updates & strong peer support.

Ubuntu released Focal Fossa (20.04 LTS) in April 2020. This tutorial will set up a LUKS encrypted Ubuntu server on the cloud. Ubuntu is a flavor or distribution of Linux, one of the most widely used open source operating systems out there. It is updated regularly, and many people use it around the world.

The server has to be accessible 24/7 with little risk of down-time. Another requirement is that the whole system has to be encrypted to protect the data from snooping. Canonical threw in a curve ball for this LTS release, and more on this below. All these factors together, I will show you how to install Ubuntu 20.04 LTS as a Linode cloud service.

If you would rather install Ubuntu 18.04 LTS (Bionic Beaver) click here.

Ubuntu and Linode Disclaimer: Ubuntu and the Ubuntu logo are registered trademarks of Canonical Ltd. Linode and the Linode logo are registered trademarks of Linode LLC. This blog references these trademarks as commentary. I am in no way speaking for or on behalf of Canonical or Linode, and I do not imply endorsement by Canonical or Linode.

Cloud or on-site server

Cloud based web services seems like a costly endeavor, but as low as $5 per month it beats paying $2k (or more) up front for a physical server. Another bonus is cloud services generally are on the web all the time. If you set up your server from home, think how many times your internet went down or had to reset the router.

My tutorials will be based on the cloud service I use, Linode. They have a server in my part of the USA, and had all the features I required. But you are more than welcome to use whatever cloud service you want. Others include DigitalOcean, Vultr, Azure, AWS, etc.

Creating a Linode

I started my server with a Linode Nanode at just $5 per month. Since starting out with a Nanode, my server needs have grown larger. Feel free to start there and upgrade if needed. I had to do this, and it wasn't too bad.

Because the operating system will be installed with encryption, the default set ups were inadequate. No worries, I'll walk you through a custom install.

After purchasing your linode, click on it to load up the dashboard. On the menu bar, go all the way to the right and select the "Disks/Configs" tab.

Linode Disks Configs

Linode - add disk & boot configs

Firstly, set up the hard drives/disks:

  • Installer disk, will have Ubuntu netboot install image loaded
  • Rescue disk, will have a rescue boot or live CD/DVD image loaded
  • Main system disk, will be the main server disk

Click on Add a Disk under the Disks section (see image above). You should create three Disks, one for each of the above. Be sure to select Create Empty Disk for each one. Each one will require a label, filesystem and size. We will set up the partitions for the different boot configurations later on.

Canonical has done something odd starting with Ubuntu 20.04 LTS. They have hidden from official documentation the mini.iso installation method. They want installation to occur by net install or by cloud image methods. These will not work for our system. It is too difficult to find a cloud service provider that allows PXE net install. I also don't know of a cloud image install method that allows system-wide encryption. Fortunately, Canonical did create a mini.iso for Focal Fossa. It required some hunting to find.

For the installer, I based the size on how big the "netboot" or network installer for Ubuntu 20.04 LTS (Focal Fossa). This is the smallest installer, and it will download all the necessary packages after the installer boots up. This is what we want; we don't want to waste precious cloud storage space on GB of installer software we will rarely (if ever) use again. You'll see that the mini.iso (the file we'll download later) is 74MB (as of writing this blog). I rounded up and chose 100 MB for the installer disk.

For the rescue disk, I made my own Debian flavor rescue ISO that was about 200MB. The most popular pre-built live or rescue Linux flavor is Knoppix. The CD iso is about 701 MB. You can skip this part all together if you don't think you need a rescue disk, and rely on Linode's own rescue software. I didn't like their limited packages available, and was not too familiar with Finnix, which is what they use.

The rest of the cloud disk space can be allocated to your main system disk. Below are my settings for each disk. You should modify them to meet your needs.

Installer Disk:

  • Create Empty Disk
  • Label: installer
  • Filesystem: ext4
  • Size: 100 MB

Rescue Disk:

  • Create Empty Disk
  • Label: rescue
  • Filesystem: ext4
  • Size: 300 MB (yours may be 700+ MB if you use Knoppix CD or whatever)

System Disk:

  • Create Empty Disk
  • Label: ubuntu
  • Filesystem: raw (this is important!)
  • Size: use the rest available

Linode Add a Disk

Now it's time to set up the boot configurations. Click on Add a Configuration under the Configuration section. With each configuration, we have to decide which disks should be available and which one to boot from. Similar to the disks, I have three separate boot configurations. One each for installer, rescue and system (Ubuntu) boot configurations. When assigning the disks, we tell the configuration how to reference them via the standard Linux method, e.g., /dev/sda, /dev/sdb and /dev/sdc. Here are the settings for each configuration.

Installer Configuration:

  • Label: installer
  • VM Mode: Paravirtualization
  • Select a Kernel: Direct Disk
  • Run Level: Run Default Level
  • Memory Limit: Do not set any limits on memory usage
  • Block Device Assignment
    • /dev/sda: ubuntu (disk)
    • /dev/sdb: installer (disk)
  • Use Custom Root: off
  • Root Device: /dev/sdb
  • Filesystem/Boot Helpers: all off

Rescue Configuration:

  • Label: rescue
  • VM Mode, Kernel, Run Level and Memory: same as above
  • Block Device Assignment
    • /dev/sda: ubuntu (disk)
    • /dev/sdb: rescue (disk)
    • /dev/sdc: installer (disk)
  • Use Custom Root: off
  • Root Device: /dev/sdb
  • Filesystem/Boot Helpers: all off

Ubuntu (system) Configuration:

  • Label: ubuntu
  • VM Mode, Kernel, Run Level and Memory: same as above
  • Block Device Assignment
    • /dev/sda: ubuntu (disk)
  • Use Custom Root: off
  • Root Device: /dev/sda
  • Filesystem/Boot Helpers: all off

Linode Add a Configuration

Linode - other settings

Because we are installing our own custom Ubuntu system, the built-in Linode tools may break our system. On the main dashboard, click on "Settings" tab. There, expancd Shutdown Watchdog and make sure it is Disabled.

Linode Watchdog Disabled

Download Ubuntu and rescue ISO

I know we set up our three boot configurations already. But to get the Ubuntu netboot installer and custom (or Knoppix or other) rescue ISO downloaded, we have to load a one-time "rescue". This is different than the rescue above. Sorry about the naming confusion. Click on "Rescue" tab from the Dashboard.

Set up the following block device assignments:

  • /dev/sda: installer
  • /dev/sdb: rescue
  • /dev/sdc: ubuntu (optional)

Linode Rescue

Click "Reboot into Rescue Mode". After Rescue Mode boots, be sure it says Running above the menu tabs. Then click on "Launch Console" right beside where it says Running. This will load a pop-up that gives us access to the disks we selected above for this one-time rescue boot. We will stay in the Weblish tab.

Linode Launch Console

In the Weblish console, you should see some basic boot status lines and a Welcome to Finnix! line. We are now using Linux, woo hoo!! If you want to confirm you have the right disks assigned, type in lsblk at the root # prompt.

For the rescue ISO, I saved the file onto a webserver I already had set up. You can either download the Knoppix ftp link directly, or use your own. Let me explain the four lines below. The first line downloads the Ubuntu netboot installer as an ISO file. The second line takes the image of the ISO file as the if= (or in file) and clones it to an out file as the actual files. The of= or out file is the installer device block we assigned to /dev/sda.

In other words, we download the installer ISO. The files stored in the installer ISO will then be copied to the installer disk in a bootable format.

A similar process is done for the rescue ISO and disk. Be sure to replace appropriate text inside the square brackets [ ]. Type in the following lines in the command line.

wget http://archive.ubuntu.com/ubuntu/dists/focal/main/installer-amd64/current/legacy-images/netboot/mini.iso
dd if=mini.iso of=/dev/sda
wget http://[Knoppix or your own hyperlink to rescue ISO]
dd if=[rescue ISO file] of=/dev/sdb

Install Ubuntu 20 (Focal)

Now we're ready to install Ubuntu. Go back to the Linode dashboard, and click "Disks/Configs" tab. Under the Configuration section, click on the three-dots ... to the right of installer. Then click "Boot this Config".

Linode Configuration Installer Boot

Be sure the installer configuration has finished booting and has a status of "Running". Now click on "Launch Console" as above. With the pop-up window, click on Glish to start the Ubuntu install. Click on the install screen window, and press Enter to select and proceed with Install.

Linode Glish Ubuntu Install

The first few screens will guide you through the keyboard. I use the default recommendations (standard English US), and probably what you want as well. The installer will then make sure the internet is available and start downloading a few packages.

Next up enter a hostname. This is what your server will be known in your network (even if it's just a network of 1 server). But if you have a domain registered, you can tie this server with that domain and identify the server with the hostname. This can be changed later on. The next screens help the installer find the closest Ubuntu mirrors to download the packages from. The defaults are fine, if you're in the USA. Unless you know you are behind a proxy, leave the HTTP proxy information blank. More packages will be downloaded. Then the installer gets information about you: name, username and password. The installer guesses where your timezone is. Change it if needed, but be sure it is set up in the timezone you want. Next up are steps to encrypt the whole system.

Encrypt - LVM - partition disks

You should be at the screen asking you to [!!] Partition disks. This is where all the magic is done to set up whole-system LUKS encryption (which is based on dm-crypt). We will be encrypting the main system device block, and under that layer of encryption will set up logical volum management (LVM) file systems.

This tutorial will guide you through the Manual set up of encryption, LVM and file system partitioning. I had to do this for setting up minimum requirements for one of the programs I wanted running. If you want to just start out with a basic system encrypted Ubuntu server, feel free to select Guided - use entire disk and set up encrypted LVM. You can join back on the tutorial at the appropriate step. For the rest, go ahead and arrow down to Manual and press Enter.

Ubuntu Install Partition Start

If you set up the device block settings correctly, then SCSI1 or sda should be the system (Ubuntu) disk. You can verify because it is much bigger than SCSI2 or sdb. Select SCSI1 (device block with the largest size), and hit enter. Select Yes to confirm creating a new empty partition table. Now select pri/log [size] FREE SPACE just under the SCSI line selected above. You'll move onto the next screen.

Ubuntu Install Partition Start

Create boot partition first.

  • Select Create a new partition
  • New partition size: 1GB
  • Type: Primary
  • Location: Beginning
  • Use as: Ext4 journaling file system
  • Mount point: /boot
  • OK to leave all other options as is
  • Select Done setting up the partition

Ubuntu Install Partition Start

Create encrypted volume.

  • Move arrow up and select Configure encrypted volumes
  • Write changes and configure encrypted volumes? Yes
  • Select Create encrypted volumes
  • Move arrow down to /dev/sda free #1 (make sure this is largest available)
  • Press spacebar and enter to select
  • OK to use default LUKS settings
  • Select Done setting up the partition
  • Write changes and configure encrypted volumes? Yes
  • Select Finish
  • Enter your Encryption passphrase. WRITE THIS DOWN AND SAVE IT SOMEWHERE SAFE!

Ubuntu Install Partition Start

Create LVM volume group and logical volumes

  • Move arrow up and select Configure the Logical Volume Manager
  • Write changes and configure encrypted volumes? Yes
  • Move arrow down and select Create volume group
    • Remember the hostname you entered before? Use that here. Replace host with your own.
    • I entered: host-vg
  • Select the encrypted partition. It should read /dev/mapper/sda5_crypt
  • Select Create logical volume
    • Select host-vg (or whatever volume group name you created above)
    • Name: root
  • Logical volume size:
    • I had to create a swap space that was 4GB. You can create one much smaller (maybe 1GB).
    • The size you enter here is the available less 4000MB (or less 1000MB)
  • Select Create logical volume
    • Select host-vg (or whatever volume group name you created above)
    • Name: swap
  • Logical volume size: use the rest of the volume (should match the number above)
  • Select Finish

Ubuntu Install Partition Start

Set up the logical volume partitions

  • Create root / partition
    • Move arrow down and select #1 just below LVM VG host-vg, LV root
    • Use as: btrfs (you can use any file system you choose, the standard is ext4)
    • Mount point: / - the root file system
    • OK to leave all other options as is
    • Select Done setting up the partition
  • Create to swap partition
    • Select #1 just below LVM VG host-vg, LV swap
    • Use as: swap area
    • Select Done setting up the partition
  • Before finalizing the partition scheme, verify your screen looks like mine.
    • Under SCSI1, there should be /boot and (sda5_crypt) or similar partitions
    • Under Encrypted volume (sda5_crypt), it should read lvm
    • Under each logical volume or LV, it should read (respectively)
      • btrfs /
      • swap swap
  • Select Finish partitioning and write changes to disk
  • Write changes and configure encrypted volumes? Yes

Ubuntu Install Partition Start

Complete Ubuntu install

I want to update my own system manually. Automatic updates are likely to break my system. And so I picked No automatic updates. To keep a lean machine, I didn't want any bloatware. The only software I installed at this point were OpenSSH server and Basic Ubuntu server (scroll to the bottom of that install screen). Be sure to select Yes when asked about GRUB boot loader. Most importantly, when asked to select Device for boot loader installation: pick /dev/sda. Select Yes when asked about system clock and UTC. Now it's time to shutdown the installer boot configuration and select Continue. Now close the Glish window.

Ubuntu Install Partition Start

Ubuntu inital boot

Go back to the Linode dashboard. Click on "Disks/Configs" menu tab on the right. Under Configuration, go to the ... to the right of ubuntu. Click on Boot This Config. Once the Linode is "Running", click on Launch Console up top. Click on Glish. You should see the window below (sometimes it renders differently). You may need to hit a few arrows to have the text pop up. Type in the LUKS password you created earlier and wrote down to keep safe. If you forget this password, lose the written down copy and the server is reset; you're pretty much screwed. You have been warned.

Ubuntu Install Partition Start

For whatever reason, Ubuntu 20.04 LTS (Focal) seems to hang with a flashing cursor while booting up (after unlocking the LUKS encryption). I had to load a TTY terminal manually by pressing Alt+F1. You may not need to do this, but I did.

You can now log in with the user credentials you created earlier. The sudo command allows you root privileges. Let's also update the apt repositories. After logging in, type in sudo apt update. For most of the file modifications below, I use nano text editor.

The following steps allow us to enter the LUKS password in the Weblish window rather than having to go to Glish. Let's back up and modify the GRUB boot loader by running sudo cp /etc/default/grub /etc/default/grub.bak && sudo nano /etc/default/grub. Modify the following lines:

GRUB_TIMEOUT=1
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="console=ttyS0,19200n8"
GRUB_SERIAL_COMMAND="serial --speed=19200 --unit=0 --word=8 --parity=no --stop=1"
GRUB_TERMINAL=serial

Now run sudo update-grub. Before restarting to see the prompt on Weblish rather than Glish, we have to set up the network. For wahtever reason, Ubuntu loads the wrong name for the network adapter. Find the enp name of the network adapter by running dmesg | grep eth0. Now we modify the netplan configuration file, which tells Ubuntu which network adapter has internet access.

sudo nano /etc/netplan/01-netcfg.yaml

Change the network adapter name to the one we found in the dmesg command above. For example, mine was enp0s3. To save Ctrl-o, to exit Ctrl-x. Now restart the settings by running sudo netplan apply. Test it out by running ping bing.com.

I like the coloring of the hostname and username. Somehow this was disabled by default in one of the LTS releases. Let's add it back in for SSH/TTY access to our server. Let's back up and modify the file by running sudo cp /etc/profile /etc/profile.bak && sudo nano /etc/profile. Add the following line in the top of the file:

TERM="xterm-color"

At the bottom of the file, add the following lines:

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
  xterm-color|*-256color) color_prompt=yes;;
esac

# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
  if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
    # We have color support; assume it's compliant with Ecma-48
    # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
    # a case would tend to support setf rather than setaf.)
    color_prompt=yes
  else
    color_prompt=
  fi
fi

if [ "$color_prompt" = yes ]; then
  PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
  PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
  test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
  alias ls='ls --color=auto'
  #alias dir='dir --color=auto'
  #alias vdir='vdir --color=auto'
  alias grep='grep --color=auto'
  alias fgrep='fgrep --color=auto'
  alias egrep='egrep --color=auto'
fi

Now restart the server by running sudo shutdown now. Go back to the Linode dashboard and boot the Ubuntu config.

If you have a domain name you own, think of a hostname to use for this server. Examples may include imap, smtp, mail, www, etc. I picked a random word for mine. As you recall, I chose host as my host name for this tutorial. The hostname can be modified via sudo nano /etc/hostname.

Let's get the default server settings given to us by Linode's DHCP server. Type in ifconfig. The network device is in the format enp0sn (where n is a number). The ipv4 is inet and ipv6 are inet6. The one we want (what I'll refer to as [ipv6]) is the one that does not start with fe80:.

Now it's time to allow us to identify ourselves to the world wide web. For this to actually work, you will also need to create A/AAAA DNS records with your domain registrar (beyond scope of this tutorial, just Bing it). Let's back up the hosts file and then edit it.

sudo cp /etc/hosts /etc/hosts.bak
sudo nano /etc/hosts

Comment out the line with the specific address 127.0.1.1 ... by adding a pound sign to it. It should look like #127.0.1.1 .... Be sure to keep the loop back devices as is for both ipv4 and ipv6. Add the Linode server's ip addresses from above (replace yours without the square brackets) and place your own host and domain names (do not use my example host.domain.com).

[ipv4] host.domain.com host
[ipv6] host.domain.com host

The hosts file should look something like this (be sure to replace with your own info).

127.0.0.1  localhost
#127.0.1.1 host.members.linode.com host
[ipv4]     host.domain.com host

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
[ipv6]  host.domain.com host

Harden server SSH

The Glish interface is wonderful for what it's for, but it is cumbersome. I like ssh'ing into the server via a terminal.

I'll assume the only person you want logging in is you. Type in the command to make a backup of the original ssh configuration file.

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config

In the nano editor, add the following lines to the top. For [username] type in your own username.

PasswordAuthentication yes
AllowUsers [username]
PubkeyAuthentication yes
PermitRootLogin no

Now that the ssh server daemon knows only you have access, let's restart the service. After typing in exit below, make sure Glish is back to the login screen. You can close the window afterwards.

sudo service ssh restart
exit

Now let's talk about ssh tunnels, and some basic terminaology. An ssh tunnel allows secure encrypted access between two computers. How we will use it is a local (think laptop or desktop workstation) and remote (or Linode server) ssh connection. One way to get access is by supplying a username and password. But a better method is by creating a secure key on the local machine, and then saving the public key on the remote server.

To create an ssh key, there are two basic methods I use: (1) Linux way and (2) Windows way. The Windows way is through the Putty and its keygen programs. I leave it to you to explore this option yourself.

For the Linux way, make sure you are on your local (laptop or desktop) device. At your $ command prompt, type ssh-keygen. You can use the default name or type in your own, but make sure it is saved in your /home/[username]/.ssh/ directory. I use the default settings and save a password. The password is optional. I will assume you didn't change the default name, and a key-pair named id_rsa was created. If you will be doing ssh to multiple remote servers/hosts, then I recommend creating a unique name for each.

Now we need to get the key we just created for the local machine readable to the remote (Linux server) host. A simple way to do this is by using the ipv4 address from above. Use the command at your local device $ prompt: ssh-copy-id [username]@[ipv4]. Be sure to substitute your username and ipv4 inside the square brackets. Alternatively, you can copy the contents of the local /home/[username]/.ssh/id_rsa.pub (via nano or cat) and paste it in the remote (Linode server) /home/[username]/.ssh/authorized_keys.

Here are commands to get from local device to remote server via ssh. The usual Linux format for the command prompt is shown. Only type in commands to the right of the $ prompt. Initially it will ask to save the remote key fingerprint locally. Allow this to happen. You will also login via username and password (will change this later). I also showed the commands to create the authorized_keys file. If you copied the pulbic key via ssh-copy-id, then you shouldn't have to create the authorized_keys file. If you did have to create the file, the last two lines are essential. Otherwise, ssh won't work.

[username]@local$ ssh [username]@[ipv4]
[username]@remote$ mkdir /home/[username]/.ssh
[username]@remote$ touch /home/[username]/.ssh/authorized_keys
[username]@remote$ chmod 700 /home/[username]/.ssh
[username]@remote$ chmod 600 /home/[username]/.ssh/authorized_keys

Now that the key-pair has been created and saved on both local device and remote server, let's only allow logging in via keys. This will prevent people from "guessing" or brute-force attacking your server via ssh. Be sure your terminal has an active ssh connection to your Linode server. Edit the ssh server configuration file on the server: sudo nano /etc/ssh/sshd_config. Modify the file with the below lines at the top of the file. Note that PasswordAuthentication is set to no.

PasswordAuthentication no
AllowUsers [username]
PubkeyAuthentication yes
PermitRootLogin no

Harden server firewall

I don't use the default ufw. Instead, I prefer the granular controlability allowed with iptables. The basic template of my iptables is based on the github examples by @jirutka.

The following steps will turn off and disable ufw. Then download a service that allows the iptables rules be saved and reloaded correctly, when the server is reboot or shutdown. OK to save current iptables when prompted.

sudo service ufw stop
sudo systemctl disable ufw.service
sudo apt install iptables-persistent 

Copy-paste the iptables rules by @jirutka to a text editor. Modify any lines that you may want. If you don't need ipv6, then turn it off in Ubuntu. Look into this tutorial by linuxbabe. Now copy-paste these modified rules files to /etc/iptables/rules.v4 and /etc/iptables/rules.v6 (if using ipv6). In case you happen to use the command sudo iptables-save, make sure you save the formatted rules files. That way you have them as reference. Otherwise, the command saves the iptables without any formatting.

sudo cp /etc/iptables/rules.v4 /etc/iptables/rules.v4.formatted
sudo cp /etc/iptables/rules.v6 /etc/iptables/rules.v6.formatted

Another program to consider is Fail2Ban. This program reviews common server and system log files to see if there are bad actors trying to access your server. If the bad actor rules are met, Fail2Ban temporarily blocks their ip address via iptables.

Now that your encrypted Ubuntu 20.04 LTS (Focal) server is up and running, there's so much you can do with it.

 
 
media,300x250,535618142
media,300x250,901397075
media,300x250,847922767
media,300x250,772653645
media,300x250,798588748
media,300x250,248431445
media,320x50,761747016
media,320x50,775121733

Suenotek Blog

Seattle, Washington

Cookies | Privacy | Policy

About | Contact Us