ラズパイのrootfsをLUKSで暗号化する

rootfs全体をLUKSで暗号化し、起動時に手動 / 自動でロック解除する方法について記載する。
自動でロック解除する場合は鍵ファイルを使用し、鍵ファイルはbootfsのinitramfsに平文で埋め込む。


### ■参考資料
- [cryptsetup - GitLab](https://gitlab.com/cryptsetup/cryptsetup/-/wikis/FrequentlyAskedQuestions#2-setup)
- [Debian Cryptsetup Initramfs integration - Debian Cryptsetup docs](https://cryptsetup-team.pages.debian.net/cryptsetup/README.initramfs.html)
- [dm-crypt/システム設定 - ArchWiki](https://wiki.archlinux.jp/index.php/Dm-crypt/%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E8%A8%AD%E5%AE%9A#crypttab)
- [dm-crypt/システム全体の暗号化 - ArchWiki](https://wiki.archlinux.jp/index.php/Dm-crypt/%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E5%85%A8%E4%BD%93%E3%81%AE%E6%9A%97%E5%8F%B7%E5%8C%96#.E3.83.96.E3.83.BC.E3.83.88.E3.83.AD.E3.83.BC.E3.83.80.E3.83.BC.E3.81.AE.E8.A8.AD.E5.AE.9A)

### ■作業環境
- Raspberry Pi 5
    - Raspberry Pi OS Lite(64bit)
- Ubuntu 24.04(VirtualBox)

### ■cryptsetupのインストール（ラズパイ）
Raspberry Pi Imagerでイメージを書き込んだmicroSDカードをラズパイに挿入し、cryptsetupをインストールする。暗号化したrootfsで起動するのに必要なinitramfs-tools, busyboxは最初からラズパイにインストール済。
```
$ sudo apt update
$ sudo apt install -y cryptsetup-initramfs
```

### ■rootfsを暗号化する（Ubuntu）
microSDカードをラズパイから抜去し、Ubuntu側のUSBカードリーダーに挿入する。
- SDカードのデバイス名は都度変わるため、確認し読み替える（sda, sdbなど）
- 暗号化するrootfsのPARTUUIDは後で必要になるためメモしておく
```
$ lsblk
sdb      8:16     1  14.4G  0 disk 
├─sdb1   8:17   1   512M  0 part /media/【ユーザー名】/bootfs
└─sdb2   8:18   1  13.9G  0 part /media/【ユーザー名】/rootfs

$ sudo blkid
/dev/sdb2: LABEL="rootfs" ... TYPE="ext4" PARTUUID="e44a4b6b-02"
```

暗号化する前にrootfsの中身を退避する。
```
$ sudo mkdir /mnt/orig
$ sudo rsync -AHXaxvc --delete /media/【ユーザー名】/rootfs/ /mnt/orig/
$ umount /dev/sdb2
```

暗号化する領域に残っている古いデータを消去する。
```
# ファイルシステムを素早く消去できるが、データは削除されない（開発時用）
$ sudo wipefs -af /dev/sdb2

# 古いデータが全削除されるが時間がかかる
$ sudo shred -n 1 -v /dev/sdb2
```
rootfsをLUKSで暗号化する。
```
$ sudo cryptsetup luksFormat --type luks2 /dev/sdb2
WARNING!
========
This will overwrite data on /dev/sdb2 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdb2: (パスフレーズを入力)
パスフレーズを確認: (パスフレーズを再入力)
```

暗号化したデバイスを /dev/mapper/cryptroot にマップし、ファイルシステムを作成する。
```
$ sudo cryptsetup luksOpen /dev/sdb2 cryptroot
Enter passphrase for /dev/sdb2: (パスフレーズを入力)

$ sudo mke2fs -t ext4 /dev/mapper/cryptroot
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 3645440 4k blocks and 912128 inodes
Filesystem UUID: 7dc57e20-6732-425c-b6e4-91242f0a5a10
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done   
```

/mnt/cryptroot/にマウントし、退避したrootfsのファイルを書き込む。
```
$ sudo mkdir /mnt/cryptroot
$ sudo mount /dev/mapper/cryptroot /mnt/cryptroot/
$ sudo rsync -AHXaxv /mnt/orig/ /mnt/cryptroot/
```

ラズパイ起動時に暗号化したrootfsを開くため、fstab, crypttab, cmdline.txtを編集する。
```
$ sudo nano /mnt/cryptroot/etc/fstab
proc                  /proc           proc    defaults          0       0
PARTUUID=b2c70024-01  /boot/firmware  vfat    defaults          0       2
#下記を変更する
#PARTUUID=b2c70024-02 /               ext4    defaults,noatime  0       1  # コメントアウト
/dev/mapper/cryptroot /               ext4    defaults,noatime  0       1  # 追加

$ sudo nano /mnt/cryptroot/etc/crypttab 
# 下記を追加
# <target name> <source device>         <key file>      <options>
cryptroot       PARTUUID=e44a4b6b-02    none            luks

$ nano /media/【ユーザー名】/bootfs/cmdline.txt
#変更前
#console=serial0,115200 console=tty1 root=PARTUUID=b2c70024-02  rootfstype=ext4 fsck.repair=yes rootwait cfg80211.ieee80211_regdom=JP
#変更後(root=を変更)
console=serial0,115200 console=tty1 root=/dev/mapper/cryptroot rootfstype=ext4 fsck.repair=yes rootwait cfg80211.ieee80211_regdom=JP
```

### ■initramfsを更新する（ラズパイ）
[raspberrypi - LUKS Disk Encryption on Raspberry Pi 4 and Ubuntu Desktop 20.10 - Ask Ubuntu](https://askubuntu.com/questions/1287837/luks-disk-encryption-on-raspberry-pi-4-and-ubuntu-desktop-20-10)

microSDをUSBカードリーダーから抜去し、ラズパイに挿入する。
この時点ではinitramfsが更新されていないため、電源投入しても暗号化したパーティションのロックが解除されず、Raspberry Pi OSが起動しない。
そのため、Raspberry Pi OSの起動する前のinitramfsでロックを手動解除する。
```
(initramfs) cryptsetup luksOpen /dev/mmcblk0p2 cryptroot
パスフレーズを入力
(initramfs) exit
```

Raspberry Pi OSの起動後、initramfsを更新する。
```
$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-6.6.20+rpt-rpi-v8
'/boot/initrd.img-6.6.20+rpt-rpi-v8' -> '/boot/firmware/initramfs8'
update-initramfs: Generating /boot/initrd.img-6.6.20+rpt-rpi-2712
'/boot/initrd.img-6.6.20+rpt-rpi-2712' -> '/boot/firmware/initramfs_2712'
```

起動時にパスフレーズを要求されたらOK。
```
$ sudo reboot
```
```
$ lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
mmcblk0         179:0    0 14.4G  0 disk  
├─mmcblk0p1   179:1    0  512M  0 part  /boot/firmware
└─mmcblk0p2   179:2    0 13.9G  0 part  
  └─cryptroot 254:0    0 13.9G  0 crypt /
```


### ■キーファイルを埋め込む場合（ラズパイ）
起動時に暗号化されたパーティションのロックを自動で解除する場合は以下を実施する。
下記を参考にしました。

https://zenn.dev/masaki_wk/articles/20240609-raspi-ubuntu-lvm-on-luks

```
$ sudo nano /etc/crypttab
# noneを変更し、鍵ファイルを指定する
cryptroot       PARTUUID=e44a4b6b-02    /etc/keys/mmcblk0p2-crypt.key    luks

$ sudo mkdir /etc/keys
$ sudo chmod go-rwx /etc/keys/
$ sudo dd if=/dev/random of=/etc/keys/mmcblk0p2-crypt.key bs=1k count=4
$ sudo chmod go-rw /etc/keys/mmcblk0p2-crypt.key
$ sudo cryptsetup luksAddKey /dev/mmcblk0p2 /etc/keys/mmcblk0p2-crypt.key
Enter any existing passphrase:(パスフレーズを入力)

$ sudo nano /etc/cryptsetup-initramfs/conf-hook
KEYFILE_PATTERN="/etc/keys/*.key"

$ sudo nano /etc/initramfs-tools/initramfs.conf
UMASK=0077

$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-6.6.20+rpt-rpi-v8
'/boot/initrd.img-6.6.20+rpt-rpi-v8' -> '/boot/firmware/initramfs8'
update-initramfs: Generating /boot/initrd.img-6.6.20+rpt-rpi-2712
'/boot/initrd.img-6.6.20+rpt-rpi-2712' -> '/boot/firmware/initramfs_2712'
```

再起動時に、パスフレーズを要求されずOSが立ち上がればOK。