diff --git a/.github/actions/run-aa-as/action.yml b/.github/actions/run-aa-as/action.yml new file mode 100644 index 0000000..6cc8939 --- /dev/null +++ b/.github/actions/run-aa-as/action.yml @@ -0,0 +1,34 @@ +name: 'Run Attestation Agent and Attestation Service' +runs: + using: "composite" + steps: + - name: Prepare attestation-agent + shell: bash + run: | + set -e + set -x + + yum install -y attestation-agent + RUST_LOG=debug attestation-agent --attestation_sock unix:///run/confidential-containers/attestation-agent/attestation-agent.sock & + + - name: Prepare attestation-service + shell: bash + run: | + set -e + set -x + + yum install -y trustee + + # Launch trustee + (/usr/bin/rvps --config /etc/trustee/rvps.json --address 127.0.0.1:50003 &) && sleep 1 + (/usr/bin/grpc-as --socket 0.0.0.0:50004 --config-file /etc/trustee/as-config.json &) && sleep 1 + (/usr/bin/kbs --config-file /etc/trustee/kbs-config.toml &) && sleep 1 + (/usr/bin/trustee-gateway --config /etc/trustee/gateway.yml > /tmp/trustee-gateway.log 2>&1 &) && sleep 1 + + # Register passphrases + mkdir -p /opt/trustee/kbs/repository/default/local-resources/ + echo -n "AAAaaawewe111" > /opt/trustee/kbs/repository/default/local-resources/volume + echo -n "AAAaaawewe222" > /opt/trustee/kbs/repository/default/local-resources/rootfs + echo -n "AAAaaawewe333" > /opt/trustee/kbs/repository/default/local-resources/data + + diff --git a/.github/workflows/build-rpm.yml b/.github/workflows/build-rpm.yml index 88f4399..094f9a3 100644 --- a/.github/workflows/build-rpm.yml +++ b/.github/workflows/build-rpm.yml @@ -57,7 +57,7 @@ jobs: ./rpmbuild/SRPMS/*.src.rpm ./rpmbuild/RPMS/*/*.rpm - test: + unit-test: strategy: fail-fast: false matrix: @@ -114,10 +114,154 @@ jobs: - name: Run test script from repo run: make run-test + test-volume-encryption: + strategy: + fail-fast: false + matrix: + distro: ["alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/alinux3:latest"] + runs-on: ubuntu-latest + defaults: + run: + shell: bash + needs: build + container: + image: ${{ matrix.distro }} + volumes: + - /run/udev/control:/run/udev/control + - /dev:/dev + options: --privileged --ipc=host + steps: + - name: Update yum mirror + run: | + set -e + set -x + + # replace the mirror + sed -i -E 's|https?://mirrors.openanolis.cn/anolis/|https://mirrors.aliyun.com/anolis/|g' /etc/yum.repos.d/*.repo + sed -i -E 's|https?://mirrors.cloud.aliyuncs.com/|https://mirrors.aliyun.com/|g' /etc/yum.repos.d/*.repo + + # install rpmdevtools + yum install -y git yum-utils + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: ./ + merge-multiple: false + + - name: Install RPM packages + run: | + set -e + set -x + + # test rpm package install + yum install -y ./rpm-packages/RPMS/*/cryptpilot-*.rpm + cryptpilot --version + + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: 'true' + + - uses: ./.github/actions/run-aa-as + + - name: Run volume encryption test + run: | + bash ./scripts/test/test-volume-encryption.sh + + test-system-encryption: + strategy: + fail-fast: false + matrix: + distro: ["alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/alinux3:latest"] + runs-on: ubuntu-latest + defaults: + run: + shell: bash + needs: build + container: + image: ${{ matrix.distro }} + volumes: + - /run/udev/control:/run/udev/control + - /dev:/dev + - /lib/modules/:/lib/modules/ # for kernel modules + options: --privileged --ipc=host + steps: + - name: Update yum mirror + run: | + set -e + set -x + + # replace the mirror + sed -i -E 's|https?://mirrors.openanolis.cn/anolis/|https://mirrors.aliyun.com/anolis/|g' /etc/yum.repos.d/*.repo + sed -i -E 's|https?://mirrors.cloud.aliyuncs.com/|https://mirrors.aliyun.com/|g' /etc/yum.repos.d/*.repo + + # install rpmdevtools + yum install -y git yum-utils + + # install requirements + yum install -y libguestfs-tools + + - name: Load nbd kernel module + run: | + yum install -y kmod zstd + + MODULE_DIR="/lib/modules/$(uname -r)" + MODULE_FILE=$(find "$MODULE_DIR" -name "nbd.ko*" -type f | head -1) + + if [ -z "$MODULE_FILE" ]; then + echo "No module file found in $MODULE_DIR" + exit 1 + fi + echo "Found module file: $MODULE_FILE" + + if [[ "$MODULE_FILE" == *.ko.zst ]]; then + echo "Found zstd compressed module file, decompressing..." + + zstd -d "$MODULE_FILE" -o "/tmp/nbd.ko" + if [ $? -ne 0 ]; then + echo "Failed to decompress module file" + exit 1 + fi + + echo "Loading the decompressed module..." + insmod "/tmp/nbd.ko" || exit 1 + else + echo "Loading the module with modprobe ..." + modprobe nbd + fi + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: /tmp/ + merge-multiple: false + + - name: Install RPM packages + run: | + set -e + set -x + + # test rpm package install + yum install -y /tmp/rpm-packages/RPMS/*/cryptpilot-*.rpm + cryptpilot --version + + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: 'true' + + - uses: ./.github/actions/run-aa-as + + - name: Run system encryption test + run: | + export LIBGUESTFS_BACKEND=appliance # set this for virt-customize + timeout 1200s bash ./scripts/test/test-system-encryption.sh --ci --package /tmp/rpm-packages/RPMS/*/cryptpilot-*.rpm --trustee-url "http://10.0.2.2:8081/api/" + release: if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest - needs: test + needs: [unit-test, test-volume-encryption, test-system-encryption] steps: - name: Download artifacts uses: actions/download-artifact@v4 diff --git a/Makefile b/Makefile index 9f01a9a..743ce10 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,7 @@ shellcheck: @command -v shellcheck >&- || { \ echo "shellcheck not found, please installing it from https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.linux.x86_64.tar.xz" ; \ } - find . -name '*.sh' -exec shellcheck {} \; + @{ find . -name '*.sh' -printf '%P\0' | xargs -0 shellcheck ; } || { echo ; echo "Shellcheck finished. You can fix with:" ; echo " find . -name '*.sh' -printf '%P\0' | xargs -0 shellcheck -f diff | patch -p1" ; echo ; exit 1 ; } .PHONE: clippy clippy: diff --git a/README.md b/README.md index cb29a44..76a0784 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,22 @@ Now you can read and write files in the mounted directory. systemctl enable --now cryptpilot.service ``` +## CI Tests + +This project includes CI tests for various encryption scenarios: + +1. System disk encryption test (test-system-encryption.sh) - Tests full disk encryption with exec provider +2. KBS volume encryption test (test-kbs-volume.sh) - Tests data volume encryption with KBS-like provider + +You can run these tests locally: +```sh +# Run system encryption test +sudo ./test-system-encryption.sh + +# Run KBS volume test +sudo ./test-kbs-volume.sh +``` + # Supported Distrubutions CryptPilot has been tested on the following distributions, and it may not work on other distributions. diff --git a/scripts/test/test-system-encryption.sh b/scripts/test/test-system-encryption.sh new file mode 100755 index 0000000..e061d24 --- /dev/null +++ b/scripts/test/test-system-encryption.sh @@ -0,0 +1,679 @@ +#!/bin/bash + +# Unified test script for system disk encryption with cryptpilot +# This script can be used in different modes: +# 1. CI mode - Automated testing with verification +# 2. Local mode - Interactive testing +# 3. Download only mode - Just download images +# 4. Encrypt only mode - Just encrypt an existing image + +set -e # Exit on any error + +# Default configuration +IMAGE_URL="https://alinux3.oss-cn-hangzhou.aliyuncs.com/aliyun_3_x64_20G_nocloud_alibase_20250117.qcow2" +IMAGE_NAME="alinux3.qcow2" +ENCRYPTED_IMAGE_NAME="encrypted.qcow2" +CONFIG_DIR="test-config" +PASSPHRASE="AAAaaawewe222" +LOG_FILE="qemu-output.log" +TRUSTEE_URL="http://10.0.2.2:8081/api/" # Trustee service URL + +# Mode flags +CI_MODE=false +LOCAL_MODE=false +DOWNLOAD_ONLY=false +ENCRYPT_ONLY=false +KEEP_FILES=false + +# Package list for cryptpilot-convert +PACKAGES=() + +# Paths to existing images (prefixed with @ to indicate they should be used as-is) +EXISTING_IMAGE_PATH="" + +# QEMU command to use +QEMU_CMD="" + +# Common QEMU paths to check +QEMU_PATHS=( + "qemu-system-x86_64" + "qemu-kvm" + "qemu-system-i386" + "/usr/libexec/qemu-kvm" + "/usr/bin/qemu-system-x86_64" + "/usr/bin/qemu-kvm" + "/usr/local/bin/qemu-system-x86_64" +) + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Help message +show_help() { + cat </dev/null 2>&1; then + QEMU_CMD="$path" + log "Found QEMU command: $QEMU_CMD" + return 0 + fi + done + + error "No QEMU command found. Please install QEMU (qemu-system-x86 or qemu-kvm)" +} + +# Cleanup function +cleanup() { + if [[ "$KEEP_FILES" == false ]]; then + log "Cleaning up..." + [[ -d "${CONFIG_DIR}" ]] && rm -rf "${CONFIG_DIR}" + # Only clean up downloaded/created files, not existing ones + if [[ -z "$EXISTING_IMAGE_PATH" ]]; then + [[ "$DOWNLOAD_ONLY" == false && "$ENCRYPT_ONLY" == false ]] && [[ -f "${IMAGE_NAME}" ]] && rm -f "${IMAGE_NAME}" + fi + [[ "$DOWNLOAD_ONLY" == false ]] && [[ -f "${ENCRYPTED_IMAGE_NAME}" ]] && rm -f "${ENCRYPTED_IMAGE_NAME}" + [[ -S "qemu-monitor.sock" ]] && rm -f "qemu-monitor.sock" + [[ -f "${LOG_FILE}" ]] && rm -f "${LOG_FILE}" + else + log "Keeping downloaded files as requested" + fi + + # Kill QEMU process if still running + if [[ -n "${qemu_pid:-}" ]]; then + log "Terminating QEMU process ${qemu_pid}" + kill "${qemu_pid}" 2>/dev/null || true + # Wait a moment for graceful termination + sleep 2 + # Force kill if still running + kill -9 "${qemu_pid}" 2>/dev/null || true + fi +} + +trap cleanup EXIT + +# Setup config directory +setup_config() { + log "Setting up cryptpilot config..." + mkdir -p "${CONFIG_DIR}" + + cat >"${CONFIG_DIR}/fde.toml" </dev/null 2>&1; then + log "Using wget with resume capability" + wget -c -O "${IMAGE_NAME}" "${IMAGE_URL}" || error "Failed to download image with wget" + # Try with curl if wget is not available + elif command -v curl >/dev/null 2>&1; then + log "Using curl" + curl -L -o "${IMAGE_NAME}" "${IMAGE_URL}" || error "Failed to download image with curl" + else + error "Neither wget nor curl found" + fi + + [[ -f "${IMAGE_NAME}" ]] || error "Image file not found after download" + log "Image downloaded successfully" +} + +# Find cryptpilot-convert command +find_cryptpilot_convert() { + log "Detecting cryptpilot-convert installation..." + + # Check if cryptpilot-convert is available in PATH + if command -v cryptpilot-convert >/dev/null 2>&1; then + CRYPTPILOT_CONVERT_CMD="cryptpilot-convert" + log "Found cryptpilot-convert command: $CRYPTPILOT_CONVERT_CMD" + return 0 + fi + + # Try to use built version + if [[ -f "target/release/cryptpilot-convert" ]]; then + CRYPTPILOT_CONVERT_CMD="./target/release/cryptpilot-convert" + log "Found built cryptpilot-convert: $CRYPTPILOT_CONVERT_CMD" + return 0 + fi + + # Try to use script version + if [[ -f "cryptpilot-convert.sh" ]]; then + chmod +x cryptpilot-convert.sh + CRYPTPILOT_CONVERT_CMD="./cryptpilot-convert.sh" + log "Found cryptpilot-convert script: $CRYPTPILOT_CONVERT_CMD" + return 0 + fi + + error "cryptpilot-convert not found" +} + +# Encrypt image with cryptpilot-convert +encrypt_image() { + if [[ -f "${ENCRYPTED_IMAGE_NAME}" ]]; then + log "Using existing encrypted image file" + return + fi + + log "Encrypting image with cryptpilot-convert..." + + # Find cryptpilot-convert command + find_cryptpilot_convert + + # Build package arguments + local package_args=() + for package in "${PACKAGES[@]}"; do + package_args+=(--package "$package") + done + + # Run cryptpilot-convert + "$CRYPTPILOT_CONVERT_CMD" --in "${IMAGE_NAME}" --out "${ENCRYPTED_IMAGE_NAME}" \ + --config-dir "${CONFIG_DIR}" --rootfs-passphrase "${PASSPHRASE}" \ + "${package_args[@]}" || error "Encryption failed" + + [[ -f "${ENCRYPTED_IMAGE_NAME}" ]] || error "Encrypted image not found after encryption process" + log "Image encrypted successfully" +} + +# Start QEMU with the encrypted image (CI mode) +start_qemu_ci() { + log "Starting QEMU with encrypted image (CI mode)..." + + # Find appropriate QEMU command + find_qemu + + # Print QEMU command for debugging + log "QEMU command: $QEMU_CMD -m 2048M -smp 2 -nographic -serial mon:stdio -monitor unix:qemu-monitor.sock,server,nowait -drive file=${ENCRYPTED_IMAGE_NAME},format=qcow2,if=virtio,id=hd0,readonly=off -netdev user,id=net0,net=192.168.123.0/24,hostfwd=tcp::2222-:22 -device virtio-net,netdev=net0" + + # Start QEMU in background, redirecting output to file for analysis + $QEMU_CMD \ + -m 2048M \ + -smp 2 \ + -nographic \ + -serial mon:stdio \ + -monitor unix:qemu-monitor.sock,server,nowait \ + -drive file="${ENCRYPTED_IMAGE_NAME}",format=qcow2,if=virtio,id=hd0,readonly=off \ + -netdev user,id=net0,net=192.168.123.0/24,hostfwd=tcp::2222-:22 \ + -device virtio-net,netdev=net0 \ + >"${LOG_FILE}" 2>&1 & + qemu_pid=$! + + log "QEMU started with PID: ${qemu_pid}" + + # Give QEMU some time to start + sleep 10 + + # Check if QEMU is still running + if ! kill -0 ${qemu_pid} 2>/dev/null; then + error "QEMU process terminated unexpectedly" + fi +} + +# Verify system boot by checking for login prompt in output (CI mode) +verify_boot() { + log "Verifying system boot by checking for login prompt..." + + # Wait for system to boot and show login prompt (max 300 seconds) + local timeout=300 + local count=0 + + while [[ $count -lt $timeout ]]; do + # Check if log file exists and has content + if [[ -f "${LOG_FILE}" ]] && [[ -s "${LOG_FILE}" ]]; then + log "Log file exists and has content, checking for login prompt..." + + # Check if login prompt appears in output log + if grep -q "login:" "${LOG_FILE}" 2>/dev/null; then + log "System boot verified - login prompt detected!" + log "Last 20 lines of output:" + tail -20 "${LOG_FILE}" + return 0 + fi + + # Show progress every 30 seconds + if ((count % 30 == 0)); then + log "Still waiting for boot (elapsed: ${count}s)..." + log "Last 10 lines of log:" + tail -10 "${LOG_FILE}" + fi + elif [[ -f "${LOG_FILE}" ]]; then + log "Log file exists but is empty (elapsed: ${count}s)" + else + log "Log file does not exist yet (elapsed: ${count}s)" + fi + + # Check if QEMU process is still running + if ! kill -0 ${qemu_pid} 2>/dev/null; then + error "QEMU process terminated unexpectedly. Check ${LOG_FILE} for details." + fi + + sleep 1 + ((count++)) + done + + # If we get here, the system didn't boot in time + log "System failed to boot within ${timeout} seconds." + if [[ -f "${LOG_FILE}" ]]; then + log "Showing last 50 lines of QEMU output:" + tail -50 "${LOG_FILE}" + else + log "No QEMU output log found." + fi + + error "System failed to boot and show login prompt within ${timeout} seconds." +} + +# Check mount entries in /etc/mtab and device mapper volumes +check_mount_entries() { + log "Checking mount entries and device mapper volumes..." + + # Wait for system to be fully ready (add a small delay) + sleep 5 + + # Try to login via console to verify system is working + log "Attempting to login via console with username 'root' and password 'root'..." + # Send username and password via QEMU monitor using sendkey command + for char in r o o t; do + echo -e "sendkey ${char}\n" | timeout 10 socat - UNIX-CONNECT:qemu-monitor.sock >/dev/null 2>&1 + sleep 0.1 + done + echo -e "sendkey ret\n" | timeout 10 socat - UNIX-CONNECT:qemu-monitor.sock >/dev/null 2>&1 + + sleep 1 + + for char in r o o t; do + echo -e "sendkey ${char}\n" | timeout 10 socat - UNIX-CONNECT:qemu-monitor.sock >/dev/null 2>&1 + sleep 0.1 + done + echo -e "sendkey ret\n" | timeout 10 socat - UNIX-CONNECT:qemu-monitor.sock >/dev/null 2>&1 + + sleep 3 + + # Try to extract information from QEMU guest + if [[ -S "qemu-monitor.sock" ]]; then + log "Extracting information from QEMU guest..." + + # Extract /etc/mtab from guest + echo -e "human-monitor-command {\"command-line\":\"cat /etc/mtab\"}\nquit" | socat - UNIX-CONNECT:qemu-monitor.sock >mtab_output.txt 2>/dev/null + + # Extract /dev/mapper contents from guest + echo -e "human-monitor-command {\"command-line\":\"ls -1 /dev/mapper\"}\nquit" | socat - UNIX-CONNECT:qemu-monitor.sock >dev_mapper_output.txt 2>/dev/null + + # Check for rootfs mount entry (only checking the first 3 columns) + if grep -q "^/dev/mapper/rootfs / overlay" mtab_output.txt; then + log "Rootfs mount entry found in /etc/mtab!" + else + log "Rootfs mount entry NOT found in /etc/mtab." + log "Current mtab entries:" + cat mtab_output.txt + return 1 + fi + + # Check for data mount entry + if grep -q "^/dev/mapper/data /data " mtab_output.txt; then + log "Data mount entry found in /etc/mtab!" + else + log "/data mount entry NOT found in /etc/mtab." + log "Current mtab entries:" + cat mtab_output.txt + return 1 + fi + + # Check for rootfs device mapper volume + if grep -q "^rootfs$" dev_mapper_output.txt; then + log "Rootfs device mapper volume found!" + else + log "Rootfs device mapper volume NOT found." + log "Current /dev/mapper contents:" + cat dev_mapper_output.txt + return 1 + fi + + # Check for data device mapper volume + if grep -q "^data$" dev_mapper_output.txt; then + log "Data device mapper volume found!" + else + log "Data device mapper volume NOT found." + log "Current /dev/mapper contents:" + cat dev_mapper_output.txt + return 1 + fi + + log "All mount entries and device mapper volumes verified successfully!" + return 0 + else + warn "QEMU monitor socket not available, skipping mount and device mapper checks" + return 0 + fi +} + +# Test container functionality by installing podman and running a simple container +test_container_functionality() { + log "Testing container functionality..." + + if [[ -S "qemu-monitor.sock" ]]; then + log "Installing podman and running test container..." + + # Install podman + echo -e "human-monitor-command {\"command-line\":\"yum install -y podman\"}\nquit" | socat - UNIX-CONNECT:qemu-monitor.sock >podman_install_output.txt 2>/dev/null + sleep 10 + + # Run test container with echo command + echo -e "human-monitor-command {\"command-line\":\"podman run --rm ghcr.io/linuxcontainers/alpine:latest echo 'Hello from container!'\"}\nquit" | socat - UNIX-CONNECT:qemu-monitor.sock >container_test_output.txt 2>/dev/null + sleep 5 + + # Check if the container ran successfully + if grep -q "Hello from container!" container_test_output.txt; then + log "Container test passed successfully!" + return 0 + else + log "Container test failed." + log "Container test output:" + cat container_test_output.txt + return 1 + fi + else + warn "QEMU monitor socket not available, skipping container functionality test" + return 0 + fi +} + +# Start QEMU with the encrypted image (Local mode) +start_qemu_local() { + log "Starting QEMU with encrypted image (Local mode)..." + + # Find appropriate QEMU command + find_qemu + + # Start QEMU with a simplified configuration for testing + log "Starting QEMU - Press Ctrl+A then X to exit" + $QEMU_CMD \ + -m 2048M \ + -smp 2 \ + -nographic \ + -serial mon:stdio \ + -drive file="${ENCRYPTED_IMAGE_NAME}",format=qcow2,if=virtio,id=hd0,readonly=off +} + +# Calculate reference values for the encrypted disk +calculate_reference_values() { + log "Calculating reference values for encrypted disk..." + + # Check if cryptpilot is available + if ! command -v cryptpilot >/dev/null 2>&1; then + error "cryptpilot command not found" + fi + + # Calculate reference values + log "Generating reference values using cryptpilot..." + if cryptpilot fde show-reference-value --stage initrd --disk "${ENCRYPTED_IMAGE_NAME}" > reference-value.json; then + log "Reference values calculated and saved to reference-value.json" + else + error "Failed to calculate reference values" + fi + + # Display reference values + log "Reference values:" + cat reference-value.json + + # Register reference values with Trustee service + log "Registering reference values with Trustee service..." + local provenance + provenance=$(cat ./reference-value.json | base64 --wrap=0) + + cat << EOF > ./register-request.json +{ + "version" : "0.1.0", + "type": "sample", + "payload": "$provenance" +} +EOF + + if command -v rvps-tool >/dev/null 2>&1; then + if rvps-tool register --path ./register-request.json; then + log "Reference values registered successfully with Trustee service" + else + warn "Failed to register reference values with Trustee service" + fi + else + warn "rvps-tool not found, skipping reference value registration" + fi +} + +# Main execution +main() { + if [ "$(id -u)" != "0" ]; then + log::error "This script must be run as root" + exit 1 + fi + + parse_args "$@" + + # Determine mode if not explicitly set + if [[ "$CI_MODE" == false && "$LOCAL_MODE" == false && "$DOWNLOAD_ONLY" == false && "$ENCRYPT_ONLY" == false ]]; then + # Default to CI mode + CI_MODE=true + fi + + log "Starting unified test script for system disk encryption" + + # Handle download-only mode + if [[ "$DOWNLOAD_ONLY" == true ]]; then + download_image + log "Download-only mode completed successfully!" + exit 0 + fi + + # Handle encrypt-only mode + if [[ "$ENCRYPT_ONLY" == true ]]; then + setup_config + encrypt_image + log "Encrypt-only mode completed successfully!" + exit 0 + fi + + # Setup config for other modes + setup_config + + # Download images or use existing ones + download_image + + # 使用virt-customize设置root密码 + set_root_password + + # Encrypt image + encrypt_image + + # Calculate reference values + # TODO: fix the udevadm problem by changing to guestmount https://github.com/openanolis/cryptpilot/actions/runs/17576971966/job/49925051838?pr=21 + # calculate_reference_values + + # Handle CI mode + if [[ "$CI_MODE" == true ]]; then + start_qemu_ci + verify_boot + check_mount_entries + test_container_functionality + log "CI mode test completed successfully!" + log "System disk encryption verification passed!" + fi + + # Handle local mode + if [[ "$LOCAL_MODE" == true ]]; then + start_qemu_local + log "Local mode test completed!" + fi +} + +# Set root password using virt-customize +set_root_password() { + log "Setting root password using virt-customize..." + + # Check if virt-customize is available + if ! command -v virt-customize >/dev/null 2>&1; then + error "virt-customize not found. Please install libguestfs-tools package." + fi + + # Use virt-customize to set root password to root + virt-customize -a "${IMAGE_NAME}" --root-password password:root || error "Failed to set root password" + + log "Root password set successfully" +} + +# Run main function +main "$@" diff --git a/scripts/test/test-volume-encryption.sh b/scripts/test/test-volume-encryption.sh new file mode 100755 index 0000000..41f4d16 --- /dev/null +++ b/scripts/test/test-volume-encryption.sh @@ -0,0 +1,331 @@ +#!/bin/bash + +# Test script for KBS volume encryption with cryptpilot +# This script tests the KBS credential provider for data volume encryption + +set -e # Exit on any error + +TRUSTEE_URL="http://127.0.0.1:8081/api/" # Trustee service URL + +# Function to check and install required commands +check_and_install_commands() { + local missing_commands=() + local install_commands=() + + # List of required commands and their packages (for RHEL/CentOS) + local commands_and_packages=( + "losetup:util-linux" + "mount:util-linux" + "umount:util-linux" + ) + + # Check which commands are missing + for item in "${commands_and_packages[@]}"; do + local cmd="${item%%:*}" + local pkg="${item#*:}" + + if ! command -v "$cmd" >/dev/null 2>&1; then + missing_commands+=("$cmd") + install_commands+=("$pkg") + fi + done + + # If there are missing commands, try to install them + if [ ${#missing_commands[@]} -gt 0 ]; then + echo "Missing required commands: ${missing_commands[*]}" + + echo "Attempting to install missing packages with yum..." + if ! yum install -y "${install_commands[@]}"; then + echo "Failed to install packages with yum. Please install the following packages manually:" + echo "${install_commands[*]}" + exit 1 + fi + fi + + echo "All required commands are available." +} + +# Default configuration +CONFIG_DIR="test-kbs-config" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Help message +show_help() { + cat </dev/null || true + fi + + [[ -f "test-disk.img" ]] && rm -f "test-disk.img" + [[ -d "/tmp/kbs-test-mount" ]] && rmdir /tmp/kbs-test-mount 2>/dev/null || true + else + log "Keeping test files as requested" + fi +} + +trap cleanup EXIT + +# Setup config directory for KBS volume +setup_config() { + log "Setting up cryptpilot config for KBS volume..." + mkdir -p "${CONFIG_DIR}/volumes" + + # Create a KBS volume config (using mock values for CI) + cat >"${CONFIG_DIR}/volumes/kbs-test.toml" </dev/null || true + fi + + # Set up loop device (try different numbers if /dev/loop99 is busy) + LOOP_DEV=$(losetup --find) + + if [[ -z "$LOOP_DEV" ]]; then + error "Failed to found a free loop device" + fi + + if ! losetup -P "$LOOP_DEV" test-disk.img 2>/dev/null; then + error "Failed to set up loop device" + fi + + # Wait for partition to be ready + sleep 2 + + log "Test disk created: $LOOP_DEV" +} + +# Test volume initialization +test_volume_init() { + log "Initializing KBS volume..." + + # check if trustee is still running + yum install -y iproute + ps -ef + + ss --tcp -n --listening + + # Initialize the volume + if ! cryptpilot init kbs-test -c "${CONFIG_DIR}" -y; then + echo "Failed to initialize volume." + + cat /tmp/trustee-gateway.log + + # check again trustee is still running + ps -ef + + ss --tcp -n --listening + + return 1 + fi + + log "Volume initialized successfully" +} + +# Test volume opening +test_volume_open() { + log "Opening KBS volume..." + + # Open the volume + if ! cryptpilot open kbs-test -c "${CONFIG_DIR}"; then + echo "Failed to open volume." + return 1 + fi + + # Check if the device mapper device exists + if [[ ! -b "/dev/mapper/kbs-test" ]]; then + echo "Device mapper device /dev/mapper/kbs-test not found" + return 1 + fi + + log "Volume opened successfully" +} + +# Test volume show +test_volume_show() { + log "Showing volume status..." + + # Show volume status + if ! cryptpilot show -c "${CONFIG_DIR}"; then + echo "Failed to show volume status." + return 1 + fi + + log "Volume status verified successfully" +} + +# Test filesystem operations +test_filesystem_ops() { + log "Testing filesystem operations..." + + # Create mount point + mkdir -p /tmp/kbs-test-mount + + # Mount the volume + if ! mount /dev/mapper/kbs-test /tmp/kbs-test-mount; then + error "Failed to mount volume" + fi + + # Test writing and reading a file + echo "test content" | tee /tmp/kbs-test-mount/test-file >/dev/null + if [[ ! -f "/tmp/kbs-test-mount/test-file" ]]; then + error "Failed to create test file" + fi + + content=$(cat /tmp/kbs-test-mount/test-file) + if [[ "$content" != "test content" ]]; then + error "File content mismatch" + fi + + # Unmount the volume + umount /tmp/kbs-test-mount + + log "Filesystem operations tested successfully" +} + +# Test volume closing +test_volume_close() { + log "Closing KBS volume..." + + # Close the volume + if ! cryptpilot close kbs-test -c "${CONFIG_DIR}"; then + echo "Failed to close volume." + return 1 + fi + + # Check that the device mapper device no longer exists + if [[ -b "/dev/mapper/kbs-test" ]]; then + echo "Device mapper device /dev/mapper/kbs-test still exists after closing" + return 1 + fi + + log "Volume closed successfully" +} + +# Main execution +main() { + if [ "$(id -u)" != "0" ]; then + log::error "This script must be run as root" + exit 1 + fi + + parse_args "$@" + + # Check and install required commands + check_and_install_commands + + log "Starting KBS volume encryption test" + + # Create test disk + create_test_disk + + # Setup config + setup_config + + # Test volume operations + if ! test_volume_init; then + error "Volume initialization failed" + fi + + if ! test_volume_open; then + error "Volume opening failed" + fi + + if ! test_volume_show; then + error "Volume show failed" + fi + + if ! test_filesystem_ops; then + error "Filesystem operations failed" + fi + + if ! test_volume_close; then + error "Volume closing failed" + fi + + log "KBS volume encryption test completed successfully!" +} + +# Run main function +main "$@"