Polish the docs and usage for the encrypted image

This commit is contained in:
LI Qing 2021-03-09 17:37:39 +08:00 committed by Zongmin.Gu
parent 5db07a2029
commit d81511ec8c
8 changed files with 62 additions and 28 deletions

@ -40,9 +40,9 @@ jobs:
- name: C with encrypted image test - name: C with encrypted image test
run: docker exec language_support_test bash -c "cd /root/occlum/demos/hello_c && make; run: docker exec language_support_test bash -c "cd /root/occlum/demos/hello_c && make;
rm -rf occlum_instance && occlum new occlum_instance; rm -rf occlum_instance && occlum new occlum_instance;
echo \"ff-2a-f9-29-ce-6d-95-04-93-70-6e-83-64-1b-d6-0c\" > occlum_instance/image_key; occlum gen-image-key occlum_instance/image_key;
cp hello_world occlum_instance/image/bin; cp hello_world occlum_instance/image/bin;
cd occlum_instance && SGX_MODE=SIM occlum build --image-key ./image_key; cd occlum_instance && SGX_MODE=SIM occlum build --image-key ./image_key --buildin-image-key;
occlum run /bin/hello_world" occlum run /bin/hello_world"
- name: C++ test - name: C++ test

@ -184,9 +184,9 @@ jobs:
- name: C with encrypted image test - name: C with encrypted image test
run: docker exec $language_support_test bash -c "cd /root/occlum/demos/hello_c && make; run: docker exec $language_support_test bash -c "cd /root/occlum/demos/hello_c && make;
rm -rf occlum_instance && occlum new occlum_instance; rm -rf occlum_instance && occlum new occlum_instance;
echo \"ff-2a-f9-29-ce-6d-95-04-93-70-6e-83-64-1b-d6-0c\" > occlum_instance/image_key; occlum gen-image-key occlum_instance/image_key;
cp hello_world occlum_instance/image/bin; cp hello_world occlum_instance/image/bin;
cd occlum_instance && occlum build --image-key ./image_key; cd occlum_instance && occlum build --image-key ./image_key --buildin-image-key;
occlum run /bin/hello_world" occlum run /bin/hello_world"
- name: C++ test - name: C++ test

@ -48,7 +48,7 @@ The `occlum init` command creates the compile-time and run-time state of Occlum
$ cp ../hello_world image/bin/ $ cp ../hello_world image/bin/
$ occlum build $ occlum build
``` ```
The content of the `image` directory is initialized by the `occlum init` command. The structure of the `image` directory mimics that of an ordinary UNIX FS, containing directories like `/bin`, `/lib`, `/root`, `/tmp`, etc. After copying the user program `hello_world` into `image/bin/`, the `image` directory is packaged by the `occlum build` command to generate a secure Occlum FS image as well as the Occlum SGX enclave. The content of the `image` directory is initialized by the `occlum init` command. The structure of the `image` directory mimics that of an ordinary UNIX FS, containing directories like `/bin`, `/lib`, `/root`, `/tmp`, etc. After copying the user program `hello_world` into `image/bin/`, the `image` directory is packaged by the `occlum build` command to generate a secure Occlum FS image as well as the Occlum SGX enclave. The FS image is integrity protected by default, if you want to protect the confidentiality and integrity with your own key, please check out [here](docs/encrypted_image.md).
For platforms that don't support SGX, it is also possible to run Occlum in SGX simulation mode. To switch to the simulation mode, `occlum build` command must be given an extra argument or an environment variable as shown below: For platforms that don't support SGX, it is also possible to run Occlum in SGX simulation mode. To switch to the simulation mode, `occlum build` command must be given an extra argument or an environment variable as shown below:
``` ```

9
docs/encrypted_image.md Normal file

@ -0,0 +1,9 @@
# The Encrypted FS Image
Since 0.21.1, Occlum has supported using an encrypted FS image, which is encrypted by a user-provided key, to run apps inside the enclave. The confidentiality and integrity of user's files and libraries are both protected with it.
## How to use
To generate the encrypted FS image, user must give the `--image-key <key_path>` flag in the `occlum build` command (If the flag is not given, the secure FS image will be integrity protected only). The `<key_path>` refers to a file consisting of a 128-bit key and the user can generate it via the `occlum gen-image-key <key_path>` command.
If user also gives the `--buildin-image-key` flag in the `occlum build` command, the key file will be packaged into the initfs after building the Occlum instance. The initfs is an integrity-only protected FS image, which is used by the [init](../tools/init) program to mount the encrypted FS image as the rootfs for the user's apps.
To use this feature in real world, user must ***NOT*** give the `--buildin-image-key` flag in the `occlum build` command, and modify the [init](../tools/init) program to acquire the key through RA or LA. We would remove the `--buildin-image-key` flag when the "init-RA" demo is ready.

