luks

LUKS(Linux Unified Key Setup)为Linux硬盘加密提供了一种标准,操作简单,只有在挂载磁盘时需要输入密码,在写入和读取磁盘时不需要。 当然我们在日常的服务器运维中几乎很少会给磁盘进行加密,不过可以对U盘进行加密。

1. LUKS使用密码验证

  1. 准备一块没有格式化的磁盘

    这里我们准备了一块名为sdb的20G的磁盘

    [root@common ~]# lsblk
    NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    sda               8:0    0  100G  0 disk
    ├─sda1            8:1    0    1G  0 part /boot
    └─sda2            8:2    0   99G  0 part
      └─centos-root 253:0    0   99G  0 lvm  /
    sdb               8:16   0   20G  0 disk
    sr0              11:0    1  4.3G  0 rom
    
  2. 对磁盘进行分区,不格式化

    Note

    这里分区后不要格式化

    下面我们通过fdisk /dev/sdb 创建了一个sdb1,10G的空间,创建过程在本文中不表现

    [root@common ~]# lsblk
    NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    sda               8:0    0  100G  0 disk
    ├─sda1            8:1    0    1G  0 part /boot
    └─sda2            8:2    0   99G  0 part
      └─centos-root 253:0    0   99G  0 lvm  /
    sdb               8:16   0   20G  0 disk
    └─sdb1            8:17   0   10G  0 part
    sr0              11:0    1  4.3G  0 rom
    
  3. 利用cryptsetup对磁盘进行加密格式化

    [root@common ~]# cryptsetup luksFormat /dev/sdb1
    
    WARNING!
    ========
    This will overwrite data on /dev/sdb1 irrevocably.
    
    Are you sure? (Type uppercase yes): YES
    Enter passphrase for /dev/sdb1:
    Verify passphrase:
    
  4. 打开并自动挂载加密的磁盘

    [root@common ~]# cryptsetup luksOpen /dev/sdb1 test
    Enter passphrase for /dev/sdb1:
    [root@common ~]#
    [root@common ~]# ls /dev/mapper/
    centos-root  control  test
    
  5. 格式化映射的设备,格式化成ext4文件系统

    [root@common ~]# mkfs.ext4 /dev/mapper/test
    
  6. 挂载

    [root@common ~]# mount /dev/mapper/test /mnt/test/
    [root@common ~]#
    [root@common ~]# ls /mnt/test/
    lost+found
    [root@common ~]#
    [root@common ~]# df -TH
    Filesystem              Type      Size  Used Avail Use% Mounted on
    /dev/mapper/centos-root xfs       107G  1.2G  106G   2% /
    devtmpfs                devtmpfs  498M     0  498M   0% /dev
    tmpfs                   tmpfs     510M     0  510M   0% /dev/shm
    tmpfs                   tmpfs     510M  8.0M  502M   2% /run
    tmpfs                   tmpfs     510M     0  510M   0% /sys/fs/cgroup
    /dev/sda1               xfs       1.1G  139M  925M  14% /boot
    tmpfs                   tmpfs     102M     0  102M   0% /run/user/0
    /dev/mapper/test        ext4       11G   38M  9.9G   1% /mnt/test
    [root@common ~]# touch /mnt/test/alvin
    [root@common ~]# ll /mnt/test/alvin
    -rw-r--r--. 1 root root 0 Jan 11 14:37 /mnt/test/alvin
    [root@common ~]#
    [root@common ~]# lsblk
    NAME            MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
    sda               8:0    0  100G  0 disk
    ├─sda1            8:1    0    1G  0 part  /boot
    └─sda2            8:2    0   99G  0 part
      └─centos-root 253:0    0   99G  0 lvm   /
    sdb               8:16   0   20G  0 disk
    └─sdb1            8:17   0   10G  0 part
      └─test        253:1    0   10G  0 crypt /mnt/test
    sr0              11:0    1  4.3G  0 rom
    
  7. 使用完成后卸载,卸载挂载点test

    umount /mnt/test
    
  8. 关闭映射设备

    [root@common ~]# cryptsetup luksClose test
    [root@common ~]# ls /dev/mapper/
    

Note

上述过程中,对分区的读写操作是不会出现输入密码验证的,只有在关闭映射的设备之后再重新打开时才会要求输入密码,这时候起到了加密的作用。

Tip

另外注意luks是Linux特有的,在unix、mac、windows等操作系统下通过luks加密的磁盘是无法打开的。

