
LUKSを使用した、Raspberry上のKali向けフルディスク暗号化
このHOWTOは、KaliをRaspberry(または他の類似のアーキテクチャ、例:ODROID-C2)上で実行し、LUKSによるフルディスク暗号化を使用することに特化しています。少し古いドキュメントここに基づいています。
LAN環境内のRaspberry Pi(または他の類似の小型・低消費電力ハードウェア)に「使い捨てハックボックス」としてKaliを展開することは明らかに有用です。しかし、収集したデータを秘密に保つことは不可欠な要件です。ここで、必須のセキュリティ概念としてフルディスク暗号化が登場します。
まず、SDカード上にRaspberry Pi用の公式の最新Kaliイメージ(暗号化なし)をセットアップします。
推奨される方法(現在)は、nexmonパッチを適用したRaspberry Pi 3カスタムビルドを使用することです(オンボードWiFiのモニタリングおよびインジェクション機能を使用するため)。公式のkali-arm-build-scriptsリポジトリには、イメージをゼロから(Kaliディストリビューション上で)セットアップする自動ビルドスクリプトがあります。また、Kali以外のディストリビューションでも動作するパッチ版はこちらにあります(Gentooでテスト済み)。現在(2017-08)、ODROID-C2用のビルドスクリプトもそのフォークされたリポジトリにあります。
ビルドツールを入手し、rootとしてイメージをゼロからビルドします(数時間かかる場合があります):
$ git clone https://github.com/tothi/kali-arm-build-scripts
$ cd kali-arm-build-scripts
$ sudo ./rpi3-nexmon.sh 2.0
生成されるイメージは rpi3-nexmon-2.0/kali-2.0-rpi3-nexmon.img.xz です。これをSDカードにコピーします(進行状況を表示するためにpvを使用):
# pixz -d rpi3-nexmon-2.0/kali-2.0-rpi3-nexmon.img.xz - | pv -treb | dd of=/dev/mmcblk0 bs=512k
(イメージは動作するはずなので、今テストできます。)
SDカードからイメージをマウントし、chroot環境内でLUKS機能を備えたinitramfsを準備します。これを機能させるには、x86(ホスト)のqemu-arm-staticバイナリがSDカードのファイルシステム上に必要です。上記のパッチ済みrpi3-nexmon.shビルドスクリプトは、これをイメージにインストールして残すため、問題なく動作するはずです。(そうでない場合は、適切なqemu静的バイナリをイメージにコピーする必要があります。)
chroot環境を初期化します(ホストシステム上でrootとして):
# mkdir -p /mnt/chroot/boot
# mount /dev/mmcblk0p2 /mnt/chroot/
# mount /dev/mmcblk0p1 /mnt/chroot/boot/
# mount -t proc none /mnt/chroot/proc
# mount -t sysfs none /mnt/chroot/sys
# mount -o bind /dev /mnt/chroot/dev
# mount -o bind /dev/pts /mnt/chroot/dev/pts
# LANG=C chroot /mnt/chroot/
まず、rootのデフォルトパスワードを変更します:
passwd
必要なパッケージをインストールします(chroot環境内):
# apt-get update
# apt-get install busybox cryptsetup dropbear
毎回のブート時に復号キーを入力する必要があることに注意してください。できればSSH経由でリモートから入力するため、dropbear(initramfs内)が必要です。
次に、/boot/cmdline.txtを編集し、ルートデバイスをマッピングされた暗号デバイス(/dev/mapper/crypt_sdcard)に変更し、適切なcryptdeviceパラメータを追加します。
元の/boot/cmdline.txtは次のとおりです:
dwc_otg.fiq_fix_enable=2 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rootflags=noload net.ifnames=0
そして、更新されたものは次のとおりです(rootとcryptdeviceパラメータが異なります):
dwc_otg.fiq_fix_enable=2 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mapper/crypt_sdcard cryptdevice=/dev/mmcblk0p2:crypt_sdcard rootfstype=ext4 rootwait rootflags=noload net.ifnames=0
次に、次の内容で/boot/config.txtを作成します:
initramfs initramfs.gz followkernel
他のハードウェアでも同様の手順が必要なことに注意してください(ODROID-C2でブートパラメータを含むファイルは/boot/boot.iniです)。
Dropbear SSHキー認証を設定しましょう。ホストマシン上(chrootの外!)で(パスワードなしの)キーペアを作成し、公開キーを読み取ります:
$ ssh-keygen -N "" -f kali-dropbear
$ cat ./kali-dropbear.pub
公開キーを/etc/dropbear-initramfs/authorized_keysに追加します。cryptrootの設定専用にDropbear SSHアクセスを制限するため、キーの先頭に次を追加します:
command="/scripts/local-top/cryptroot && kill -9 `ps | grep -m 1 'cryptroot' | cut -d ' ' -f 3`"
パーミッションを修正します:
chmod 600 /etc/dropbear-initramfs/authorized_keys
/etc/fstabを編集します。元の内容:
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
/デバイスが/dev/mapper/crypt_sdcardに変更された更新後:
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mapper/crypt_sdcard / ext4 defaults,noatime 0 1
/etc/crypttabに次の行を追加します:
crypt_sdcard /dev/mmcblk0p2 none luks
/etc/cryptsetup-initramfs/conf-hookを変更し、次のように設定します:
CRYPTSETUP=y
initramfsイメージにcryptsetupファイルを含めます。
最後に、現在のカーネルバージョン用のinitramfsを作成し、chrootを終了します(mkinitramfs中のエラー/警告は気にしないでください):
# ls -l /lib/modules/ |awk -F" " '{print $9}'
4.4.50-v7+
# mkinitramfs -o /boot/initramfs.gz 4.4.50-v7+
uname -rはchroot内ではなくホストのカーネルバージョンを返すため、イメージを生成する際(特に他のハードウェアでは)注意が必要です。したがって、例えばODROID-C2では/boot/mkuinitrdはそのままでは機能しないため、スクリプト内のコマンドを手動で実行する必要があります(カーネルバージョンは他のハードウェアに合わせて調整してください!):
# rm /boot/initrd.img-3.14.79
# update-initramfs -c -k 3.14.79
# mkimage -A arm64 -O linux -T ramdisk -C none -a 0 -e 0 -n "uInitrd" -d /boot/initrd.img-3.14.79 /boot/uInitrd
#
chroot環境を終了します
exit
SDカード上に暗号化ボリュームを作成する(そしてすべてを削除する)前に、ファイルシステムをアンマウントし、rootfsをバックアップします:
# umount /mnt/chroot/boot
# umount /mnt/chroot/sys
# umount /mnt/chroot/proc
# mkdir -p /mnt/backup
# rsync -avh /mnt/chroot/* /mnt/backup/
chroot全体をアンマウントします:
# umount /mnt/chroot/dev/pts
# umount /mnt/chroot/dev
# umount /mnt/chroot
暗号化されていないルートパーティション(2番)を削除し、空のパーティションを作成します(SDカード全体を使用):
# echo -e "d\n2\nw" | fdisk /dev/mmcblk0
# echo -e "n\np\n2\n\n\nw" | fdisk /dev/mmcblk0
ここで、(おそらく)SDカードを抜き差しして、新しいパーティションを認識させる必要があります。
強力なパスフレーズで暗号化ボリュームを作成します(この手順で元のrootfsが破棄されます!):
# cryptsetup -v -y --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat /dev/mmcblk0p2
# cryptsetup -v luksOpen /dev/mmcblk0p2 crypt_sdcard
# mkfs.ext4 /dev/mapper/crypt_sdcard
rootfsを暗号化ボリュームに復元し、ディスクを閉じます:
# mkdir -p /mnt/encrypted
# mount /dev/mapper/crypt_sdcard /mnt/encrypted/
# rsync -avh /mnt/backup/* /mnt/encrypted/
# umount /mnt/encrypted/
# cryptsetup luksClose /dev/mapper/crypt_sdcard
# sync
SDカードを取り出し、Raspberryでテストします。
最初のブートプロセスは失敗し、busyboxにフォールバックします。次のコマンドを入力します:
# cryptsetup luksOpen /dev/mmcblk0p2 crypt_sdcard
## provide password
# exit
これでデバイスがブートするはずです。先ほど選択したパスワードでログインし、次のコマンドを実行します:
mkinitramfs -o /boot/initramfs.gz
reboot
これ以降はより見やすいプロンプトでパスフレーズが求められます。さらに、busyboxにsshで接続してパスフレーズを入力することもできます(必要に応じてカスタムのknown_hostsファイルを使用できます):
$ ssh -o "UserKnownHostsFile=~/.ssh/known_hosts.initramfs" -i ~/.ssh/kali-dropbear [email protected]
動作するようになったら、ホスト上のバックアップファイルを忘れずに削除してください:
# rm -fr /mnt/backup
# rm -fr /mnt/chroot
ブート中の完全なデバッグ出力を取得するには、cmdline.txtにdebug=1を追加できます。