Due to the need to work in another city, I had to buy a laptop.
Gradually, there was a problem of synchronization of his and stationary machine.
Despite the fact that all my projects are conducted in gita, not all the code is completely mine, and I don’t want to upload it to the githab.
To solve this problem, I began to build my NAS, which will give me, among other things, additional features.
After examining which OSs are currently available for solving this problem, I came to the conclusion that, of all the variety, FreeND based on FreeBSD and OpenMediaVault based on Debian, developed by one of the FreeNAS developers, are most developed, widely used and, therefore, developed.
FreeND is stable, convenient, flexible and generally good, but when I tried to install it, instead of FreeBSD bsdinstall, I saw a completely stripped installer in which I can only select disks and enter the root password: you can not even partition the disks.
GELI I liked more cryptsetup on Linux, like BSD-shny parted.
Having tried to make root on an encrypted partition, I realized that this task is nontrivial, despite the fact that they already use root on ZFS.
Then, after talking with the FreeNAS community, who began to prove that FreeNAS is not an OS, but an application, I decided to install OMV.
In addition, Debian is my main OS and with Linux things promised to be easier ...
It turned out that not quite. The task of creating such a configuration like mine is not at all trivial. Therefore, I decided to write this article.
The ZFS for Linux project guide is the main document, without which I would have to understand much longer.
His need to at least briefly look.
Having done most of the work manually, I came across a script that performs a similar task, but without organizing a mirror.
Well and, nevertheless I will mention man on cryptsetup, the Debian manual on enciphering , articles and documentation on ZFS here (there are links to original documentation).
A lot of ZFS data is on the FreeNAS forum .
And already in the process of writing this article, it turned out that nothing is new under the Moon .
However, my somewhat different scheme, and it has both its disadvantages and advantages.
The system is installed on two SSDs: Micron and Samsung PRO (in the future, I will contact them).
Each SSD has the following partitioning scheme:
part_boot
- partition with bootloader. Size = 1 GB.part_system
- the partition with the system. Size = 32 GB (Recommended size: 16 GB * 2).part_slog
- a section with SLOG. Size = 5 GB.part_system
and part_slog
encrypted in XTS mode.
In general, it looks like this:
SSD1: [part_boot] -> [ext4] <---> SSD2 SSD1: [part_system] -> [crypto_xts] -> [zfs_mirror] <---> SSD2 SSD1: [part_slog] -> [crypto_xts] -> [zfs_zil_mirror] <---> SSD2
ZIL and system root are duplicated on the second SSD using ZFS.
Further actions in a lot borrowed from the manual and given with some of my explanations.
It assumes that all commands are executed as root.
echo "deb http://ftp.debian.org/debian stretch main contrib" > /etc/apt/sources.list && apt-get update
apt-get install debootstrap linux-headers-$(uname -r) zfs-dkms
apt-get install cryptsetup
dd if=/dev/urandom bs=4M oflag=direct of=/dev/disk/by-id/ata-Samsung_SSD_850_PRO && blkdiscard /dev/disk/by-id/ata-Samsung_SSD_850_PRO
dd if=/dev/urandom bs=4M oflag=direct of=/dev/disk/by-id/ata-Micron_1100 && blkdiscard /dev/disk/by-id/ata-Micron_1100
This will take about 30 minutes for a 250 GB SSD.
A call to blkdiscard will mark all blocks on the SSD as unused.
sgdisk -a1 -n1:34:2047 -t1:EF02 -n2:0:+1G -t2:8300 /dev/disk/by-id/ata-Samsung_SSD_850_PRO
sgdisk -a1 -n1:34:2047 -t1:EF02 -n2:0:+1G -t2:8300 /dev/disk/by-id/ata-Micron_1100
This is where GRUB will be installed later.
Creating the first small section is mandatory: it will not load without it.
sgdisk -n3::+32G -t3:8300 -c3:part_system1 /dev/disk/by-id/ata-Samsung_SSD_850_PRO
sgdisk -n3::+32G -t3:8300 -c3:part_system2 /dev/disk/by-id/ata-Micron_1100
sgdisk -n4::+5G -t4:8300 -c4:part_slog1 /dev/disk/by-id/ata-Samsung_SSD_850_PRO && sgdisk -n4::+5G -t4:8300 -c4:part_slog2 /dev/disk/by-id/ata-Micron_1100
In this article, they are not used at all.
Doing this is guided by a Debian document , if you don't know cryptsetup very well.
It uses LUKS, which somewhat simplifies the work with encryption.
cryptsetup --cipher aes-xts-plain64 --key-size 512 --verify-passphrase --hash sha512 --use-random -v luksFormat /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part3
cryptsetup --cipher aes-xts-plain64 --key-size 512 --verify-passphrase --hash sha512 --use-random -v luksFormat /dev/disk/by-id/ata-Micron_1100-part3
Now you need to open the sections:
cryptsetup luksOpen /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part3 root_crypt1
cryptsetup luksOpen /dev/disk/by-id/ata-Micron_1100-part3 root_crypt2
After entering the correct password, new block devices will be created that are used for encryption.
They will house the ZFS root pool.
modprobe zfs zpool create -o ashift=12 \ -O atime=off -O canmount=off -O compression=lz4 -O normalization=formD \ -O mountpoint=/ -R /mnt \ rpool mirror /dev/disk/by-id/dm-name-root_crypt*
Now there is a pool that includes both encrypted partitions that are mirrored.
ashift
- the degree to which you need to build a two to get the specified block size.
12 is a 4K block.
The block size can be blockdev --getbsz /dev/<disk>
with the blockdev --getbsz /dev/<disk>
, or from the technical specification for the device.
If the block size does not match the size of the disk sector, there will be a performance drop.
Modern hard drives have a 4K sector size and 512 byte sector emulation.
With the exception of high-speed SAS disks of low volume (about hundreds of GB), the sector size of which remains 512 bytes.
zfs create -o canmount=off -o mountpoint=none rpool/ROOT
zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/debian
zfs mount rpool/ROOT/debian
zpool set bootfs=rpool/ROOT/debian rpool
zfs create -o setuid=off rpool/home
zfs create -o mountpoint=/root rpool/home/root
zfs create -o canmount=off -o setuid=off -o exec=off rpool/var
zfs create -o com.sun:auto-snapshot=false rpool/var/cache
zfs create rpool/var/log
zfs create rpool/var/spool
zfs create -o com.sun:auto-snapshot=false -o exec=on rpool/var/tmp
At this stage, the structure of the FS is ready.
chmod 1777 /mnt/var/tmp
debootstrap stretch /mnt && zfs set devices=off rpool
echo nas > /mnt/etc/hostname
.echo "rpool/ROOT/debian / zfs defaults,noatime 0 0" > /mnt/etc/fstab
echo "tmpfs /tmp tmpfs nosuid,nodev 0 0" >> /mnt/etc/fstab
Here / tmp is mounted as tmpfs, and / will be on ZFS.
Then you need to fix /mnt/etc/hosts
. It is required to add the host name "nas".
And add network interface settings to /mnt/etc/network/interfaces.d
(required):
ip addr show
.echo "auto $iface_name" > /mnt/etc/network/interfaces.d/$iface_name
echo "iface $iface_name inet dhcp" >> /mnt/etc/network/interfaces.d/$iface_name
This is an important point! If you do not do this, after rebooting, you will find yourself without a network and without installed packages. If you don’t, the network will have to be lifted manually.
mount --rbind /dev /mnt/dev && mount --rbind /proc /mnt/proc && mount --rbind /sys /mnt/sys
chroot /mnt /bin/bash --login
mount /tmp
Further, all the work goes on in the installed system .
apt-get install apt-transport-https
apt-get update
.apt-get install locales && dpkg-reconfigure locales
dpkg-reconfigure tzdata
apt-get install bash-completion man gdisk linux-headers-$(uname -r) linux-image-amd64
apt-get install cryptsetup zfs-dkms zfs-initramfs
Building the ZFS module will take considerable time.
Definitely include in initramfs:sed -i 's/#CRYPTSETUP=/CRYPTSETUP=y/' /etc/cryptsetup-initramfs/conf-hook
Then, fix the cryptroot hook in / usr / share / initramfs-tools / hooks / cryptroot and replace the script in / etc / initrmafs-tools / scripts / local-top / cryptroot.
There are two problems with the cryptsetup package in Debian Stretch:
The bug on ZFS has been started for a long time, my improvements have been sent there.
I got a bug on the password caching and sent a fix, so maybe it will already be fixed.
However, I provide full scripts and diffs:
#!/bin/sh PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac . /usr/share/initramfs-tools/hook-functions # get_fs_devices() - determine source device(s) of mount point from /etc/fstab # # expected arguments: # * fstab mount point (full path) # # This function searches for the first entry from /etc/fstab which has the # given mountpoint set. It returns the canonical_device() of corresponding # source device (first field in /etc/fstab entry). # In case of btrfs, canoncial_device() of all btrfs source devices (possibly # more than one) are returned. # get_fs_devices() { local device mount type options dump pass local wantmount="$1" if [ ! -r /etc/fstab ]; then return 1 fi grep -s '^[^#]' /etc/fstab | \ while read device mount type options dump pass; do if [ "$mount" = "$wantmount" ]; then local devices if [ "$type" = "btrfs" ]; then for dev in $(btrfs filesystem show $(canonical_device "$device" --no-simplify) 2>/dev/null | sed -r -e 's/.*devid .+ path (.+)/\1/;tx;d;:x') ; do devices="${devices:+$devices }$(canonical_device "$dev")" done elif [ "$type" = "zfs" ]; then zpool="$(echo "$device"|sed 's#^/dev/zvol/##;s#\([^/]*\).*#\1#')" for ss in $(zpool list -Pv "$zpool"); do cdev=$(canonical_device "$ss" 2>/dev/null) || continue devices="${devices:+$devices }$cdev" done || return 0 else devices=$(canonical_device "$device") || return 0 fi printf '%s' "$devices" return fi done } # get_resume_devices() - determine devices used for system suspend/hibernate # # expected arguments: # * none # # This function searches well known places for devices that are used for system # suspension and/or hibernation. It returns canonical_device() of any detected # devices and prints a warning if more than one device is detected. # get_resume_devices() { local device opt count dupe candidates devices derived candidates="" # First, get a list of potential resume devices # uswsusp if [ -e /etc/uswsusp.conf ]; then device=$(sed -rn 's/^resume device[[:space:]]*[:=][[:space:]]*// p' /etc/uswsusp.conf) if [ -n "$device" ]; then candidates="${candidates:+$candidates }$device" fi fi # uswsusp - again... if [ -e /etc/suspend.conf ]; then device=$(sed -rn 's/^resume device[[:space:]]*[:=][[:space:]]*// p' /etc/suspend.conf) if [ -n "$device" ]; then candidates="${candidates:+$candidates }$device" fi fi # regular swsusp for opt in $(cat /proc/cmdline); do case $opt in resume=*) device="${opt#resume=}" candidates="${candidates:+$candidates }$device" ;; esac done # initramfs-tools >=0.129 device="${RESUME:-auto}" if [ "$device" != none ]; then if [ "$device" = auto ]; then # next line from /usr/share/initramfs-tools/hooks/resume device="$(grep ^/dev/ /proc/swaps | sort -rnk3 | head -n 1 | cut -d " " -f 1)" if [ -n "$device" ]; then device="UUID=$(blkid -s UUID -o value "$device" || true)" fi fi candidates="${candidates:+$candidates }$device" fi # Now check the sanity of all candidates devices="" count=0 for device in $candidates; do # Remove quotes around device candidate device=$(printf '%s' "$device" | sed -r -e 's/^"(.*)"\s*$/\1/' -e "s/^'(.*)'\s*$/\1/") # Weed out clever defaults if [ "$device" = "<path_to_resume_device_file>" ]; then continue fi # Detect devices required by decrypt_derived derived=$(get_derived_device "$device") if [ -n "$derived" ]; then devices="${devices:+$devices }$derived" fi device=$(canonical_device "$device") || return 0 # Weed out duplicates dupe=0 for opt in $devices; do if [ "$device" = "$opt" ]; then dupe=1 fi done if [ $dupe -eq 1 ]; then continue fi # This device seems ok devices="${devices:+$devices }$device" count=$(( $count + 1 )) done if [ $count -gt 1 ]; then echo "cryptsetup: WARNING: found more than one resume device candidate:" >&2 for device in $devices; do echo " $device" >&2 done fi if [ $count -gt 0 ]; then printf '%s' "$devices" fi return 0 } # get_initramfs_devices() - determine devices with explicit 'initramfs' option # # expected arguments: # * none # # This function processes entries from /etc/crypttab with the 'initramfs' # option set. For each processed device, potential get_derived_device() # devices are determined. The canonical_device() of each detected device # is returned. # get_initramfs_devices() { local device opt count dupe target source key options candidates devices derived candidates="$(grep -s '^[^#]' /etc/crypttab | \ while read target source key options; do if printf '%s' "$options" | grep -Eq "^(.*,)?initramfs(,.*)?$"; then echo " /dev/mapper/$target" fi done;)" devices="" count=0 for device in $candidates; do # Detect devices required by decrypt_derived derived=$(get_derived_device "$device") if [ -n "$derived" ]; then devices="${devices:+$devices }$derived" fi device=$(canonical_device "$device") || return 0 # Weed out duplicates dupe=0 for opt in $devices; do if [ "$device" = "$opt" ]; then dupe=1 fi done if [ $dupe -eq 1 ]; then continue fi # This device seems ok devices="${devices:+$devices }$device" count=$(( $count + 1 )) done if [ $count -gt 0 ]; then printf '%s' "$devices" fi return 0 } # get_derived_device() - determine dependency devices for decrypt_derived # # expected arguments: # * crypttab target device name (either <name> or /dev/mapper/<name>) # # This function takes a target device name and checks whether this device has # the decrypt_derived keyscript set in /etc/crypttab. If true, the dependency # device required for the decrypt_derived keyscript is detected and its # canonical_device() returned if it's not listed in $rootdevs. # get_derived_device() { local device derived device="$1" derived="$( awk -vtarget="${device#/dev/mapper/}" \ '$1 == target && $4 ~ /^(.*,)?keyscript=([^,]*\/)?decrypt_derived(,.*)?$/ {print $3; exit}' \ /etc/crypttab )" if [ -n "$derived" ]; then if node_is_in_crypttab "$derived"; then derived=$(canonical_device "/dev/mapper/$derived") || return 0 if ! printf '%s' "$rootdevs" | tr ' ' '\n' | grep -Fxq "$derived"; then printf '%s' "$derived" fi else echo "cryptsetup: WARNING: decrypt_derived device $derived not found in crypttab" >&2 fi fi } # node_is_in_crypttab() - test whether a device is configured in /etc/crypttab # # expected arguments: # * crypttab target device names (without /dev/mapper/ prefix) # # This function takes a target device name and fails if it is not # configured in /etc/crypttab. # node_is_in_crypttab() { [ -f /etc/crypttab ] || return 1 sed -n '/^[^#]/ s/\s.*//p' /etc/crypttab | grep -Fxq "$1" } # node_or_pv_is_in_crypttab() - test whether devices are configured in /etc/crypttab # # expected arguments: # * crypttab target device names (without /dev/mapper/ prefix), or LVM # logical volume device-mapper name (format <VG>-<LV>) # # This function fails unless every argument is either a target device # name configured in /etc/crypttab, or an LVM logical volume # device-mapper name (format <VG>-<LV>) with only parents devices (PVs) # configured in /etc/crypttab. # node_or_pv_is_in_crypttab() { local node lvmnodes lvmnode for node in "$@"; do if ! node_is_in_crypttab "$node"; then lvmnodes="$(get_lvm_deps "$node" --assert-crypt)" || return 1 [ "$lvmnodes" ] || return 1 for lvmnode in $lvmnodes; do node_is_in_crypttab "$lvmnode" || return 1 done fi done return 0 } # get_lvm_deps() - determine the parent devices (PVs) of a LVM logical volume # # expected arguments: # * LVM logical volume device-mapper name (format <VG>-<LV>) # * optional options to the function # # This function takes a LVM logical volume name and determines the corresponding # crypted physical volumes (PVs). It returns the name of the underlying # device-mapper crypt devices (without /dev/mapper). # If option '--assert-crypt' is given as second argument, then the # function fails unless all PVs are dm-crypt devices. # get_lvm_deps() { local node opt deps maj min depnode node="$1" opt="${2:-}" if [ -z "$node" ]; then echo "cryptsetup: WARNING: get_lvm_deps - invalid arguments" >&2 return 1 fi if ! deps=$(vgs --noheadings -o pv_name $(dmsetup --noheadings splitname $node | cut -d':' -f1) 2>/dev/null); then # $node is not a LVM node, stopping here [ "$opt" != '--assert-crypt' ] && return 0 || return 1 fi # We should now have a list of physical volumes for the VG for dep in $deps; do depnode=$(dmsetup info -c --noheadings -o name "$dep" 2>/dev/null) if [ -z "$depnode" ]; then [ "$opt" != '--assert-crypt' ] && continue || return 1 fi if [ "$(dmsetup table "$depnode" 2>/dev/null | cut -d' ' -f3)" != "crypt" ]; then get_lvm_deps "$depnode" $opt || return 1 continue fi printf '%s\n' "$depnode" done return 0 } # get_device_opts() - determine and set options for a crypttab target device # # expected arguments: # * crypttab target device name (without /dev/mapper/ prefix) # * optional extra options # # This function determines options for a crypttab target device and sets them # accordingly. In order to detect the options, it parses the corresponding # /etc/crypttab entry and takes optional extra options as second argument. # Some sanity checks are done on the corresponding source device and configured # options. # After everything is processed, the options are saved in '$OPTIONS' for later # access by parent functions. # get_device_opts() { local target source link extraopts rootopts opt key target="$1" extraopts="$2" KEYSCRIPT="" KEYFILE="" # key file to copy to the initramfs image CRYPTHEADER="" OPTIONS="" if [ -z "$target" ]; then echo "cryptsetup: WARNING: get_device_opts - invalid arguments" >&2 return 1 fi opt="$( awk -vtarget="$target" '$1 == target {gsub(/[ \t]+/," "); print; exit}' /etc/crypttab )" source=$( printf '%s' "$opt" | cut -d " " -f2 ) key=$( printf '%s' "$opt" | cut -d " " -f3 ) rootopts=$( printf '%s' "$opt" | cut -d " " -f4- ) if [ -z "$opt" ] || [ -z "$source" ] || [ -z "$key" ] || [ -z "$rootopts" ]; then echo "cryptsetup: WARNING: invalid line in /etc/crypttab for $target - $opt" >&2 return 1 fi # Sanity checks for $source if [ -h "$source" ]; then link=$(readlink -nqe "$source") if [ -z "$link" ]; then echo "cryptsetup: WARNING: $source is a dangling symlink" >&2 return 1 fi if [ "$link" != "${link#/dev/mapper/}" ]; then echo "cryptsetup: NOTE: using $link instead of $source for $target" >&2 source="$link" fi fi if [ "UUID=${source#UUID=}" = "$source" -a ! \( -b "/dev/disk/by-uuid/${source#UUID=}" -o -b "/dev/disk/by-partuuid/${source#UUID=}" \) ] || [ "UUID=${source#UUID=}" != "$source" -a ! -b "$source" ]; then echo "cryptsetup: WARNING: Invalid source device $source" >&2 fi # Sanity checks for $key if [ "$key" = "/dev/random" ] || [ "$key" = "/dev/urandom" ]; then echo "cryptsetup: WARNING: target $target has a random key, skipped" >&2 return 1 fi if [ -n "$extraopts" ]; then rootopts="$extraopts,$rootopts" fi # We have all the basic options, let's go trough them OPTIONS="target=$target,source=$source" local IFS_BCK="$IFS" local IFS=", " unset HASH_FOUND unset LUKS_FOUND for opt in $rootopts; do case $opt in cipher=*) OPTIONS="$OPTIONS,$opt" ;; size=*) OPTIONS="$OPTIONS,$opt" ;; hash=*) OPTIONS="$OPTIONS,$opt" HASH_FOUND=1 ;; tries=*) OPTIONS="$OPTIONS,$opt" ;; discard) OPTIONS="$OPTIONS,$opt" ;; luks) LUKS_FOUND=1 ;; header=*) opt="${opt#header=}" if [ ! -e "$opt" ]; then echo "cryptsetup: WARNING: target $target has an invalid header, skipped" >&2 return 1 fi CRYPTHEADER="$opt" OPTIONS="$OPTIONS,header=$CRYPTHEADER" ;; tcrypt) OPTIONS="$OPTIONS,$opt" ;; keyscript=*) opt="${opt#keyscript=}" if [ ! -x "/lib/cryptsetup/scripts/$opt" ] && [ ! -x "$opt" ]; then echo "cryptsetup: WARNING: target $target has an invalid keyscript, skipped" >&2 return 1 fi KEYSCRIPT="$opt" OPTIONS="$OPTIONS,keyscript=/lib/cryptsetup/scripts/$(basename "$opt")" ;; keyslot=*) OPTIONS="$OPTIONS,$opt" ;; veracrypt) OPTIONS="$OPTIONS,$opt" ;; lvm=*) OPTIONS="$OPTIONS,$opt" ;; rootdev) OPTIONS="$OPTIONS,$opt" ;; resumedev) OPTIONS="$OPTIONS,$opt" ;; *) # Presumably a non-supported option ;; esac done IFS="$IFS_BCK" # Warn for missing hash option, unless we have a LUKS partition if [ -z "$HASH_FOUND" ] && [ -z "$LUKS_FOUND" ]; then echo "WARNING: Option hash missing in crypttab for target $target, assuming ripemd160." >&2 echo " If this is wrong, this initramfs image will not boot." >&2 echo " Please read /usr/share/doc/cryptsetup/README.initramfs.gz and add" >&2 echo " the correct hash option to your /etc/crypttab." >&2 fi # Warn that header only applies to a LUKS partition currently if [ -n "$CRYPTHEADER" ] && [ -z "$LUKS_FOUND" ]; then echo "WARNING: Option LUKS missing in crypttab for target $target." >&2 echo " Headers are only supported for LUKS devices." >&2 fi # If keyscript is set, the "key" is just an argument to the script if [ "$key" != "none" ] && [ -z "$KEYSCRIPT" ]; then case "$key" in $KEYFILE_PATTERN) KEYFILE="$key" key="/cryptroot-keyfiles/${target}.key" ;; *) key=$(readlink -e "$key") # test whether $target is a root device (or parent of the root device) if printf '%s' "$OPTIONS" | grep -Eq '^(.*,)?rootdev(,.*)?$'; then echo "cryptsetup: WARNING: root target $target uses a key file, skipped" >&2 return 1 # test whether a) key file is not on root fs # or b) root fs is not encrypted elif [ "$(stat -c %m -- "$key" 2>/dev/null)" != / ] || ! node_or_pv_is_in_crypttab $rootdevs; then echo "cryptsetup: WARNING: $target's key file $key is not on an encrypted root FS, skipped" >&2 return 1 fi if printf '%s' "$OPTIONS" | grep -Eq '^(.*,)?resumedev(,.*)?$'; then # we'll be able to decrypt the device, but won't be able to use it for resuming echo "cryptsetup: WARNING: resume device $source uses a key file" >&2 fi # prepend "/root" (to be substituted by the real root FS # mountpoint "$rootmnt" in the boot script) to the # absolute filename key="/root$key" ;; esac OPTIONS="$OPTIONS,keyscript=cat" fi OPTIONS="$OPTIONS,key=$key" } # get_device_modules() - determine required crypto kernel modules for device # # expected arguments: # * crypttab target device name (without /dev/mapper/ prefix) # # This function determines the required crypto kernel modules for cipher, # block cipher and optionally ivhash of the target device and returns them. # get_device_modules() { local node value cipher blockcipher ivhash node="$1" # Check the ciphers used by the active root mapping value=$(dmsetup table "$node" | cut -d " " -f4) cipher=$(echo "$value" | cut -d ":" -f1 | cut -d "-" -f1) blockcipher=$(echo "$value" | cut -d ":" -f1 | cut -d "-" -f2) ivhash=$(echo "$value" | cut -d ":" -s -f2) if [ -n "$cipher" ]; then echo "$cipher" else return 1 fi if [ -n "$blockcipher" ] && [ "$blockcipher" != "plain" ]; then echo "$blockcipher" fi if [ -n "$ivhash" ] && [ "$ivhash" != "plain" ]; then echo "$ivhash" fi return 0 } # canonical_device() - determine the # # expected arguments: # * device (either full path or LABEL=<x> or UUID=<y>) # * optional options to the function # # This function takes a device as argument and determines the corresponding # canonical device name. # If option '--no-simplify' is given as second argument, then the origin device # path after unraveling LABEL= and UUID= format and following symlinks is # returned. # If no option is given, the device is further unraveled and depending on the # device path, either the corresponding device-mapper path (as found in # /dev/mapper/) or the the corresponding disk symlink (as found in # /dev/disk/by-*/) is returned. # canonical_device() { local dev altdev original dev="$1" opt="$2" if [ "${dev#LABEL=}" != "$dev" ]; then altdev="${dev#LABEL=}" dev="/dev/disk/by-label/$(printf '%s' "$altdev" | sed 's,/,\\x2f,g')" elif [ "${dev#UUID=}" != "$dev" ]; then altdev="${dev#UUID=}" dev="/dev/disk/by-uuid/$altdev" fi original="$dev" if [ -h "$dev" ]; then dev=$(readlink -e "$dev") fi if [ "$opt" = "--no-simplify" ]; then printf '%s' "$dev" return 0 fi if [ "x${dev%/dev/dm-*}" = "x" ]; then # try to detect corresponding symlink in /dev/mapper/ for dmdev in /dev/mapper/*; do if [ "$(readlink -e "$dmdev")" = "$dev" ]; then dev="$dmdev" fi done fi altdev="${dev#/dev/mapper/}" if [ "$altdev" != "$dev" ]; then printf '%s' "$altdev" return 0 elif [ "x${original%/dev/disk/by-*/*}" = "x" ]; then # support crypttab UUID/LABEL entries # this is a /dev/disk/by-*/ path so return just the 'basename' echo "${original##/dev/disk/by-*/}" return 0 fi echo "cryptsetup: WARNING: failed to detect canonical device of $original" >&2 return 1 } # add_device() - Process a given device and add to /conf/conf.d/cryptroot # # expected arguments: # * device name (either crypttab target device name without /dev/mapper/ prefix # or LVM device-mapper name in format '<VG>:<LV>') # # This function takes a device name, does all required processing and adds the # result with all device options to /conf/conf.d/cryptroot in the initramfs. # Additionally, it returns required kernel modules. # add_device() { local node nodes lvmnodes opts lastopts i count nodes="$1" opts="" # Applied to all nodes lastopts="" # Applied to last node if [ -z "$nodes" ]; then return 0 fi # Flag root and resume devices if printf '%s' "$rootdevs" | tr ' ' '\n' | grep -Fxq "$nodes"; then opts="${opts:+$opts,}rootdev" fi if printf '%s' "$resumedevs" | tr ' ' '\n' | grep -Fxq "$nodes"; then opts="${opts:+$opts,}resumedev" fi # Check that it is a node under /dev/mapper/ # nodes=$(canonical_device "$nodes") || return 0 # Can we find this node in crypttab if ! node_is_in_crypttab "$nodes"; then # dm node but not in crypttab, is it a lvm device backed by dm-crypt nodes? lvmnodes=$(get_lvm_deps "$nodes") || return 1 # not backed by any dm-crypt nodes; stop here if [ -z "$lvmnodes" ]; then return 0 fi # It is a lvm device! opts="${opts:+$opts,}lvm=$nodes" nodes="$lvmnodes" fi # Prepare to setup each node count=$(printf '%s' "$nodes" | wc -w) i=1 for node in $nodes; do # Prepare the additional options if [ $i -eq $count ]; then if [ -n "$lastopts" ]; then opts="${opts:+$opts,}$lastopts" fi fi # Get crypttab root options if ! get_device_opts "$node" "$opts"; then continue fi printf '%s\n' "$OPTIONS" >>"$DESTDIR/conf/conf.d/cryptroot" # If we have a keyscript, make sure it is included if [ -n "$KEYSCRIPT" ]; then if [ ! -d "$DESTDIR/lib/cryptsetup/scripts" ]; then mkdir -p "$DESTDIR/lib/cryptsetup/scripts" fi if [ -e "/lib/cryptsetup/scripts/$KEYSCRIPT" ]; then copy_exec "/lib/cryptsetup/scripts/$KEYSCRIPT" /lib/cryptsetup/scripts >&2 elif [ -e "$KEYSCRIPT" ]; then copy_exec "$KEYSCRIPT" /lib/cryptsetup/scripts >&2 elif KSTYPE="$(type "$KEYSCRIPT" 2>&1)"; then if [ -x "${KSTYPE#"$KEYSCRIPT" is }" ]; then copy_exec "${KSTYPE#"$KEYSCRIPT" is }" /lib/cryptsetup/scripts >&2 fi else echo "cryptsetup: WARNING: failed to find keyscript $KEYSCRIPT" >&2 continue fi elif [ -n "$KEYFILE" ]; then case "$KEYFILE" in $KEYFILE_PATTERN) mkdir -pm0700 "$DESTDIR/cryptroot-keyfiles" cp --preserve=all "$KEYFILE" "$DESTDIR/cryptroot-keyfiles/${node}.key" ;; esac fi # If we have a LUKS header, make sure it is included # TODO: make it configurable to include the LUKS header into initramfs # disabled for now due to security reasons if [ -n "$CRYPTHEADER" ]; then if [ ! -d "$DESTDIR/conf/conf.d/cryptheader" ]; then mkdir -p "$DESTDIR/conf/conf.d/cryptheader" fi #if [ -e "$CONFDIR/conf.d/cryptheader/$CRYPTHEADER" ]; then # copy_exec "$CONFDIR/conf.d/cryptheader/$CRYPTHEADER" /conf/conf.d/cryptheader >&2 #elif [ -e "$CRYPTHEADER" ]; then # copy_exec "$CRYPTHEADER" /conf/conf.d/cryptheader >&2 #else # echo "cryptsetup: WARNING: failed to find LUKS header $CRYPTHEADER" >&2 # continue #fi fi # Calculate needed modules modules=$(get_device_modules $node | sort | uniq) if [ -z "$modules" ]; then echo "cryptsetup: WARNING: failed to determine cipher modules to load for $node" >&2 continue fi echo dm_mod echo dm_crypt echo "$modules" # Load hardware aes module if cpu_has_aesni; then echo aesni fi i=$(( $i + 1 )) done return 0 } # cpu_has_aesni() - Detect whether the host CPU has AES-NI support # # expected arguments: # * none # # This functions returns true when the host CPU has AES-NI support. # cpu_has_aesni() { return $(grep -q "^flags\s*:\s*.*aes" /proc/cpuinfo) } # add_crypto_modules() - determine kernel module path and add to initramfs # # expected arguments: # * kernel module name # # This function takes a kernel module name, determines the corresponding path # and runs manual_add_modules() from initramfs hook functions to add the module # to the initramfs. # add_crypto_modules() { local mod file altmod found genericfound mod="$1" found="" genericfound="" if [ -z "$mod" ]; then return 1 fi # We have several potential sources of modules (in order of preference): # # a) /lib/modules/$VERSION/kernel/arch/$ARCH/crypto/$mod-$specific.ko # b) /lib/modules/$VERSION/kernel/crypto/$mod_generic.ko # c) /lib/modules/$VERSION/kernel/crypto/$mod.ko # # and (currently ignored): # # d) /lib/modules/$VERSION/kernel/drivers/crypto/$specific-$mod.ko for file in $(find "$MODULESDIR/kernel/arch/" -name "$mod-*.ko" 2>/dev/null); do altmod="${file##*/}" altmod="${altmod%.ko}" manual_add_modules "$altmod" found="yes" done for file in $(find "$MODULESDIR/kernel/crypto/" -name "${mod}_generic.ko" 2>/dev/null); do altmod="${file##*/}" altmod="${altmod%.ko}" manual_add_modules "$altmod" found="yes" genericfound="yes" done if [ -z "$genericfound" ]; then for file in $(find "$MODULESDIR/kernel/crypto/" -name "${mod}.ko" 2>/dev/null); do altmod="${file##*/}" altmod="${altmod%.ko}" manual_add_modules "$altmod" found="yes" done fi if [ -z "$found" ]; then return 1 fi return 0 } # # Begin real processing # setup="no" rootdevs="" usrdevs="" resumedevs="" # XXX Backward compatibility: remove once Stretch has been promoted stable for v in CRYPTSETUP KEYFILE_PATTERN; do if eval [ "\${$v+x}" ]; then echo "WARNING: Setting $v in /etc/initramfs-tools/initramfs.conf" \ "is deprecated and will stop working in the future." \ "Use /etc/cryptsetup-initramfs/conf-hook instead." >&2 fi done # Load the hook's config if [ -f "/etc/cryptsetup-initramfs/conf-hook" ]; then . /etc/cryptsetup-initramfs/conf-hook fi # Include cryptsetup modules, regardless of _this_ machine configuration if [ -n "$CRYPTSETUP" ] && [ "$CRYPTSETUP" != "n" ]; then setup="yes" fi if [ "$KEYFILE_PATTERN" ]; then setup="yes" case "${UMASK:-$(umask)}" in 0[0-7]77) ;; *) echo "WARNING: permissive UMASK (${UMASK:-$(umask)})." \ "Private key material inside the initrd might be left unprotected." >&2 ;; esac fi # Find the root and resume device(s) if [ -r /etc/crypttab ]; then rootdevs=$(get_fs_devices /) if [ -z "$rootdevs" ]; then echo "cryptsetup: WARNING: could not determine root device from /etc/fstab" >&2 fi usrdevs=$(get_fs_devices /usr) resumedevs=$(get_resume_devices) initramfsdevs=$(get_initramfs_devices) fi # Load the config opts and modules for each device for dev in $rootdevs $usrdevs $resumedevs $initramfsdevs; do if ! modules=$(add_device "$dev"); then echo "cryptsetup: FAILURE: could not determine configuration for $dev" >&2 continue fi if [ -n "$modules" ]; then setup="yes" fi if [ "$setup" = "no" ]; then continue fi if [ "$MODULES" = "most" ]; then archcrypto="$(find "$MODULESDIR/kernel/arch" -type d -name "crypto" 2>/dev/null)" if [ -n "$archcrypto" ]; then copy_modules_dir "${archcrypto##*${MODULESDIR}/}" fi copy_modules_dir "kernel/crypto" else for mod in $modules; do add_crypto_modules $mod done fi done # With large initramfs, we always add a basic subset of modules if [ "$MODULES" != "dep" ] && [ "$setup" = "yes" ]; then for mod in aes cbc chainiv cryptomgr krng sha256 xts; do add_crypto_modules $mod done fi # See if we need to add the basic components if [ "$setup" = "yes" ]; then for mod in dm_mod dm_crypt; do manual_add_modules $mod done copy_exec /sbin/cryptsetup copy_exec /sbin/dmsetup copy_exec /lib/cryptsetup/askpass # We need sed. Either via busybox or as standalone binary. if [ "$BUSYBOX" = "n" ] || [ ! -e ${BUSYBOXDIR}/busybox ]; then copy_exec /bin/sed fi fi exit 0
45a46,51 > elif [ "$type" = "zfs" ]; then > zpool="$(echo "$device"|sed 's#^/dev/zvol/##;s#\([^/]*\).*#\1#')" > for ss in $(zpool list -Pv "$zpool"); do > cdev=$(canonical_device "$ss" 2>/dev/null) || continue > devices="${devices:+$devices }$cdev" > done || return 0 375c381 < if [ "UUID=${source#UUID=}" = "$source" -a ! -b "/dev/disk/by-uuid/${source#UUID=}" ] || [ "UUID=${source#UUID=}" != "$source" -a ! -b "$source" ]; then --- > if [ "UUID=${source#UUID=}" = "$source" -a ! \( -b "/dev/disk/by-uuid/${source#UUID=}" -o -b "/dev/disk/by-partuuid/${source#UUID=}" \) ] || [ "UUID=${source#UUID=}" != "$source" -a ! -b "$source" ]; then
#!/bin/sh PREREQ="cryptroot-prepare" # # Standard initramfs preamble # prereqs() { # Make sure that cryptroot is run last in local-top for req in $(dirname $0)/*; do script=${req##*/} if [ $script != cryptroot ]; then echo $script fi done } case $1 in prereqs) prereqs exit 0 ;; esac # source for log_*_msg() functions, see LP: #272301 . /scripts/functions # # Helper functions # message() { if [ -x /bin/plymouth ] && plymouth --ping; then plymouth message --text="$@" elif [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then usplash_write "TEXT-URGENT $@" else echo "$@" >&2 fi return 0 } udev_settle() { # Wait for udev to be ready, see https://launchpad.net/bugs/85640 if command -v udevadm >/dev/null 2>&1; then udevadm settle --timeout=30 elif command -v udevsettle >/dev/null 2>&1; then udevsettle --timeout=30 fi return 0 } parse_options() { local cryptopts cryptopts="$1" if [ -z "$cryptopts" ]; then return 1 fi # Defaults cryptcipher=aes-cbc-essiv:sha256 cryptsize=256 crypthash=ripemd160 crypttarget=cryptroot cryptsource="" cryptheader="" cryptlvm="" cryptkeyscript="" cryptkey="" # This is only used as an argument to an eventual keyscript cryptkeyslot="" crypttries=3 crypttcrypt="" cryptveracrypt="" cryptrootdev="" cryptdiscard="" CRYPTTAB_OPTIONS="" local IFS=" ," for x in $cryptopts; do case $x in hash=*) crypthash=${x#hash=} ;; size=*) cryptsize=${x#size=} ;; cipher=*) cryptcipher=${x#cipher=} ;; target=*) crypttarget=${x#target=} export CRYPTTAB_NAME="$crypttarget" ;; source=*) cryptsource=${x#source=} if [ ${cryptsource#UUID=} != $cryptsource ]; then cryptsource="/dev/disk/by-uuid/${cryptsource#UUID=}" elif [ ${cryptsource#LABEL=} != $cryptsource ]; then cryptsource="/dev/disk/by-label/$(printf '%s' "${cryptsource#LABEL=}" | sed 's,/,\\x2f,g')" elif [ ${cryptsource#ID=} != $cryptsource ]; then cryptsource="/dev/disk/by-id/${cryptsource#ID=}" fi export CRYPTTAB_SOURCE="$cryptsource" ;; header=*) cryptheader=${x#header=} if [ ! -e "$cryptheader" ] && [ -e "/conf/conf.d/cryptheader/$cryptheader" ]; then cryptheader="/conf/conf.d/cryptheader/$cryptheader" fi export CRYPTTAB_HEADER="$cryptheader" ;; lvm=*) cryptlvm=${x#lvm=} ;; keyscript=*) cryptkeyscript=${x#keyscript=} ;; key=*) if [ "${x#key=}" != "none" ]; then cryptkey=${x#key=} fi export CRYPTTAB_KEY="$cryptkey" ;; keyslot=*) cryptkeyslot=${x#keyslot=} ;; tries=*) crypttries="${x#tries=}" case "$crypttries" in *[![:digit:].]*) crypttries=3 ;; esac ;; tcrypt) crypttcrypt="yes" ;; veracrypt) cryptveracrypt="--veracrypt" ;; rootdev) cryptrootdev="yes" ;; discard) cryptdiscard="yes" ;; esac PARAM="${x%=*}" if [ "$PARAM" = "$x" ]; then VALUE="yes" else VALUE="${x#*=}" fi CRYPTTAB_OPTIONS="$CRYPTTAB_OPTIONS $PARAM" eval export CRYPTTAB_OPTION_$PARAM="\"$VALUE\"" done export CRYPTTAB_OPTIONS if [ -z "$cryptsource" ]; then message "cryptsetup ($crypttarget): source parameter missing" return 1 fi return 0 } activate_vg() { # Sanity checks if [ ! -x /sbin/lvm ]; then message "cryptsetup ($crypttarget): lvm is not available" return 1 fi # Detect and activate available volume groups /sbin/lvm vgscan /sbin/lvm vgchange -ay --sysinit return $? } setup_mapping() { local opts count cryptopen cryptremove NEWROOT is_luks opts="$1" is_luks=0 if [ -z "$opts" ]; then return 0 fi parse_options "$opts" || return 1 if [ -z "$cryptkeyscript" ]; then if [ ${cryptsource#/dev/disk/by-uuid/} != $cryptsource ]; then # UUIDs are not very helpful diskname="$crypttarget" else diskname="$cryptsource ($crypttarget)" fi cryptkeyscript="/lib/cryptsetup/askpass" cryptkey="1Please unlock disk $diskname: " elif ! type "$cryptkeyscript" >/dev/null; then message "cryptsetup ($crypttarget): error - script \"$cryptkeyscript\" missing" return 1 fi if [ "$cryptkeyscript" = "cat" ] && [ "${cryptkey#/root/}" != "$cryptkey" ]; then # skip the mapping if the root FS is not mounted yet sed -rn 's/^\s*[^#]\S*\s+(\S+)\s.*/\1/p' /proc/mounts | grep -Fxq "$rootmnt" || return 1 # substitute the "/root" prefix by the real root FS mountpoint otherwise cryptkey="${rootmnt}/${cryptkey#/root/}" fi if [ -n "$cryptheader" ] && ! type "$cryptheader" >/dev/null; then message "cryptsetup ($crypttarget): error - LUKS header \"$cryptheader\" missing" return 1 fi # The same target can be specified multiple times # eg root and resume lvs-on-lvm-on-crypto if [ -e "/dev/mapper/$crypttarget" ]; then return 0 fi modprobe -q dm_crypt # Make sure the cryptsource device is available if [ ! -e $cryptsource ]; then activate_vg fi # If the encrypted source device hasn't shown up yet, give it a # little while to deal with removable devices # the following lines below have been taken from # /usr/share/initramfs-tools/scripts/local, as suggested per # https://launchpad.net/bugs/164044 if [ ! -e "$cryptsource" ]; then log_begin_msg "Waiting for encrypted source device..." # Default delay is 180s if [ -z "${ROOTDELAY}" ]; then slumber=180 else slumber=${ROOTDELAY} fi if [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT ${slumber}" || true fi slumber=$(( ${slumber} * 10 )) while [ ! -e "$cryptsource" ]; do # retry for LVM devices every 10 seconds if [ ${slumber} -eq $(( ${slumber}/100*100 )) ]; then activate_vg fi /bin/sleep 0.1 slumber=$(( ${slumber} - 1 )) [ ${slumber} -gt 0 ] || break done if [ ${slumber} -gt 0 ]; then log_end_msg 0 else log_end_msg 1 || true fi if [ -x /sbin/usplash_write ]; then /sbin/usplash_write "TIMEOUT 15" || true fi fi udev_settle # We've given up, but we'll let the user fix matters if they can if [ ! -e "${cryptsource}" ]; then echo " ALERT! ${cryptsource} does not exist." echo " Check cryptopts=source= bootarg: cat /proc/cmdline" echo " or missing modules, devices: cat /proc/modules; ls /dev" panic -r "Dropping to a shell. Will skip ${cryptsource} if you can't fix." fi if [ ! -e "${cryptsource}" ]; then return 1 fi # Prepare commands cryptopen="/sbin/cryptsetup -T 1" if [ "$cryptdiscard" = "yes" ]; then cryptopen="$cryptopen --allow-discards" fi if [ -n "$cryptheader" ]; then cryptopen="$cryptopen --header=$cryptheader" fi if [ -n "$cryptkeyslot" ]; then cryptopen="$cryptopen --key-slot=$cryptkeyslot" fi if /sbin/cryptsetup isLuks ${cryptheader:-$cryptsource} >/dev/null 2>&1; then is_luks=1 cryptopen="$cryptopen open --type luks $cryptsource $crypttarget --key-file=-" elif [ "$crypttcrypt" = "yes" ]; then cryptopen="$cryptopen open --type tcrypt $cryptveracrypt $cryptsource $crypttarget" else cryptopen="$cryptopen -c $cryptcipher -s $cryptsize -h $crypthash open --type plain $cryptsource $crypttarget --key-file=-" fi cryptremove="/sbin/cryptsetup remove $crypttarget" NEWROOT="/dev/mapper/$crypttarget" # Try to get a satisfactory password $crypttries times count=0 while [ $crypttries -le 0 ] || [ $count -lt $crypttries ]; do export CRYPTTAB_TRIED="$count" if [ $count -gt 1 ]; then /bin/sleep 3 fi if [ -z "$cryptkeyscript" -a "$is_luks" -eq "1" ]; then cryptkey="Unlocking the disk $cryptsource ($crypttarget)\nEnter passphrase: " if [ -x /bin/plymouth ] && plymouth --ping; then cryptkeyscript="plymouth ask-for-password --prompt" cryptkey=$(echo -e "$cryptkey") else cryptkeyscript="/lib/cryptsetup/askpass" fi fi if [ -n "$CACHED_PASSWORD" ]; then if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \ echo -n "$CACHED_PASSWORD" | $cryptopen 2>/dev/null; then unset CACHED_PASSWORD fi fi count=$(( $count + 1 )) if [ -z "$CACHED_PASSWORD" ]; then CACHED_PASSWORD="`$cryptkeyscript \"$cryptkey\"`" if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \ echo -n "$CACHED_PASSWORD" | $cryptopen; then message "cryptsetup: cryptsetup failed, bad password or options?" unset CACHED_PASSWORD continue fi fi if [ ! -e "$NEWROOT" ]; then message "cryptsetup ($crypttarget): unknown error setting up device mapping" return 1 fi #FSTYPE='' #eval $(fstype < "$NEWROOT") FSTYPE="$(/sbin/blkid -s TYPE -o value "$NEWROOT")" # See if we need to setup lvm on the crypto device #if [ "$FSTYPE" = "lvm" ] || [ "$FSTYPE" = "lvm2" ]; then if [ "$FSTYPE" = "LVM_member" ] || [ "$FSTYPE" = "LVM2_member" ]; then if [ -z "$cryptlvm" ]; then message "cryptsetup ($crypttarget): lvm fs found but no lvm configured" return 1 elif ! activate_vg; then # disable error message, LP: #151532 #message "cryptsetup ($crypttarget): failed to setup lvm device" return 1 fi # Apparently ROOT is already set in /conf/param.conf for # flashed kernels at least. See bugreport #759720. if [ -f /conf/param.conf ] && grep -q "^ROOT=" /conf/param.conf; then NEWROOT=$(sed -n 's/^ROOT=//p' /conf/param.conf) else NEWROOT=${cmdline_root:-/dev/mapper/$cryptlvm} if [ "$cryptrootdev" = "yes" ]; then # required for lilo to find the root device echo "ROOT=$NEWROOT" >>/conf/param.conf fi fi #eval $(fstype < "$NEWROOT") FSTYPE="$(/sbin/blkid -s TYPE -o value "$NEWROOT")" fi #if [ -z "$FSTYPE" ] || [ "$FSTYPE" = "unknown" ]; then if [ -z "$FSTYPE" ]; then message "cryptsetup ($crypttarget): unknown fstype, bad password or options?" udev_settle $cryptremove unset CACHED_PASSWORD continue fi # decrease $count by 1, apparently last try was successful. count=$(( $count - 1 )) message "cryptsetup ($crypttarget): set up successfully" export CACHED_PASSWORD break done failsleep=60 # make configurable later? if [ "$cryptrootdev" = "yes" ] && [ $crypttries -gt 0 ] && [ $count -ge $crypttries ]; then message "cryptsetup ($crypttarget): maximum number of tries exceeded" message "cryptsetup: going to sleep for $failsleep seconds..." sleep $failsleep exit 1 fi udev_settle return 0 } exit_script() { CACHED_PASSWORD="`dd bs=512 if=/dev/random count=1 2>/dev/null `" unset CACHED_PASSWORD exit $1 } # # Begin real processing # # Do we have any kernel boot arguments? cmdline_cryptopts='' unset cmdline_root for opt in $(cat /proc/cmdline); do case $opt in cryptopts=*) opt="${opt#cryptopts=}" if [ -n "$opt" ]; then if [ -n "$cmdline_cryptopts" ]; then cmdline_cryptopts="$cmdline_cryptopts $opt" else cmdline_cryptopts="$opt" fi fi ;; root=*) opt="${opt#root=}" case $opt in /*) # Absolute path given. Not lilo major/minor number. cmdline_root=$opt ;; *) # lilo major/minor number (See #398957). Ignore esac ;; esac done if [ -n "$cmdline_cryptopts" ]; then # Call setup_mapping separately for each possible cryptopts= setting for cryptopt in $cmdline_cryptopts; do setup_mapping "$cryptopt" done exit 0 fi # Do we have any settings from the /conf/conf.d/cryptroot file? if [ -r /conf/conf.d/cryptroot ]; then while read mapping <&3; do setup_mapping "$mapping" 3<&- done 3< /conf/conf.d/cryptroot fi exit_script 0
35a36,37 > elif [ -p /dev/.initramfs/usplash_outfifo ] && [ -x /sbin/usplash_write ]; then > usplash_write "TEXT-URGENT $@" 101a104,105 > elif [ ${cryptsource#ID=} != $cryptsource ]; then > cryptsource="/dev/disk/by-id/${cryptsource#ID=}" 182c186 < local opts count cryptopen cryptremove NEWROOT --- > local opts count cryptopen cryptremove NEWROOT is_luks 183a188 > is_luks=0 199c204 < cryptkey="Please unlock disk $diskname: " --- > cryptkey="1Please unlock disk $diskname: " 244a250,252 > if [ -x /sbin/usplash_write ]; then > /sbin/usplash_write "TIMEOUT ${slumber}" || true > fi 262a271,273 > if [ -x /sbin/usplash_write ]; then > /sbin/usplash_write "TIMEOUT 15" || true > fi 291a303 > is_luks=1 304a317,337 > if [ $count -gt 1 ]; then > /bin/sleep 3 > fi > > if [ -z "$cryptkeyscript" -a "$is_luks" -eq "1" ]; then > cryptkey="Unlocking the disk $cryptsource ($crypttarget)\nEnter passphrase: " > if [ -x /bin/plymouth ] && plymouth --ping; then > cryptkeyscript="plymouth ask-for-password --prompt" > cryptkey=$(echo -e "$cryptkey") > else > cryptkeyscript="/lib/cryptsetup/askpass" > fi > fi > > if [ -n "$CACHED_PASSWORD" ]; then > if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \ > echo -n "$CACHED_PASSWORD" | $cryptopen 2>/dev/null; then > unset CACHED_PASSWORD > fi > fi > 307c340,341 < if [ ! -e "$NEWROOT" ]; then --- > if [ -z "$CACHED_PASSWORD" ]; then > CACHED_PASSWORD="`$cryptkeyscript \"$cryptkey\"`" 309,310c343,345 < $cryptkeyscript "$cryptkey" | $cryptopen; then < message "cryptsetup ($crypttarget): cryptsetup failed, bad password or options?" --- > echo -n "$CACHED_PASSWORD" | $cryptopen; then > message "cryptsetup: cryptsetup failed, bad password or options?" > unset CACHED_PASSWORD 355a391 > unset CACHED_PASSWORD 362a399,401 > > export CACHED_PASSWORD > 378a418,424 > exit_script() > { > CACHED_PASSWORD="`dd bs=512 if=/dev/random count=1 2>/dev/null `" > unset CACHED_PASSWORD > exit $1 > } > 425c471 < exit 0 --- > exit_script 0
crypttab:
echo "root_crypt1 /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part3 none luks,discard" >> /mnt/etc/crypttab
echo "root_crypt2 /dev/disk/by-id/ata-Micron_1100-part3 none luks,discard" >> /mnt/etc/crypttab
UUID, .
cryptroot, ( ) - UUID- .
apt-get install grub-pc
grub-probe /
— "zfs"
echo GRUB_PRELOAD_MODULES=\"part_gpt zfs\" >> /etc/default/grub
echo GRUB_DISABLE_OS_PROBER=true >> /etc/default/grub
echo "export ZPOOL_VDEV_NAME_PATH=YES" > /etc/profile.d/grub2_zpool_fix.sh
ZPOOL_VDEV_NAME_PATH=YES update-grub
update-initramfs -u -k all
cd && tar -C / -cf boot.tar /boot
mkfs.ext4 -L boot1 -m0 /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part2
mkfs.ext4 -L boot2 -m0 /dev/disk/by-id/ata-Micron_1100-part2
mount /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part2 /boot && tar -C / -xf boot.tar
update-initramfs -k all -u -t && update-grub
grub-install --bootloader-id=debian1 --recheck --no-floppy /dev/disk/by-id/ata-Samsung_SSD_850_PRO
umount /boot
mount /dev/disk/by-id/ata-Micron_1100-part2 /boot && tar -C / -xf boot.tar
update-initramfs -k all -u -t && update-grub
grub-install --bootloader-id=debian2 --recheck --no-floppy /dev/disk/by-id/ata-Micron_1100
umount /boot
passwd
zfs snapshot rpool/ROOT/debian@install
umount /tmp
exit
mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {}
zpool export rpool
reboot
( ONLINE):zpool status -v
SSH .
:zfs create rpool/home/user
adduser user
cp -a /etc/skel/.[!.]* /home/user
chown -R user:user /home/user
usermod -a -G audio,cdrom,dip,floppy,netdev,plugdev,sudo,video user
apt dist-upgrade --yes
Debian ZFS .
.
:
, , , .
:
, , .
, . grub .
Grub , (, , cryptroot).
, .
, NAS WEB-. FreeBSD — , , FreeNAS.
OpenMediaVault — , Debian.
, , Debian: , .
FreeNAS, ZFS.
, ZFS Linux.
Source: https://habr.com/ru/post/351932/
All Articles