LUKS를 사용하여 root 영역을 암호화했다고 가정하면, OS가 부팅되기 전에 해당 영역을 언락해야 합니다.

이 과정에 항상 LUKS passphrase를 입력하는 것이 번거로운데, 본 방식을 이용하면 컴퓨터에 key가 담긴 USB가 꽂혀 있을 경우 자동으로 언락되어 부팅됩니다. (물론 이후 OS에 사용자로 로그인하는 것과는 무관합니다.)

본 글은 Ubuntu 20.04를 기준으로 합니다.

LUKS란?

디스크 암호화란 특정 저장 장치 또는 파티션 등을 암호화하여 저장 장치에 물리적으로 접근할 수 있어도 내용을을 조회할 수 없도록 하는 방법입니다.

LUKS(Linux Unified Key Setup)는 디스크 암호화 방식 중 호환성이 높고 널리 쓰이는 방식 중 한 가지 입니다.

LUKS에는 여러 암호를 등록할 수 있다는 특징이 있습니다. 실제 암호화, 복호화에 사용되는 master key는 하나이지만, 사용자는 직접 master key를 입력할 필요는 없습니다. 이 master key에 접근하도록 하는 여러 passphrase를 등록하고 passphrase를 통해 디스크를 언락할 수 있습니다.

(참고용) Ubuntu에서 LUKS 사용

컴퓨터에 LUKS를 적용하는 방식은 여러 가지가 있지만, Ubuntu 설치 도구에서 제공하는 가장 간단한 방식 한 가지만 소개하겠습니다.

이 방식은 boot 영역은 암호화하지 않고, root 영역만 암호화하여 데이터를 보호하는 방식입니다.

luks-1.png

Ubuntu 설치 도구의 Installation Type의 Advanced features를 선택하면 LVM을 이용하고 LUKS를 활성화하는 옵션이 있습니다.

luks-2.png

이후 LUKS에서 사용할 security key를 입력하게 되는데, 이 security key가 부팅 전에 입력해야 하는 LUKS passphrase가 됩니다.

luks-3.png

LUKS가 적용된 컴퓨터가 부팅되면, 위 사진과 같이 passphrase를 입력하는 창이 뜨고, 등록된 passphrase를 입력해야 root 영역이 언락되어 사용자 로그인 화면으로 넘어갑니다.

luks-4.png

LUKS가 적용된 컴퓨터의 파티션을 확인하면, /dev/nvme0n1p6이 암호화된 것을 확인할 수 있습니다.

USB key 등록

USB를 LUKS key로 사용하기 위해서는 USB에 key를 저장하고, 해당 key를 LUKS에 등록하고, 부트로더에 USB로부터 key를 가져와 LUKS 암호화를 풀도록 하는 스크립트를 추가하는 과정이 필요합니다.

우선 현재 컴퓨터의 디스크를 확인하겠습니다.

check-disk.png

/dev/nvme0n1이 OS가 저장된 디스크입니다. 이 중 /dev/nvme0n1p6이 암호화되어 있으므로, 이 영역을 언락하는 것이 필요합니다. /dev/sda가 key로 사용할 USB입니다.

이 USB는 MBR 파티션 테이블을 사용하며, ext4로 포맷되어 있습니다.

key를 저장하는 위치는 정해져있지는 않지만, 본 방법은 USB의 파일 시스템 영역과 무관한 위치에 key를 저장하여, key로 사용되는 USB임에도 불구하고 평범한 USB처럼 사용할 수 있도록 하는 방법입니다.

fdisk로 USB를 확인해보니, start sector가 2048입니다. 따라서 USB의 start sector 전의 어떤 공간에 key를 저장한다면, USB의 파일 시스템에는 아무것도 존재하지 않는 상태로도 USB를 key로 사용할 수 있습니다. (USB의 파티션 정보를 손상시키지 않기 위해 앞의 4 sector는 사용하지 않습니다.)

create-random-key.png

sudo dd if=/dev/urandom of=/dev/sda bs=512 seek=4 count=16

위 명령어로 key로 사용될 랜덤 값을 USB에 저장합니다.

check-random-key.png

sudo dd if=/dev/sda of=~/usb_secret.key bs=512 skip=4 count=16
xxd ~/usb_secret.key

USB에 저장된 key값을 ~/usb_secret.key에 저장하고 조회합니다. 이 때, 출력된 값들이 위처럼 랜덤 값들인지 확인합니다.

check-blkid.png

blkid

암호화된 장치의 UUID를 확인합니다. /dev/nvme0n1p6이 암호화된 장치였으므로, UUID는 71f22b2a-637b-4602-97cf-bfd7cc6aaac1 입니다. 또한, 대응하는 mapper 장치는 nvme0n1p6_crypt라는 것을 알 수 있습니다. (이 두 값은 추후에 사용됩니다.)