2. 使用秘钥免密码验证

  1. 使用随机数生成一个密码文件,为4096位即可

    dd if=/dev/urandom of=/passwd_test bs=4096 count=1
    
  2. 对密码文件设置权限,其他人不允许读取和写入,600

    chmod 600 /passwd_test
    
  3. 用key加密对上面做的/dev/sdc1加密

    cryptsetup luksAddKey /dev/sdb1 /passwd_test
    
  4. 编辑/etc/crypttab,配置认证秘钥

    这个配置就是会将/dev/sdb1在开机的时候映射到/dev/mapper/test

    [root@common ~]# vi /etc/crypttab
    [root@common ~]# cat /etc/crypttab
    test /dev/sdb1 /passwd_test
    
  5. 编辑/etc/fstab,配置开机自动挂载

    [root@common ~]# vi /etc/fstab
    [root@common ~]# tail -1 /etc/fstab
    /dev/mapper/test /mnt/test ext4 defaults 0 0
    

    上面配置完成后,重启系统,/mnt/test会自动挂载。

手动用keyfile进行映射

cryptsetup luksOpen -d /passwd_test /dev/sdb1 test

3. 加密根分区免密进系统

加密根分区

[root@test3 ~]# lsblk
NAME                                          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                                             8:0    0   20G  0 disk
├─sda1                                          8:1    0    1G  0 part  /boot
└─sda2                                          8:2    0   19G  0 part
  └─luks-7c9f8240-a395-4541-90db-e66456aec1be 253:0    0   19G  0 crypt /

将根分区所在的加密设备,放入变量,便于后续使用

ROOT_DEVICE=/dev/sda2

Note

如果当前系统使用的是逻辑卷,比如lsblk的状态是这样的

[root@test4 ~]# lsblk
NAME                                            MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                                               8:0    0   20G  0 disk
├─sda1                                            8:1    0    1G  0 part  /boot
└─sda2                                            8:2    0   19G  0 part
  └─centos-root                                 253:0    0   19G  0 lvm
    └─luks-73585d9b-b7f6-4473-8aa3-4b380930eab8 253:1    0   19G  0 crypt /
sr0                                              11:0    1  4.3G  0 rom

那么ROOT_DEVICE=/dev/centos/root

创建key file

  1. 使用随机数生成一个密码文件,为4096位即可

    dd if=/dev/urandom of=/tmp/keyfile bs=4096 count=1
    
  2. 对密码文件设置权限,其他人不允许读取和写入,600

    chmod 600 /tmp/keyfile
    
  3. 用key加密对上面做的$ROOT_DEVICE加密

    cryptsetup luksAddKey $ROOT_DEVICE /tmp/keyfile
    

修改initramfs

创建新的initramfs,忽略systemd

因为systemd会让luks使用密码进行验证,如果不禁用的话,后续修改grub制定keyfile那些操作也不会生效。

mkdir -p initramfs
cd initramfs
dracut -o "systemd" no-systemd-initramfs.img

解压initramfs

[root@auto3 initramfs]# /usr/lib/dracut/skipcpio no-systemd-initramfs.img  | zcat | cpio -id --no-absolute-filenames
[root@auto3 initramfs]# ls
bin  dev  etc  init  lib  lib64  no-systemd-initramfs.img  proc  root  run  sbin  shutdown  sys  sysroot  tmp  usr  var
[root@auto3 initramfs]# mv no-systemd-initramfs.img ..

Note

如果上面的命令解压的时候没有解压成功,可以使用下面的命令

cpio -idmv < no-systemd-initramfs.img

添加keyfile到initramfs的根

[root@auto3 initramfs]# cp /tmp/keyfile .

注释一行包含unicode的参数,避免开机报错

这里我们注销一行内容,注销的内容是 #inst_key_val 1 /etc/vconsole.conf rd.vconsole.font.unicode vconsole.font.unicode UNICODE vconsole.unicode

如果不注销这行内容,启动系统时会报错/etc/vconsole.conf: line 1: vconsole.font.unicode=1: command not found, 虽然不影响进入系统,但没有这个报错出现会更好。

[root@auto3 initramfs]# sed -i 's/.*unicode.*/#&/' usr/lib/dracut/hooks/cmdline/20-parse-i18n.sh

设置initramfs里的etc/crypttab

uuid=`blkid $ROOT_DEVICE|awk -F 'UUID="' '{print $2}' |awk -F '"' '{print $1}'`  #根分区在$ROOT_DEVIC
echo "luks-$uuid /dev/disk/by-uuid/$uuid /keyfile" > etc/crypttab

打包新的initramfs.img

[root@auto3 initramfs]# find . | cpio -c -o > ../initrd.img

用新的initramfs.img替换旧的

[root@auto3 initramfs]# cp /boot/initramfs-3.10.0-957.el7.x86_64.img /boot/initramfs-3.10.0-957.el7.x86_64.img.bak
[root@auto3 initramfs]# \cp ../initrd.img /boot/initramfs-3.10.0-957.el7.x86_64.img

修改grub

sed -i.bak 's/crashkernel=auto/& rd.luks.key=\/keyfile/' /etc/default/grub
grub2-mkconfig >/etc/grub2.cfg

重启验证

reboot