#1493 PR merged: Improve cryptographic security and user-friendliness for LUKS volumes

Labels: enhancement, fixed / solved / done

OliverO2 opened issue at 2017-09-15 09:07:

Problem

ReaR 2.2 with cryptsetup 1.6.6 (as on Ubuntu 16.04.3 LTS) uses compiled-in default values which are not up-to-date in terms of cryptographic security:

Option cryptsetup 1.6.6 Default More Secure Auto-detectable
Key size --key-size 256 --key-size 512 Yes
Passphrase processing time (msecs) --iter-time 1000 --iter-time 2000 No
Random number generation device --use-urandom --use-random No

For details, see Encryption options for LUKS mode in the ArchWiki.

In addition, ReaR can neither auto-detect nor use existing keyfiles for the automatic decryption of recreated LUKS volumes. A recovered system will ask the user for a passphrase where the original system would not.

Solution

This PR improves LUKS recovery with these characteristics:

  • Auto-detect the --key-size option from the original volume.
  • Auto-detect keyfiles in crypttab and add them to recreated LUKS volumes.
  • Allow additional cryptsetup options, which cannot be auto-detected, to be configured.

Strategy

See comment in commit c9e7e1bdc5a788590e3a378839fbc6e099158a04.

Note: Removing the documented mode option is an incompatible change, which simplifies the code by processing each option in the same way. Since disklayout.conf is usually re-generated before being edited, introducing this change seems OK to me.

Tested on Ubuntu 16.04.3 LTS.

jsmeix commented at 2017-09-15 09:36:

@OliverO2 only FYI
you may have a look at the related issue
https://github.com/rear/rear/issues/1444

@gozora
I know nothing at all about LUKS so that it is bad luck for you ;-)
that you are curious about how ReaR works with LUKS
https://github.com/rear/rear/issues/1444#issuecomment-324071821
so that I dare to assign this one to you :-)

jsmeix commented at 2017-09-15 09:44:

@OliverO2
as far as I see in your comments in your
usr/share/rear/finalize/GNU/Linux/240_reassign_luks_keyfiles.sh

original keyfiles should have been restored from the backup

it means that with this pull request nothing secret
will be added into the ReaR recovery system?
At least not by default without an explicit user setting?
Cf.
https://github.com/rear/rear/pull/1472#issuecomment-328459748
and
https://github.com/rear/rear/issues/1444#issuecomment-324294539

OliverO2 commented at 2017-09-15 10:15:

@jsmeix
Yes, no secrets will be added to the rescue medium as stated in the comment of commit c9e7e1bdc5a788590e3a378839fbc6e099158a04:

Auto-detect 'keyfile' option, enable unattended (password-less)
decryption via temporary keyfile without leaking original keyfiles on
rescue medium, securely re-assign keyfiles after restore.

Also see this comment in 160_include_luks_code.sh.

When you have encrypted disks and you leak secrets onto the unencrypted rescue medium it is like building an expensive underground bank vault and then putting the key into a tin box on your desk. So I just went the extra mile to avoid this.

I agree with https://github.com/rear/rear/pull/1472#issuecomment-328459748 and below.

My next task is actually to provide a ReaR option to encrypt ssh keys which

  • currently leak onto ReaR's rescue media, and
  • may lack passphrase-protection for unattended operations, and
  • may provide access to the central backup repository.

