Remote encrypted backup with iSCSI and LUKS2

The idea here is to have a LUKS2 encrypted volume stored on a remote server that allows authenticated clients to load and decrypt it without letting the server know what data are being written, read and stored.

.:. Server A.K.A. Target
Install the required packages:

su -c "yum install targetcli && systemctl start target && systemctl enable target"

Target configuration is done via the command line utility targetcli.
Select a device or a file as backstore:

sudo targetcli

/> /backstores/fileio create file1 /tmp/disk1.img 2000GB write_back=false

Create an iSCSI target:

/> iscsi/
/iscsi> create

Configure a LUN:

/iscsi/iqn.20...mple:444/tpg1> luns/ create /backstores/fileio/file1

Add some ACLs, to get the server FQDN use:

sudo iscsiadm -m discovery -t st -p
/iscsi/iqn.20...mple:444/tpg1> acls/
/iscsi/iqn.20...444/tpg1/acls> create <FQDN>

Disable authentication and set a user/password for CHAP auth:

/iscsi/iqn.20...mple:444/tpg1 set attribute authentication=0
/iscsi/iqn.20...mple:444/tpg1/acls/iqn.20...mple:444/ set auth userid=<USER> password=<PASSWORD>

Restart the service:

sudo systemctl restart target

.:. Client A.K.A. Initiator
Install the required packages:

sudo dnf install -y iscsi-initiator-utils

Edit iSCSI configuration file to instruct the initiator to use CHAP authentication, uncomment or add the following lines:

node.session.auth.authmethod = CHAP
# As USER and PASSWORD use the ones you created on the Target machine when defining the iSCSI LUN
node.session.auth.username = <USER>
node.session.auth.password = <PASSWORD>

Discover and load the iSCSI target:

sudo iscsiadm -m discovery -t sendtargets -p <TARGET-IP-ADDRESS>
sudo iscsiadm -m discovery -P1
sudo systemctl restart iscsid
sudo iscsiadm -m node -T <FQDN displayed using the discovery command> -l

Now that the iSCSI target is loaded we can mount it, but first we need to identify its device name (in this case it is /dev/sdf):

lsblk --scsi
sda  1:0:0:0    disk ATA      AAA              BBB  sata
sdb  4:0:0:0    disk ATA      AAA              BBB  sata
sdc  5:0:0:0    disk ATA      AAA              BBB  sata
sdd  6:0:0:0    disk ATA      AAA              BBB  sata
sde  7:0:0:0    disk ATA      AAA              BBB  sata
sdf  10:0:0:0   disk LIO-ORG  backup           4.0  iscsi

The iSCSI target behaves like a physical hard drive, we can partion it, format it, mount it, etc as usual.
In this particular case we want to create a LUKS2 encrypted volume, to do so run:

sudo cryptsetup luksFormat -M luks2 --pbkdf argon2id -i 5000 /dev/sdf
sudo cryptsetup luksOpen /dev/sdf <luks_volume_name>
sudo mkfs.xfs /dev/mapper/<luks_volume_name>
sudo mount /dev/mapper/<luks_volume_name> /mountpoint

To unmount the encrypted LUKS2 iSCSI target run:

sudo sync
sudo umount /mnt/backup
sudo cryptsetup luksClose /dev/mapper/backup
sudo iscsiadm -m node -T <FQDN displayed using the discovery command> -u

.:. Target iptables configuration
Instruct iptables to allow TCP traffic on port 3260.

systemctl stop iptables

Add the following rule and restart iptables.

-A INPUT -p tcp -m state --state NEW -m tcp --dport 3260 -j ACCEPT
systemctl start iptables

.:. Links

LUKS2 the right way: Argon2

Version 2 of cryptsetup got a few new fancy options, one of them is the ability to use Argon2 as key derivation function.
Creating a LUKS2 volume with Argon2 as hash function is very easy:

sudo cryptsetup luksFormat -M luks2 --pbkdf argon2id -i 5000 /dev/sdb

Please note that grub still does not support it, so it can’t be used for boot drives.
Once the volume is created, to mount it run:

sudo cryptsetup luksOpen /dev/sdb <luks_volume_name>
sudo mkfs.xfs /dev/mapper/<luks_volume_name>
sudo mount /dev/mapper/<luks_volume_name> /mountpoint

To have the the volume mounted at boot add the following lines to the files:

<luks_volume_name> UUID=2e100f89-b0dd-44f3-9c0c-e8cab0d4fc14 none discard
/dev/mapper/<luks_volume_name> 	/mountpoint	xfs	defaults,x-systemd.device-timeout=0,noatime	0 0

To manually mount a LUKS volume run:

sudo cryptsetup luksOpen /dev/sdb <luks_volume_name> mountpoint
sudo mount /dev/mapper/<luks_volume_name>

To manually unmount a LUKS volume run:

sudo umount /mountpoint
sudo cryptsetup luksClose /dev/mapper/<luks_volume_name>

To get info regarding a LUKS encrypted volume run:

sudo cryptsetup luksDump /dev/sdb

Here comes the fun part, let’s say we have a LUKS2 volume and we want to change key derivation algorithm to argon2i/d/id without having to re-encrypt the whole volume:

sudo dnf install cryptsetup-reencrypt
sudo cryptsetup-reencrypt --keep-key --pbkdf argon2id /dev/sdb

As a general not, Argon2id is the all around best variant of it, don’t use Argon2i or Argon2d unless you really know what you are doing
After changing crypttab and fstab remember to regenerate initramfs, to do so on Fedora/Centos/RHL run:

sudo dracut --regenerate-all --force

Generate a secure SSH key

In Fedora, CentOS and probably many other Linux distros “ssh-keygen” still defaults to RSA 2048.
People have not yet realized that the newer, and also faster, elliptic curve cryptography is available; even between my peers I still see that many of them are using old and insecure RSA based keys.
Since SSH clients support multiple keys transitioning to newer keys can be painless:
1. create a new elliptic curve key;
2. do not delete the old RSA key;
3. once you login into a server swap the old key with the new one.
Generating a new secure SSH key is pretty simple, just open a terminal and run:

ssh-keygen -o -a 256 -t ed25519