@ -22,9 +22,9 @@ To mount an Occlum's secure FS image successfully, three conditions must be sati
1. The secure FS image exists and is not being used (e.g., via the `occlum run` or `occlum mount` command). This condition ensures that the secure FS will not be broken due to the concurrent access of different Occlum commands. 1. The secure FS image exists and is not being used (e.g., via the `occlum run` or `occlum mount` command). This condition ensures that the secure FS will not be broken due to the concurrent access of different Occlum commands.
2. The two (optional) sign key and sign tool arguments that are given to the `occlum mount` command must have the same values as those given to the `occlum build` command, which is how the image is created in the first place. This ensures that the secure FS can only be accessed by the owner of the enclave. 2. The three (optional) sign key, sign tool and image key arguments that are given to the `occlum mount` command must have the same values as those given to the `occlum build` command, which is how the image is created in the first place. This ensures that the secure FS can only be accessed by the owner of the enclave.
3. The `occlum mount` command must be run on the same machine as the `occlum run` command that runs the current Occlum instance and writes to the image. This condition is due to the fact that the encryption key of the secure FS is bound to the machine. 3. If the image key is not given to the `occlum build` command, the `occlum mount` command must be run on the same machine as the `occlum run` command that runs the current Occlum instance and writes to the image. This condition is due to the fact that the encryption key of the secure FS is bound to the machine.
With the three conditions satisfied, the mount command is able to start a Linux FUSE FS server. Any I/O operations on the FUSE FS mounted at the specified path will be redirected by Linux kernel as I/O requests to the FUSE server. The FUSE server is backed by a special enclave, which can encrypt or decrypt the content of the secure FS image on demand. With the three conditions satisfied, the mount command is able to start a Linux FUSE FS server. Any I/O operations on the FUSE FS mounted at the specified path will be redirected by Linux kernel as I/O requests to the FUSE server. The FUSE server is backed by a special enclave, which can encrypt or decrypt the content of the secure FS image on demand.

