ceph/qa/workunits/rbd/luks-encryption.sh
Ilya Dryomov 8d5d478532 qa/workunits/rbd: add encryption-aware resize test
Note that we are hitting https://tracker.ceph.com/issues/58160 here
because by the time we get to "rbd resize" RAW_DEV mapping owns the
lock (due to a write to /dev/mapper/cryptsetupdev being last).

While at it, resurrect the ability to easily run this script on
vstart clusters -- see commit f737c2855a ("qa/workunits/rbd: make
luks-encryption test work on vstart cluster").

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
2022-12-04 18:24:10 +01:00

218 lines
6.8 KiB
Bash
Executable File

#!/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