The idea incorporates asking the user for an initial recovery master password (resembling https://github.com/rear/rear/issues/1444#issuecomment-324294539), although I would not recommend putting this into configuration files.

jsmeix commented at 2017-09-15 10:31:

@OliverO2
many thanks for your explanation.

As you can also see in
https://github.com/rear/rear/pull/1489#issuecomment-329424147
encryption stuff is not one of my favourite areas of interest.
Accordingly I do very much appreciate it when you check
and even improve those things in ReaR.
I look forward to your ssh improvements.
As long as in etc/rear/local.conf even a dumb

SSH_ROOT_PASSWORD="rear"

still "just works" to "just get" ssh access into the recovery system
I am happy because I use that all the time on my testing systems.
( I do not what to have the "good old times" back when one had
to do special setup to get ssh access into the recovery system. ;-)

OliverO2 commented at 2017-09-25 19:02:

@gozora

For me implementing automatic volume unlocking is somehow politic decision, and as I don't like politics I let @schlomo decide whether something like this should or should not be implemented. (c.f. #1444 (comment)).

Isn't that the original system administrator's decision that we just recreate during recovery? He has finally decided to go with crypttab keyfiles after all. Do you think that this decision should be overruled by ReaR?

this PR is broken for systems that don't use automatic unlocking of volumes (which is completely valid setup)

You are right. I'll correct this. Can you point me to the manpage you've used? It seems to be a rather old version of the cryptsetup suite as newer versions (like this one) don't seem to allow verbatim passwords there anymore.

gozora commented at 2017-09-25 19:12:

Isn't that the original system administrator's decision that we just recreate during recovery? He has finally decided to go with crypttab keyfiles after all. Do you think that this decision should be overruled by ReaR?

Like I said, for me this is politics, I don't like politics. ReaR is my spare time project and I don't do thing I don't like in my spare time.
So again, if @schlomo does not object neither me will object.

You are right. I'll correct this. Can you point me to the manpage you've used? It seems to be a rather old version of the cryptsetup suite as newer versions (like this one) don't seem to allow verbatim passwords there anymore.

I don't think so.

Excerpt from http://manpages.ubuntu.com/manpages/xenial/en/man5/crypttab.5.html:

   It can also be a device name (e.g. /dev/urandom), note however that
   LUKS requires a persistent key and therefore does not support random
   data keys.

   If the key file is the string “none”, a passphrase will be read
   interactively from the console. In this case, the options precheck,
   check, checkargs and tries may be useful.

But to answer your question I've used man crypttab from CentOS 7.3

OliverO2 commented at 2017-09-25 19:24:

OK, I misunderstood this one:

The third field specifies the encryption password.

It initially sounded to me like is was meant to be a verbatim password first, and a path to a keyfile only under certain circumstances. When reading more carefully, it was never really meant to be a password. So they have just improved the explanation in newer incarnations of that manual page.

Anyway, I'll take care of the special cases of 'none' and '-'.

jsmeix commented at 2017-09-26 09:30:

A "caution!" regarding running any programs in ReaR
that may (sometimes) do interactive user dialogs like
"a passphrase will be read interactively from the console":

In ReaR interactive user dialogs won't work by default because
both STDERR and STDOUT are redirected into ReaR's log file,
cf. "What to do with stdout and stderr" at
https://github.com/rear/rear/wiki/Coding-Style

OliverO2 commented at 2017-09-26 17:13:

@gozora Should work now:

  • temporary keyfiles are named after the target (/dev/mapper) name, which must be unique
  • none entries in crypttab are recognized

OliverO2 commented at 2017-09-26 17:23:

@jsmeix
I've even tried to use the new UserInput -C variant to gather a password in layout/prepare/GNU/Linux/160_include_luks_code.sh, replacing the two branches in the elif ... fi section at the end with:

    else
        if [ -n "$password" ] ; then
            password="$(UserInput -I LUKS_DEVICE_PASSWORD -C -t 0 -p "Please enter the password for LUKS device $target_name ($source_device):")"
        fi
        echo "echo \"$password\" | cryptsetup luksFormat --batch-mode $cryptsetup_options $source_device"
        echo "echo \"$password\" | cryptsetup luksOpen $source_device $target_name"
    fi

UserInput works as advertised...

2017-09-26 16:17:10.938445407 UserInput: called in /usr/share/rear/layout/prepare/GNU/Linux/160_include_luks_code.sh line 54
2017-09-26 16:17:10.940826635 UserInput: No choices specified
2017-09-26 16:17:10.942013330 Please enter the password for LUKS device Foxtrot-02 (/dev/sdb1):
2017-09-26 16:17:26.970608078 UserInput: 'read' got user input

...but passwords then appeared in diskrestore.sh and in the logfile nonetheless:

+++ echo '2017-09-26 16:18:11.732036596 Creating luks device Foxtrot-02 on /dev/sdb1'
2017-09-26 16:18:11.732036596 Creating luks device Foxtrot-02 on /dev/sdb1
+++ echo abcdef5
+++ cryptsetup luksFormat --batch-mode --cipher aes-xts-plain64 --key-size 512 --hash sha256 --uuid e1949e50-2b2a-46ae-becf-70e0122df4fb --iter-time 2000 --use-random /dev/sdb1
+++ cryptsetup luksOpen /dev/sdb1 Foxtrot-02
+++ echo abcdef5
+++ component_created /dev/mapper/Foxtrot-02 crypt

So I've reverted this change.

schlomo commented at 2017-09-26 17:57:

@OliverO2 isn't that in debug mode? Then I would expect the passwords to show up. Users are not expected to use ReaR in debug mode so that regular usage would be save.

OliverO2 commented at 2017-09-26 19:18:

@schlomo Invocation was just rear recover. Neither -d nor -D were used.

Seems like it's in diskrestore.sh, which begins:

#!/bin/bash

LogPrint "Start system layout restoration."

mkdir -p /mnt/local
if create_component "vgchange" "rear" ; then
    lvm vgchange -a n >/dev/null
    component_created "vgchange" "rear"
fi

set -e
set -x

Log output looks like this:

2017-09-26 19:09:23.782373730 ======================
2017-09-26 19:09:23.783321212 Running 'layout/recreate' stage
2017-09-26 19:09:23.784120375 ======================
2017-09-26 19:09:23.789236573 Including layout/recreate/default/100_ask_confirmation.sh
2017-09-26 19:09:23.790280158 Please confirm that '/var/lib/rear/layout/diskrestore.sh' is as you expect.
2017-09-26 19:09:24.823612547 User selected: 5) Continue recovery
2017-09-26 19:09:24.827109572 Including layout/recreate/default/200_run_script.sh
2017-09-26 19:09:24.830486207 Start system layout restoration.
/var/lib/rear/layout/diskrestore.sh: line 7: lvm: command not found
+++ create_component /dev/sda disk
+++ local device=/dev/sda
+++ local type=disk
+++ local touchfile=disk--dev-sda
+++ '[' -e /tmp/rear.QUvz5k8O4h9QKwx/tmp/touch/disk--dev-sda ']'
+++ return 0
+++ Log 'Stop mdadm'
++++ date '+%Y-%m-%d %H:%M:%S.%N '
+++ local 'timestamp=2017-09-26 19:09:24.835891725 '
+++ test 1 -gt 0
+++ echo '2017-09-26 19:09:24.835891725 Stop mdadm'
2017-09-26 19:09:24.835891725 Stop mdadm
+++ grep -q md /proc/mdstat
+++ Log 'Erasing MBR of disk /dev/sda'
++++ date '+%Y-%m-%d %H:%M:%S.%N '
+++ local 'timestamp=2017-09-26 19:09:24.838378106 '
+++ test 1 -gt 0
+++ echo '2017-09-26 19:09:24.838378106 Erasing MBR of disk /dev/sda'
2017-09-26 19:09:24.838378106 Erasing MBR of disk /dev/sda
+++ dd if=/dev/zero of=/dev/sda bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.0308365 s, 16.6 kB/s
+++ sync