@ -22,14 +22,18 @@ fn main() -> Result<(), Box<dyn Error>> {
}; };
let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t; let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t;
// Get the key of encrypted SEFS image if exists // Get the key of FS image if needed
let key = match image_config.key { let key = match &image_config.image_type[..] {
Some(key_str) => { "encrypted" => {
// TODO: Get the key through RA or LA
const IMAGE_KEY_FILE: &str = "/etc/image_key";
let key_str = load_key(IMAGE_KEY_FILE)?;
let mut key: sgx_key_128bit_t = Default::default(); let mut key: sgx_key_128bit_t = Default::default();
parse_str_to_bytes(&key_str, &mut key)?; parse_str_to_bytes(&key_str, &mut key)?;
Some(key) Some(key)
} }
None => None, "integrity-only" => None,
_ => unreachable!(),
}; };
let key_ptr = key let key_ptr = key
.as_ref() .as_ref()
@ -55,8 +59,7 @@ type sgx_aes_gcm_128bit_tag_t = [u8; 16];
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct ImageConfig { struct ImageConfig {
occlum_json_mac: String, occlum_json_mac: String,
#[serde(default)] image_type: String,
key: Option<String>,
} }
fn load_config(config_path: &str) -> Result<ImageConfig, Box<dyn Error>> { fn load_config(config_path: &str) -> Result<ImageConfig, Box<dyn Error>> {
@ -70,6 +73,13 @@ fn load_config(config_path: &str) -> Result<ImageConfig, Box<dyn Error>> {
Ok(config) Ok(config)
} }
fn load_key(key_path: &str) -> Result<String, Box<dyn Error>> {
let mut key_file = File::open(key_path)?;
let mut key = String::new();
key_file.read_to_string(&mut key)?;
Ok(key.trim_end_matches(|c| c == '\r' || c == '\n').to_string())
}
fn parse_str_to_bytes(arg_str: &str, bytes: &mut [u8]) -> Result<(), Box<dyn Error>> { fn parse_str_to_bytes(arg_str: &str, bytes: &mut [u8]) -> Result<(), Box<dyn Error>> {
let bytes_str_vec = { let bytes_str_vec = {
let bytes_str_vec: Vec<&str> = arg_str.split('-').collect(); let bytes_str_vec: Vec<&str> = arg_str.split('-').collect();

@ -52,16 +52,11 @@ Usage:
occlum init occlum init
Initialize a directory as the Occlum instance. Initialize a directory as the Occlum instance.
occlum build [--sign-key <key_path>] [--sign-tool <tool_path>] [--image-key <key_path>] [--no-buildin-image-config] [-f/--force] occlum build [--sign-key <key_path>] [--sign-tool <tool_path>] [--image-key <key_path>] [--buildin-image-key] [-f/--force]
Build and sign an Occlum SGX enclave (.so) and generate its associated secure Build and sign an Occlum SGX enclave (.so) and generate its associated secure
FS image according to the user-provided image directory and Occlum.json config file. FS image according to the user-provided image directory and Occlum.json config file.
The whole building process is incremental: the building artifacts are built only The whole building process is incremental: the building artifacts are built only
when needed. when needed.
A Configuration file (i.e., image_config.json) consists of the MAC of Occlum.json and
the key (if provided) of the secure FS image will be built into the initfs by default,
the init program can use it to mount the secure FS image as the rootfs.
To protect the security of FS image, give the [--no-buildin-image-config] flag,
and modifies the init program to acquire the MAC and key with LA or RA.
To force rebuilding all artifacts, give the [-f/--force] flag. To force rebuilding all artifacts, give the [-f/--force] flag.
occlum run <program_name> <program_args> occlum run <program_name> <program_args>
@ -81,6 +76,9 @@ Usage:
occlum mount [--sign-key <key_path>] [--sign-tool <tool_path>] [--image-key <key_path>] <path> occlum mount [--sign-key <key_path>] [--sign-tool <tool_path>] [--image-key <key_path>] <path>
Mount the secure FS image of the Occlum instance as a Linux FS at an existing <path>. Mount the secure FS image of the Occlum instance as a Linux FS at an existing <path>.
This makes it easy to access and manipulate Occlum's secure FS for debug purpose. This makes it easy to access and manipulate Occlum's secure FS for debug purpose.
occlum gen-image-key <key_path>
Generate a file consists of a randomly generated 128-bit key for encryption of the FS image.
EOF EOF
} }
@ -231,7 +229,7 @@ cmd_build() {
pal_lib=libocclum-pal.so pal_lib=libocclum-pal.so
libos_lib=libocclum-libos.so libos_lib=libocclum-libos.so
BUILDIN_IMAGE_CONF=true BUILDIN_IMAGE_KEY=false
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
@ -239,7 +237,7 @@ cmd_build() {
--sign-tool) [ -n "$2" ] && ENCLAVE_SIGN_TOOL=$2 ; shift 2 || exit_error "empty signing tool path" ;; --sign-tool) [ -n "$2" ] && ENCLAVE_SIGN_TOOL=$2 ; shift 2 || exit_error "empty signing tool path" ;;
--sgx-mode) [[ -n "$2" && "$2" != "HW" ]] && export SGX_MODE=SIM ; shift 2 || exit_error "empty sgx mode";; --sgx-mode) [[ -n "$2" && "$2" != "HW" ]] && export SGX_MODE=SIM ; shift 2 || exit_error "empty sgx mode";;
--image-key) [ -n "$2" ] && SECURE_IMAGE_KEY=$2 ; shift 2 || exit_error "empty secure image key path" ;; --image-key) [ -n "$2" ] && SECURE_IMAGE_KEY=$2 ; shift 2 || exit_error "empty secure image key path" ;;
--no-buildin-image-config) BUILDIN_IMAGE_CONF=false ; shift ;; --buildin-image-key) BUILDIN_IMAGE_KEY=true ; shift ;;
--force | -f) MAKE_OPTION="--always-make" ; shift ;; --force | -f) MAKE_OPTION="--always-make" ; shift ;;
*) exit_error "Unknown option: $1" ;; *) exit_error "Unknown option: $1" ;;
esac esac
@ -279,7 +277,7 @@ cmd_build() {
occlum_dir=$occlum_dir instance_dir=$instance_dir pal_lib=$pal_lib major_ver=$major_ver \ occlum_dir=$occlum_dir instance_dir=$instance_dir pal_lib=$pal_lib major_ver=$major_ver \
occlum_version=$occlum_version libos_lib=$libos_lib \ occlum_version=$occlum_version libos_lib=$libos_lib \
ENCLAVE_SIGN_KEY=$ENCLAVE_SIGN_KEY ENCLAVE_SIGN_TOOL=$ENCLAVE_SIGN_TOOL \ ENCLAVE_SIGN_KEY=$ENCLAVE_SIGN_KEY ENCLAVE_SIGN_TOOL=$ENCLAVE_SIGN_TOOL \
SECURE_IMAGE_KEY=$SECURE_IMAGE_KEY BUILDIN_IMAGE_CONF=$BUILDIN_IMAGE_CONF \ SECURE_IMAGE_KEY=$SECURE_IMAGE_KEY BUILDIN_IMAGE_KEY=$BUILDIN_IMAGE_KEY \
make -f $build_makefile $MAKE_OPTION make -f $build_makefile $MAKE_OPTION
cd "$instance_dir" cd "$instance_dir"
@ -497,6 +495,19 @@ cmd_status() {
cat "$status_file" cat "$status_file"
} }
cmd_gen_image_key() {
if [ -z $@ ]; then
echo "Error: target file is not set"
exit 1
fi
key_path="$@"
if [[ "$key_path" != "/"* ]]; then
key_path="$instance_dir/$@"
fi
cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 32 | head -n 1 | sed -r 's/.{2}/&-/g; s/.$//' > $key_path
}
set -e set -e
if [[ ( "$#" < 1 ) ]] ; then if [[ ( "$#" < 1 ) ]] ; then
@ -539,6 +550,9 @@ case "$cmd" in
status) status)
cmd_status cmd_status
;; ;;
gen-image-key)
cmd_gen_image_key "${@:2:1}"
;;
*) *)
report_arg_error "Error: unknown sub-command $cmd" report_arg_error "Error: unknown sub-command $cmd"
exit 1 exit 1

