diff options
Diffstat (limited to 'qa/workunits/rbd/luks-encryption.sh')
-rwxr-xr-x | qa/workunits/rbd/luks-encryption.sh | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/qa/workunits/rbd/luks-encryption.sh b/qa/workunits/rbd/luks-encryption.sh new file mode 100755 index 000000000..5d3cc68cd --- /dev/null +++ b/qa/workunits/rbd/luks-encryption.sh @@ -0,0 +1,217 @@ +#!/usr/bin/env bash +set -ex + +CEPH_ID=${CEPH_ID:-admin} +TMP_FILES="/tmp/passphrase /tmp/passphrase2 /tmp/testdata1 /tmp/testdata2 /tmp/cmpdata" + +_sudo() +{ + local cmd + + if [ `id -u` -eq 0 ] + then + "$@" + return $? + fi + + # Look for the command in the user path. If it fails run it as is, + # supposing it is in sudo path. + cmd=`which $1 2>/dev/null` || cmd=$1 + shift + sudo -nE "${cmd}" "$@" +} + +function drop_caches { + sudo sync + echo 3 | sudo tee /proc/sys/vm/drop_caches +} + +function expect_false() { + if "$@"; then return 1; else return 0; fi +} + +function test_encryption_format() { + local format=$1 + clean_up_cryptsetup + + # format + rbd encryption format testimg $format /tmp/passphrase + drop_caches + + # open encryption with cryptsetup + sudo cryptsetup open $RAW_DEV --type luks cryptsetupdev -d /tmp/passphrase + sudo chmod 666 /dev/mapper/cryptsetupdev + + # open encryption with librbd + LIBRBD_DEV=$(_sudo rbd -p rbd map testimg -t nbd -o encryption-passphrase-file=/tmp/passphrase) + sudo chmod 666 $LIBRBD_DEV + + # write via librbd && compare + dd if=/tmp/testdata1 of=$LIBRBD_DEV oflag=direct bs=1M + dd if=/dev/mapper/cryptsetupdev of=/tmp/cmpdata iflag=direct bs=4M count=4 + cmp -n 16MB /tmp/cmpdata /tmp/testdata1 + + # write via cryptsetup && compare + dd if=/tmp/testdata2 of=/dev/mapper/cryptsetupdev oflag=direct bs=1M + dd if=$LIBRBD_DEV of=/tmp/cmpdata iflag=direct bs=4M count=4 + cmp -n 16MB /tmp/cmpdata /tmp/testdata2 + + # FIXME: encryption-aware flatten/resize misbehave if proxied to + # RAW_DEV mapping (i.e. if RAW_DEV mapping ows the lock) + # (acquire and) release the lock as a side effect + rbd bench --io-type read --io-size 1 --io-threads 1 --io-total 1 testimg + + # check that encryption-aware resize compensates LUKS header overhead + (( $(sudo blockdev --getsize64 $LIBRBD_DEV) < (32 << 20) )) + expect_false rbd resize --size 32M testimg + rbd resize --size 32M --encryption-passphrase-file /tmp/passphrase testimg + (( $(sudo blockdev --getsize64 $LIBRBD_DEV) == (32 << 20) )) + + _sudo rbd device unmap -t nbd $LIBRBD_DEV +} + +function test_clone_encryption() { + clean_up_cryptsetup + + # write 1MB plaintext + dd if=/tmp/testdata1 of=$RAW_DEV oflag=direct bs=1M count=1 + + # clone (luks1) + rbd snap create testimg@snap + rbd snap protect testimg@snap + rbd clone testimg@snap testimg1 + rbd encryption format testimg1 luks1 /tmp/passphrase + + # open encryption with librbd, write one more MB, close + LIBRBD_DEV=$(_sudo rbd -p rbd map testimg1 -t nbd -o encryption-format=luks1,encryption-passphrase-file=/tmp/passphrase) + sudo chmod 666 $LIBRBD_DEV + dd if=$LIBRBD_DEV of=/tmp/cmpdata iflag=direct bs=1M count=1 + cmp -n 1MB /tmp/cmpdata /tmp/testdata1 + dd if=/tmp/testdata1 of=$LIBRBD_DEV seek=1 skip=1 oflag=direct bs=1M count=1 + _sudo rbd device unmap -t nbd $LIBRBD_DEV + + # second clone (luks2) + rbd snap create testimg1@snap + rbd snap protect testimg1@snap + rbd clone testimg1@snap testimg2 + rbd encryption format testimg2 luks2 /tmp/passphrase2 + + # open encryption with librbd, write one more MB, close + LIBRBD_DEV=$(_sudo rbd -p rbd map testimg2 -t nbd -o encryption-format=luks2,encryption-passphrase-file=/tmp/passphrase2,encryption-format=luks1,encryption-passphrase-file=/tmp/passphrase) + sudo chmod 666 $LIBRBD_DEV + dd if=$LIBRBD_DEV of=/tmp/cmpdata iflag=direct bs=1M count=2 + cmp -n 2MB /tmp/cmpdata /tmp/testdata1 + dd if=/tmp/testdata1 of=$LIBRBD_DEV seek=2 skip=2 oflag=direct bs=1M count=1 + _sudo rbd device unmap -t nbd $LIBRBD_DEV + + # flatten + expect_false rbd flatten testimg2 --encryption-format luks1 --encryption-format luks2 --encryption-passphrase-file /tmp/passphrase2 --encryption-passphrase-file /tmp/passphrase + rbd flatten testimg2 --encryption-format luks2 --encryption-format luks1 --encryption-passphrase-file /tmp/passphrase2 --encryption-passphrase-file /tmp/passphrase + + # verify with cryptsetup + RAW_FLAT_DEV=$(_sudo rbd -p rbd map testimg2 -t nbd) + sudo cryptsetup open $RAW_FLAT_DEV --type luks cryptsetupdev -d /tmp/passphrase2 + sudo chmod 666 /dev/mapper/cryptsetupdev + dd if=/dev/mapper/cryptsetupdev of=/tmp/cmpdata iflag=direct bs=1M count=3 + cmp -n 3MB /tmp/cmpdata /tmp/testdata1 + _sudo rbd device unmap -t nbd $RAW_FLAT_DEV +} + +function test_clone_and_load_with_a_single_passphrase { + local expectedfail=$1 + + # clone and format + rbd snap create testimg@snap + rbd snap protect testimg@snap + rbd clone testimg@snap testimg1 + rbd encryption format testimg1 luks2 /tmp/passphrase2 + + if [ "$expectedfail" = "true" ] + then + expect_false rbd flatten testimg1 --encryption-passphrase-file /tmp/passphrase2 + rbd flatten testimg1 --encryption-passphrase-file /tmp/passphrase2 --encryption-passphrase-file /tmp/passphrase + else + rbd flatten testimg1 --encryption-passphrase-file /tmp/passphrase2 + fi + + rbd remove testimg1 + rbd snap unprotect testimg@snap + rbd snap remove testimg@snap +} + +function test_plaintext_detection { + # 16k LUKS header + sudo cryptsetup -q luksFormat --type luks2 --luks2-metadata-size 16k $RAW_DEV /tmp/passphrase + test_clone_and_load_with_a_single_passphrase true + + # 4m LUKS header + sudo cryptsetup -q luksFormat --type luks2 --luks2-metadata-size 4m $RAW_DEV /tmp/passphrase + test_clone_and_load_with_a_single_passphrase true + + # no luks header + dd if=/dev/zero of=$RAW_DEV oflag=direct bs=4M count=8 + test_clone_and_load_with_a_single_passphrase false +} + +function get_nbd_device_paths { + rbd device list -t nbd | tail -n +2 | egrep "\s+rbd\s+testimg" | awk '{print $5;}' +} + +function clean_up_cryptsetup() { + ls /dev/mapper/cryptsetupdev && sudo cryptsetup close cryptsetupdev || true +} + +function clean_up { + sudo rm -f $TMP_FILES + clean_up_cryptsetup + for device in $(get_nbd_device_paths); do + _sudo rbd device unmap -t nbd $device + done + + rbd remove testimg2 || true + rbd snap unprotect testimg1@snap || true + rbd snap remove testimg1@snap || true + rbd remove testimg1 || true + rbd snap unprotect testimg@snap || true + rbd snap remove testimg@snap || true + rbd remove testimg || true +} + +if [[ $(uname) != "Linux" ]]; then + echo "LUKS encryption tests only supported on Linux" + exit 0 +fi + + +if [[ $(($(ceph-conf --name client.${CEPH_ID} --show-config-value rbd_default_features) & 64)) != 0 ]]; then + echo "LUKS encryption tests not supported alongside image journaling feature" + exit 0 +fi + +clean_up + +trap clean_up INT TERM EXIT + +# generate test data +dd if=/dev/urandom of=/tmp/testdata1 bs=4M count=4 +dd if=/dev/urandom of=/tmp/testdata2 bs=4M count=4 + +# create passphrase files +printf "pass\0word\n" > /tmp/passphrase +printf "\t password2 " > /tmp/passphrase2 + +# create an image +rbd create testimg --size=32M + +# map raw data to nbd device +RAW_DEV=$(_sudo rbd -p rbd map testimg -t nbd) +sudo chmod 666 $RAW_DEV + +test_plaintext_detection + +test_encryption_format luks1 +test_encryption_format luks2 + +test_clone_encryption + +echo OK |