[...]

+++ component_created btrfsmountedsubvol:/mnt/reserve btrfsmountedsubvol
+++ local device=btrfsmountedsubvol:/mnt/reserve
+++ local type=btrfsmountedsubvol
+++ local touchfile=btrfsmountedsubvol-btrfsmountedsubvol:-mnt-reserve
+++ touch /tmp/rear.QUvz5k8O4h9QKwx/tmp/touch/btrfsmountedsubvol-btrfsmountedsubvol:-mnt-reserve
+++ set +x
2017-09-26 19:10:02.921303941 Disk layout created.
2017-09-26 19:10:02.923994344 Including layout/recreate/default/250_verify_mount.sh
2017-09-26 19:10:02.928602720 Finished running 'layout/recreate' stage in 39 seconds
2017-09-26 19:10:02.929844149 ======================
2017-09-26 19:10:02.930850913 Running 'restore' stage
2017-09-26 19:10:02.932030174 ======================

schlomo commented at 2017-09-26 19:19:

Maybe the code around diskrestore actually enables set -x permanently.

OliverO2 commented at 2017-09-26 19:32:

Apparently, it's layout/prepare/default/540_generate_device_code.sh. Nothing for me to mess with at this time ;-).

gozora commented at 2017-09-27 09:41:

@OliverO2 thanks for updating this PR.
From my point of view, this improvement works well enough to be merged, so if there are not other objections I'll merge it next days.

V.

jsmeix commented at 2017-09-27 10:16:

Only a side note how to run commands really silently:
To run commands that deal with confidential data
really silently in ReaR see the comment in the
UserInput function that reads:

#       If confidential user input is needed also in debugscripts mode the caller of the UserInput function
#       must call it in an appropriate (temporary) environment e.g. with STDERR redirected to /dev/null like:
#           { password="$( UserInput -I PASSWORD -C -r -s -p 'Enter the pasword' )" ; } 2>/dev/null

I.e. you need to put confidentially working commands into
an appropriate silencing enviroment for example like

{ root_password="$( grep '^root:' /etc/shadow | cut -d ':' -f2 )" ; } 2>/dev/null
{ echo "$root_password" ; } 1>/dev/null 2>/dev/null

You cannot rely on that 'set -x' is not somehow set.
The user can set it, a script may set it, whatever else...

gozora commented at 2017-10-04 08:42:

@OliverO2 thanks for this improvement!


[Export of Github issue for rear/rear.]