@ -96,9 +96,10 @@ $(INITFS_IMAGE): $(INITFS) $(INITFS_DIRS) $(INITFS_FILES) $(IMAGE_CONFIG_JSON) $
@echo "Building the initfs..." @echo "Building the initfs..."
@rm -rf build/initfs @rm -rf build/initfs
@mkdir -p build/initfs @mkdir -p build/initfs
@[ "$(BUILDIN_IMAGE_CONF)" == "true" ] && \ @[ "$(BUILDIN_IMAGE_KEY)" == "true" ] && \
cp "$(IMAGE_CONFIG_JSON)" "$(INITFS)/etc/" || \ cp "$(SECURE_IMAGE_KEY)" "$(INITFS)/etc/image_key" || \
rm -f "$(INITFS)/etc/`basename $(IMAGE_CONFIG_JSON)`" rm -f "$(INITFS)/etc/image_key"
@cp "$(IMAGE_CONFIG_JSON)" "$(INITFS)/etc/"
@LD_LIBRARY_PATH="$(SGX_SDK)/sdk_libs" $(SEFS_CLI_SIM) \ @LD_LIBRARY_PATH="$(SGX_SDK)/sdk_libs" $(SEFS_CLI_SIM) \
--enclave "$(SIGNED_SEFS_CLI_LIB)" \ --enclave "$(SIGNED_SEFS_CLI_LIB)" \
zip \ zip \
@ -110,10 +111,10 @@ $(IMAGE_CONFIG_JSON): $(instance_dir)/build/Occlum.json.protected
@export OCCLUM_CONF_FILE_MAC=`$(get_occlum_user_conf_file_mac)` ; \ @export OCCLUM_CONF_FILE_MAC=`$(get_occlum_user_conf_file_mac)` ; \
echo "EXPORT => OCCLUM_CONF_FILE_MAC = $$OCCLUM_CONF_FILE_MAC" ; \ echo "EXPORT => OCCLUM_CONF_FILE_MAC = $$OCCLUM_CONF_FILE_MAC" ; \
[ -n "$(SECURE_IMAGE_KEY)" ] && \ [ -n "$(SECURE_IMAGE_KEY)" ] && \
jq -n --arg mac_val "$$OCCLUM_CONF_FILE_MAC" --arg key_val "`cat $(SECURE_IMAGE_KEY)`" \
'{occlum_json_mac: $$mac_val, key: $$key_val}' > $(IMAGE_CONFIG_JSON) || \
jq -n --arg mac_val "$$OCCLUM_CONF_FILE_MAC" \ jq -n --arg mac_val "$$OCCLUM_CONF_FILE_MAC" \
'{occlum_json_mac: $$mac_val}' > $(IMAGE_CONFIG_JSON) '{image_type: "encrypted", occlum_json_mac: $$mac_val}' > $(IMAGE_CONFIG_JSON) || \
jq -n --arg mac_val "$$OCCLUM_CONF_FILE_MAC" \
'{image_type: "integrity-only", occlum_json_mac: $$mac_val}' > $(IMAGE_CONFIG_JSON)
$(instance_dir)/build/Occlum.json.protected: $(instance_dir)/build/Occlum.json $(instance_dir)/build/Occlum.json.protected: $(instance_dir)/build/Occlum.json
@cd "$(instance_dir)/build" ; \ @cd "$(instance_dir)/build" ; \