Using luks/cryptsetup and loopdevices to create encrypted containers
Table of Contents
1. Creating the container
We need to create a file, encrypt it and format. I use fallocate because it may be faster than dd, as it uses a special syscall.
exec 2>&1 set -x fallocate -l 1G /tmp/container dev=$(sudo losetup --find --show /tmp/container) head -c 5000 /dev/urandom > /tmp/container-pwd sudo cryptsetup luksFormat --type luks2 "$dev" /tmp/container-pwd sudo cryptsetup open --type luks2 "$dev" container-luks --key-file /tmp/container-pwd lsblk sudo mkfs.ext4 /dev/mapper/container-luks sudo cryptsetup close container-luks :
+ fallocate -l 1G /tmp/container ++ sudo losetup --find --show /tmp/container + dev=/dev/loop0 + head -c 5000 /dev/urandom + sudo cryptsetup luksFormat --type luks2 /dev/loop0 /tmp/container-pwd + sudo cryptsetup open --type luks2 /dev/loop0 container-luks --key-file /tmp/container-pwd + lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 1G 0 loop └─container-luks 254:0 0 1008M 0 crypt zd0 230:0 0 20G 0 disk /var/lib/docker nvme0n1 259:0 0 1.8T 0 disk ├─nvme0n1p1 259:1 0 512M 0 part /efi ├─nvme0n1p2 259:2 0 512M 0 part /boot ├─nvme0n1p3 259:3 0 700G 0 part ├─nvme0n1p4 259:4 0 200G 0 part ├─nvme0n1p5 259:5 0 16M 0 part └─nvme0n1p6 259:6 0 195G 0 part nvme1n1 259:7 0 1.8T 0 disk ├─nvme1n1p1 259:8 0 512M 0 part ├─nvme1n1p2 259:9 0 512M 0 part └─nvme1n1p3 259:10 0 700G 0 part + sudo mkfs.ext4 /dev/mapper/container-luks mke2fs 1.46.5 (30-Dec-2021) Creating filesystem with 258048 4k blocks and 64512 inodes Filesystem UUID: 0ed2c690-97e4-46ed-8c1a-bf8db5667400 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: 0/8 done Writing inode tables: 0/8 done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: 0/8 done + sudo cryptsetup close container-luks + :
Now, /tmp/container is an encrypted file which (after decryption) is formatted with ext4.
2. Mounting the container for work
We can't mount an ordinary file - we need to create a /dev entry for it. losetup handles that by creating virtual devices. Then we decrypt the file with cryptsetup and mount an ext4 partition
exec 2>&1 set -x dev=$(sudo losetup --find --show /tmp/container) sudo cryptsetup open --type luks2 "$dev" container-luks --key-file /tmp/container-pwd sudo mount /dev/mapper/container-luks /mnt :
++ sudo losetup --find --show /tmp/container + dev=/dev/loop1 + sudo cryptsetup open --type luks2 /dev/loop1 container-luks --key-file /tmp/container-pwd + sudo mount /dev/mapper/container-luks /mnt + :
3. Unmounting the partition after work.
Linux will handle that on shutdown but you can do it manually. Crafting jq invocation took most of the time.
exec 2>&1 set -x sudo umount /mnt sudo cryptsetup close container-luks dev=$(losetup -l -J | jq --raw-output '.loopdevices | map(select(."back-file" == "/tmp/container"))[0] | .name') sudo losetup -d "$dev" :
+ sudo umount /mnt + sudo cryptsetup close container-luks ++ losetup -l -J ++ jq --raw-output '.loopdevices | map(select(."back-file" == "/tmp/container"))[0] | .name' + dev=/dev/loop1 + sudo losetup -d /dev/loop1 + :
4. Removing the container
That's as easy as removing the files.
exec 2>&1 set -x # find the loopdev which mapped container rm /tmp/container /tmp/container-pwd :
+ rm /tmp/container /tmp/container-pwd + :