部分VPS提供商的控制面板仅提供简单的重装系统功能,只能从其提供的有限的iso中选择安装,并且无法验证iso的完整性,或者根本不提供iso挂载功能,直接使用模板重置vps。因此我们无法安装自己所需的系统和对vps系统进行全盘加密。这篇文章简单记录一下如何在vps上挂载自定义iso安装系统并进行加密。

目的

  • 为vps安装自己所需的发行版或特定的版本,如kali等
  • luks全盘加密并提供ssh远程解密,重启后直接ssh远程输入luks密钥解密,无需登录vps控制面板操作控制台会话

适用条件

  • 使用kvm/vmware等完全虚拟化技术的vps
  • 控制面板不提供iso挂载功能或仅允许挂载其提供的iso
  • 控制面板需提供控制台会话访问

安装系统

这里以vmware虚拟机为例子来说明如何安装全盘加密的ubuntu server 16.04。我在ESXi中准备了一台相同版本ubuntu server 16.04虚拟机,没有lvm,没有luks加密:

1
2
3
4
5
6
7
8
9
10
11
$ uname -a
Linux ubuntu 4.4.0-87-generic #110-Ubuntu SMP Tue Jul 18 12:55:35 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/fstab
UUID=0041d83f-a90d-4c9e-82cf-3edf45ca6da4 / ext4 errors=remount-ro 0 1
UUID=d3c1de79-74a4-409b-b321-efaa3346ff6a none swap sw 0 0

$ mount
...
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
...

安装过程大致是在grub2中使用memdisk将ubuntu的iso载入内存,然后引导安装。对于ubuntu来说,我们使用memdisk安装的时候用常规iso的话,在安装过程中会报”Your installation CD-ROM couldn’t be mounted. This probably means that the CD-ROM was not in the drive. If so you can insert it and try again.”这个错误,因此我们要使用网络安装版(Network installer)的iso。

下载syslinux,解压,并将memdisk解压到根目录备用:

1
2
3
wget https://www.kernel.org/pub/linux/utils/boot/syslinux/6.xx/syslinux-6.03.tar.xz
tar xvJf syslinux-6.03.tar.xz
cp syslinux-6.03/bios/memdisk/memdisk /

下载ubuntu网络安装iso到根目录备用:

1
wget http://archive.ubuntu.com/ubuntu/dists/xenial-updates/main/installer-amd64/current/images/netboot/mini.iso -O /mini.iso

安装过程需要使用网络,且vps所在网络环境可能不提供DHCP服务,因此需要记录网络配置备用,包括IP地址,子网掩码,网关等。

然后为grub2添加新的引导菜单。这里为了方便,我们仅修改grub2相关参数,在启动时手动操作。修改配置文件/etc/default/grub,注释GRUB_HIDDEN_TIMEOUT行,修改GRUB_TIMEOUT数值为30,使grub2引导界面不会一闪已过,方便中断。最后运行命令update-grub使grub2参数生效。

至此,准备工作完成。重启后从vps控制面板进入控制台会话,可以发现系统停在grub2引导界面等待引导。

按c进入命令行模式,并使用以下命令引导iso:

1
2
3
4
insmod memdisk
linux16 /memdisk iso
initrd16 /mini.iso
boot

如果vps存在多个磁盘,可能会存在memdiskmini.iso不在当前磁盘的情况,则需要先使用search -f "--set-root /mini.iso"来指定root。一切正常的话,我们已经可以看到ubuntu安装界面:

安装过程和正常安装一样跟着向导一步一步操作就行。如果网络中没有DHCP服务的话会跳出手动配置网络的界面,将上面记录的网络信息填入;如果存在DHCP,但是分配的地址不能用于联网的话,在配置Hostname那一步里双击esc,选手动配置网络,然后填入网络信息。

配置过程中用户Home目录加密选No,因为我们采用lvm+luks全盘加密。选择磁盘界面,我们选择use entire disk and setup encrypted lvm

选择磁盘之后输入加密密码:

最后根据向导完成安装,记得勾选安装OpenSSH Server。

重启后会看到要求输入luks密码的界面:

输入刚设置的密码即可启动系统。至此,全盘加密的ubuntu server安装完成。

远程解密系统

全盘加密的系统,每次重启后都需要登录vps控制面板,在控制台会话里输入密码才能启动。我们可以将ssh集成到initramfs里,从而实现远程通过ssh输入密码解密系统。

在initramfs里创建root家目录与.ssh目录,并写入公钥:

1
2
mkdir -p /etc/initramfs-tools/root/.ssh/
echo "your ssh public key" >> /etc/initramfs-tools/root/.ssh/authorized_keys

安装busyboxdropbear

1
apt-get install dropbear busybox

编辑/etc/initramfs-tools/initramfs.conf,配置网络与dropbear。

配置网络连接
DEVICE=下一行加入

1
2
3
IP=IPADDR::GATEWAY:NETMASK::DEV:off
// example:
// IP=10.105.16.153::10.105.16.1:255.255.255.0::ens33:off

更改dropbear端口,添加行

1
DROPBEAR_OPTIONS="-p 2222"

这里更改dropbear端口是为了避免连接时报错Host key verification failed,因为vps系统ssh公钥和initramfs下dropbear的公钥是不一样的。

加入unlock脚本

1
2
wget https://gist.githubusercontent.com/gusennan/712d6e81f5cf9489bd9f/raw/fda73649d904ee0437fe3842227ad8ac8ca487d1/crypt_unlock.sh -O /etc/initramfs-tools/hooks/crypt_unlock.sh
chmod +x /etc/initramfs-tools/hooks/crypt_unlock.sh

最后更新initramfs

1
update-initramfs -u

重启后使用root用户通过证书认证从2222端口连接ssh,运行unlock命令,输入密码即可解密并引导系统。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ssh root@ip -p 2222
To unlock root-partition run unlock


BusyBox v1.22.1 (Ubuntu 1:1.22.0-15ubuntu1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

# unlock
Please unlock disk sda5_crypt:
/run/lvm/lvmetad.socket: connect failed: No such file or directory
WARNING: Failed to connect to lvmetad. Falling back to internal scanning.
Reading all physical volumes. This may take a while...
Found volume group "ubuntu-vg" using metadata type lvm2
/run/lvm/lvmetad.socket: connect failed: No such file or directory
WARNING: Failed to connect to lvmetad. Falling back to internal scanning.
2 logical volume(s) in volume group "ubuntu-vg" now active
cryptsetup: sda5_crypt set up successfully
Connection to ip closed.

注意事项

  • 以上操作均基于ubuntu server 16.04.3,如选择其他发行版或者其他版本,部分配置可能需要根据实际情况进行调整。
  • 系统配置完成后修改用户密码和luks密码,防止在控制台会话做了键盘记录这种极端情况下密码被窃取。操作luks密码可以使用cryptsetup命令。
  • 文中提到的全盘加密并非实际意义上的整个磁盘加密,仅指系统分区的加密,因为在启动时需要boot分区里的initramfs。
  • 由于boot分区无法进行加密,第三方可以挂载此分区并对initramfs进行篡改,加入恶意代码截取密码。因此系统配置完成后,最好记录下boot分区里initramfs的hash值,在每次手动重启前确认该文件是否被篡改。或者在意外重启后,连上initramfs的ssh后手动挂载boot分区,检查文件hash,确认无误后才输入密码进行解密。