-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cdh/docs: add document for secure mount with block devices
add document for secure mount with block devices. Signed-off-by: ChengyuZhu6 <[email protected]>
- Loading branch information
Showing
3 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
confidential-data-hub/docs/use-cases/secure-mount-with-block-device.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Secure mount with Block Device | ||
|
||
This guide helps an user to use confidential data hub to secure mount inside TEE environment. | ||
|
||
## Preliminaries | ||
|
||
- Ensure that [cryptsetup](https://gitlab.com/cryptsetup/cryptsetup/) is installed. | ||
|
||
## Example | ||
|
||
### Create a loop device | ||
|
||
```shell | ||
$ loop_file="/tmp/test.img" | ||
$ sudo dd if=/dev/zero of=$loop_file bs=1M count=1000 | ||
$ sudo losetup -fP $loop_file | ||
$ device=$(sudo losetup -j $loop_file | awk -F'[: ]' '{print $1}') | ||
$ echo $device | ||
# Output should be something like /dev/loop0 | ||
$ device_num=$(sudo lsblk -no MAJ:MIN $device) | ||
$ echo $device_num | ||
# Output should be something like 7:0 | ||
``` | ||
|
||
### Secure mount inside a TEE environment | ||
|
||
1. Build the CDH and its client tool | ||
|
||
Follow the instructions in the [CDH README](../../README.md#confidential-data-hub) and [Client Tool README](../../README.md#client-tool) to build the CDH and its client tool. | ||
|
||
2. Install `luks-encrypt-storage` | ||
|
||
Install [luks-encrypt-storage](../../storage/scripts/luks-encrypt-storage) into `/usr/local/bin` | ||
|
||
3. Run CDH | ||
```shell | ||
$ confidential-data-hub | ||
``` | ||
|
||
4. Prepare a request JSON `storage.json` | ||
```json | ||
{ | ||
{ | ||
"volume_type": "BlockDevice", | ||
"options": { | ||
"deviceId": "7:0", | ||
"encryptType": "LUKS", | ||
"dataIntegrity": "true" | ||
}, | ||
"flags": [], | ||
"mount_point": "/mnt/test-path" | ||
} | ||
} | ||
|
||
``` | ||
- Fields: | ||
- `volume_type`: The secure mount plugin type name. It determines how the rest of the fields are used. | ||
- `options`: A key-value map specifying the settings for the mount operation. Different plugins can define different keys in the options. In this example, all keys are for block devices. | ||
- `flags`: A string list specifying settings for the mount operation. Different plugins can define different uses for this field. | ||
- `mount_point`: The target mount path for the operation. | ||
|
||
- Options Fields: | ||
- `deviceId`: The device number, formatted as "MAJ:MIN". | ||
- `encryptType`: The encryption type. Currently, only LUKS is supported. | ||
- `encryptKey`: Encryption key. It can be a sealed secret or a resource uri. If not set, it means that the device is unencrypted and a random 4096-byte key will be generated to encrypt the device. | ||
- `dataIntegrity`: Enables dm-integrity to protect data integrity. Note that enabling data integrity will reduce IO performance by more than 30%. | ||
|
||
5. Make a request to CDH | ||
```shell | ||
$ client-tool secure-mount --storage-path storage.json | ||
|
||
# Check the target path to see if the mount succeeded | ||
$ lsblk |grep "encrypted_disk" | ||
# Expected output: | ||
└─encrypted_disk_OEyEj_dif 253:1 0 968.6M 0 crypt | ||
└─encrypted_disk_OEyEj 253:2 0 968.6M 0 crypt /mnt/test-path | ||
``` |
149 changes: 149 additions & 0 deletions
149
confidential-data-hub/storage/scripts/luks-encrypt-storage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#!/bin/bash | ||
# | ||
# Copyright (c) 2022 Intel Corporation | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
|
||
set -o errexit | ||
set -o nounset | ||
set -o pipefail | ||
set -o errtrace | ||
|
||
[ -n "${DEBUG:-}" ] && set -o xtrace | ||
|
||
handle_error() { | ||
local exit_code="${?}" | ||
local line_number="${1:-}" | ||
echo "error:" | ||
echo "Failed at $line_number: ${BASH_COMMAND}" | ||
exit "${exit_code}" | ||
} | ||
trap 'handle_error $LINENO' ERR | ||
|
||
die() | ||
{ | ||
local msg="$*" | ||
echo >&2 "ERROR: $msg" | ||
exit 1 | ||
} | ||
|
||
setup() | ||
{ | ||
local cmds=() | ||
|
||
cmds+=("cryptsetup" "mkfs.ext4" "mount") | ||
|
||
local cmd | ||
for cmd in "${cmds[@]}" | ||
do | ||
command -v "$cmd" &>/dev/null || die "need command: '$cmd'" | ||
done | ||
} | ||
|
||
setup | ||
|
||
device_num=${1:-} | ||
if [ -z "$device_num" ]; then | ||
die "invalid arguments, at least one param for device num" | ||
fi | ||
|
||
is_encrypted="false" | ||
if [ -n "${2-}" ]; then | ||
is_encrypted="$2" | ||
fi | ||
|
||
mount_point="/tmp/target_path" | ||
if [ -n "${3-}" ]; then | ||
mount_point="$3" | ||
fi | ||
|
||
storage_key_path="/run/encrypt_storage.key" | ||
if [ -n "${4-}" ]; then | ||
storage_key_path="$4" | ||
fi | ||
|
||
data_integrity="true" | ||
if [ -n "${5-}" ]; then | ||
data_integrity="$5" | ||
fi | ||
|
||
device_name=$(sed -e 's/DEVNAME=//g;t;d' "/sys/dev/block/${device_num}/uevent") | ||
device_path="/dev/$device_name" | ||
|
||
opened_device_name=$(mktemp "encrypted_disk_XXXXX") | ||
|
||
if [[ -n "$device_name" && -b "$device_path" ]]; then | ||
|
||
if [ "$is_encrypted" == "false" ]; then | ||
|
||
if [ "$data_integrity" == "false" ]; then | ||
echo "YES" | cryptsetup luksFormat --type luks2 "$device_path" --sector-size 4096 \ | ||
--cipher aes-xts-plain64 "$storage_key_path" | ||
else | ||
# Wiping a device is a time consuming operation. To avoid a full wipe, integritysetup | ||
# and crypt setup provide a --no-wipe option. | ||
# However, an integrity device that is not wiped will have invalid checksums. Normally | ||
# this should not be a problem since a page must first be written to before it can be read | ||
# (otherwise the data would be arbitrary). The act of writing would populate the checksum | ||
# for the page. | ||
# However, tools like mkfs.ext4 read pages before they are written; sometimes the read | ||
# of an unwritten page happens due to kernel buffering. | ||
# See https://gitlab.com/cryptsetup/cryptsetup/-/issues/525 for explanation and fix. | ||
# The way to propery format the non-wiped dm-integrity device is to figure out which pages | ||
# mkfs.ext4 will write to and then to write to those pages before hand so that they will | ||
# have valid integrity tags. | ||
echo "YES" | cryptsetup luksFormat --type luks2 "$device_path" --sector-size 4096 \ | ||
--cipher aes-xts-plain64 --integrity hmac-sha256 "$storage_key_path" \ | ||
--integrity-no-wipe | ||
fi | ||
fi | ||
|
||
cryptsetup luksOpen -d "$storage_key_path" "$device_path" $opened_device_name | ||
rm "$storage_key_path" | ||
|
||
if [ "$data_integrity" == "false" ]; then | ||
mkfs.ext4 /dev/mapper/$opened_device_name -E lazy_journal_init | ||
else | ||
# mkfs.ext4 doesn't perform whole sector writes and this will cause checksum failures | ||
# with an unwiped integrity device. Therefore, first perform a dry run. | ||
output=$(mkfs.ext4 /dev/mapper/$opened_device_name -F -n) | ||
|
||
# The above command will produce output like | ||
# mke2fs 1.46.5 (30-Dec-2021) | ||
# Creating filesystem with 268435456 4k blocks and 67108864 inodes | ||
# Filesystem UUID: 4a5ff012-91c0-47d9-b4bb-8f83e830825f | ||
# Superblock backups stored on blocks: | ||
# 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, | ||
# 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, | ||
# 102400000, 214990848 | ||
delimiter="Superblock backups stored on blocks:" | ||
blocks_list=$([[ $output =~ $delimiter(.*) ]] && echo "${BASH_REMATCH[1]}") | ||
|
||
# Find list of blocks | ||
block_nums=$(echo "$blocks_list" | grep -Eo '[0-9]{4,}' | sort -n) | ||
|
||
# Add zero to list of blocks | ||
block_nums="0 $block_nums" | ||
|
||
# Iterate through each block and write to it to ensure that it has valid checksum | ||
for block_num in $block_nums | ||
do | ||
echo "Clearing page at $block_num" | ||
# Zero out the page | ||
dd if=/dev/zero bs=4k count=1 oflag=direct \ | ||
of=/dev/mapper/$opened_device_name seek="$block_num" | ||
done | ||
|
||
# Now perform the actual ext4 format. Use lazy_journal_init so that the journal is | ||
# initialized on demand. This is safe for ephemeral storage since we don't expect | ||
# ephemeral storage to survice a power cycle. | ||
mkfs.ext4 /dev/mapper/$opened_device_name -E lazy_journal_init | ||
fi | ||
|
||
[ ! -d "$mount_point" ] && mkdir -p $mount_point | ||
|
||
mount /dev/mapper/$opened_device_name $mount_point | ||
else | ||
die "Invalid device: '$device_path'" | ||
fi |