luks-add-key.png

cryptsetup luksAddKey /dev/nvme0n1p6 ~/usb_secret.key --key-slot 1

램덤으로 생성된 USB key를 LUKS에 등록해야 합니다. 대상 파티션은 /dev/nvme0n1p6이며, key 값이 저장된 파일은 ~/usb_secret.key입니다. key slot 0번에는 처음 입력한 LUKS passphrase가 저장되어 있고, USB key값은 key slot 1번에 저장합니다. (~/usb_secret.key 파일은 조회와 등록을 위해 사용되었으므로 이제 삭제해도 됩니다.)

custom-udev.png

SUBSYSTEMS=="usb", DRIVERS=="usb", SYMLINK+="usbdevice%n"

컴퓨터에 연결된 USB를 바로 이용할 수 있도록 /dev/usbdevice라는 symlink를 생성합니다. 위 내용을 /etc/udev/rules.d/99-custom-usb.rules에 저장합니다.

reload-udev.png

udevadm control --reload-rules

위 명령어를 통해 udev rule을 적용시킵니다.

open-luks-devices.png

부트 시 USB를 읽는 스크립트 생성합니다. 아래 내용을 /usr/local/sbin/openluksdevices.sh에 저장합니다.

#!/bin/sh
TRUE=0
FALSE=1

# flag tracking usb availability
OPENED=$FALSE

sleep 2

if [ -b /dev/usbdevice ]; then
# if device exists then output the keyfile from the usb 
dd if=/dev/usbdevice bs=512 skip=4 count=16 | cat
OPENED=$TRUE
fi

if [ $OPENED -ne $TRUE ]; then
echo "Failed using usb as key." >&2
/lib/cryptsetup/askpass "Try using LUKS passphrase: "
else
echo "Successfully used usb as key." >&2
fi

sleep 2
chmod a+x /usr/local/sbin/openluksdevices.sh

위 스크립트에 실행 권한을 추가합니다.

update-crypttab.png

암호화 관련 메타데이터가 저장된 /etc/crypttab을 수정합니다.

위 사진처럼 keyscript=/usr/local/sbin/openluksdevices.sh을 추가합니다.

update-cryptroot.png

/etc/initramfs-tools/conf.d/cryptroot를 생성하고, 아래 내용을 저장합니다. 이 때 위에서 확인한 암호화된 파티션과 UUID를 입력합니다.

CRYPTROOT=target=nvme0n1p6_crypt,source=/dev/disk/by-uuid/71f22b2a-637b-4602-97cf-bfd7cc6aaac1

udev-usb-key.png

커스텀 udev 규칙을 initrd에 저장하는 스크립트 /etc/initramfs-tools/hooks/udevusbkey.sh를 생성하고, 아래 내용을 저장합니다.

#!/bin/sh
PREREQ="udev"
prereqs()
{
echo "$PREREQ"
}

case $1 in
prereqs)
prereqs
exit 0
;;
esac

. /usr/share/initramfs-tools/hook-functions

# copy across relevant rules
cp /etc/udev/rules.d/99-custom-usb.rules ${DESTDIR}/lib/udev/rules.d/

exit 0
chmod a+x /etc/initramfs-tools/hooks/udevusbkey.sh

위 스크립트에 실행 권한을 추가합니다.

마지막으로 부트로더에서 생성한 스크립트들을 사용하도록 GRUB을 업데이트해야 합니다.

update-grub-config.png

/etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT를 위와 같이 수정합니다.

rootdelay=20 cryptopts=target=nvme0n1p6_crypt,source=/dev/disk/by-uuid/71f22b2a-637b-4602-97cf-bfd7cc6aaac1,keyscript=/usr/local/sbin/openluksdevices.sh

이 때도 위에서 확인한 암호화된 파티션과 UUID를 입력합니다.

update-grub

위 명령어를 통해 변경 사항을 반영합니다.

check-grub-config.png

위 사진 처럼 /boot/grub/grub.cfg 파일에 입력한 수정 사항이 반영되었는지 확인합니다.

update-initramfs.png

update-initramfs -u

부트 시 사용할 임시 파일 시스템을 생성합니다.

USB 확인

boot-with-passphrase.png

컴퓨터에 USB가 연결되지 않았을 경우, 위 사진처럼 passphrase를 요구합니다.

boot-with-usb.png

컴퓨터에 USB가 연결되었을 경우, 위 사진처럼 자동으로 언락됩니다.

usb-used-as-key.png

위에서 언급한대로 USB의 파일 시스템 영역을 건드리지 않았기 때문에, 일반 USB처럼 사용할 수 있고, 아무 파일이 존재하지 않습니다.


본 글은 https://www.howtoforge.com/tutorial/passwordless-encryption-of-linux-root-partition를 참고하여 작성되었습니다.