Add maa init demo
This commit is contained in:
parent
54de00a3bc
commit
5c10af738e
@ -10,6 +10,10 @@ This demo is programming in C, covering the SGX quote generation and format the
|
||||
|
||||
This demo is programming in RUST, based on the Azure provided [`REST APIs`](https://docs.microsoft.com/en-us/rest/api/attestation/). It provides steps to do SGX quote generation and attestation.
|
||||
|
||||
### MAA attestation in Occlum init stage [`maa_init`](./maa_init)
|
||||
|
||||
This demo bases on [`maa_attestation`](./maa_attestation), provides steps to do SGX quote generation and attestation in Occlum init process and save the attestation token to rootfs. With this flow, the real application loaded after Occlum init process may get the attestation token and do whatever it wants, without getting involved in the messy attestation part.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Platform
|
||||
|
@ -0,0 +1,53 @@
|
||||
## Sample code for doing Microsoft Azure Attestation in Occlum init
|
||||
|
||||
This demo is programming in RUST, based on the Azure provided [`REST APIs`](https://docs.microsoft.com/en-us/rest/api/attestation/). It provides steps to do SGX quote generation and attestation in Occlum init process and save the attestation token to rootfs.
|
||||
|
||||

|
||||
|
||||
### Flow
|
||||
|
||||
1. **`Occlum run`** to start the Occlum instance.
|
||||
|
||||
2. For every Occlum instance, it starts `init` process first, then starts the real application in RootFS. The default [`init`](../../../tools/init/) process just run RootFS integrity check and then load the RootFS where the real application is located. For this demo, a modified [`init`](./init/) is used. Besides the general `init` operation, it does Azure Attestation and saves the token to `/root/token` in RootFS where the real application can access.
|
||||
|
||||
3. The real application starts with easy access to the Azure Attestation token. The application can set its own strategy for the token. In this demo, a simple `busybox` as real application is used to print the content of attestation token obtained in init process.
|
||||
|
||||
### Environments
|
||||
|
||||
There are three environments below which are provided to users to modify according to the actual scenarios.
|
||||
|
||||
* **MAA_PROVIDER_URL**
|
||||
The MAA provider URL, this demo uses "https://shareduks.uks.attest.azure.net"
|
||||
In default.
|
||||
|
||||
* **MAA_REPORT_DATA**
|
||||
The report data (base64 encoded string) to be used for MAA quote generation.
|
||||
|
||||
* **MAA_TOKEN_PATH**
|
||||
The MAA token and raw quote saved path in rootfs which is `/root` in default. Thus applications could find the attestation response token and raw quote (base64 encoded) in `/root/token` and `/root/quote_base64`.
|
||||
|
||||
Please refer to the [`scrit`](./build.sh) for how to modify the above environments.
|
||||
|
||||
|
||||
* Build
|
||||
|
||||
1. Pull rust-sgx-sdk submodule which is the dependence of occlum dcap library.
|
||||
|
||||
```
|
||||
# cd occlum
|
||||
# git submodule update --init
|
||||
```
|
||||
|
||||
2. Do the build with the [`scrit`](./build.sh).
|
||||
|
||||
```
|
||||
# ./build.sh
|
||||
```
|
||||
|
||||
* Run
|
||||
```
|
||||
# cd occlum_instance
|
||||
# occlum run /bin/busybox cat /root/token
|
||||
```
|
||||
|
||||
If successful, it prints the Azure attestation token.
|
@ -0,0 +1,9 @@
|
||||
includes:
|
||||
- base.yaml
|
||||
targets:
|
||||
# copy busybox
|
||||
- target: /bin
|
||||
copy:
|
||||
- files:
|
||||
- /opt/occlum/toolchains/busybox/glibc/busybox
|
||||
|
46
demos/remote_attestation/azure_attestation/maa_init/build.sh
Executable file
46
demos/remote_attestation/azure_attestation/maa_init/build.sh
Executable file
@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
BLUE='\033[1;34m'
|
||||
NC='\033[0m'
|
||||
INSTANCE_DIR="occlum_instance"
|
||||
IMG_BOM="../bom.yaml"
|
||||
INIT_BOM="../init_maa.yaml"
|
||||
|
||||
function build() {
|
||||
pushd init
|
||||
cargo clean
|
||||
cargo build --release
|
||||
popd
|
||||
|
||||
echo "Generate example base64 encoded string as report data"
|
||||
openssl genrsa -out key.pem 2048
|
||||
report_data=$(base64 -w 0 key.pem)
|
||||
|
||||
rm -rf ${INSTANCE_DIR} && occlum new ${INSTANCE_DIR}
|
||||
pushd ${INSTANCE_DIR}
|
||||
|
||||
rm -rf image
|
||||
copy_bom -f ${IMG_BOM} --root image --include-dir /opt/occlum/etc/template
|
||||
|
||||
# Update env
|
||||
new_json="$(jq '.env.default += ["MAA_PROVIDER_URL=https://shareduks.uks.attest.azure.net"] |
|
||||
.env.default += ["MAA_TOKEN_PATH=/root"] |
|
||||
.env.default += ["MAA_REPORT_DATA=BASE64_STRING"]' Occlum.json)" && \
|
||||
echo "${new_json}" > Occlum.json
|
||||
|
||||
# Update report data string
|
||||
sed -i "s/BASE64_STRING/$report_data/g" Occlum.json
|
||||
|
||||
# prepare init maa content
|
||||
rm -rf initfs
|
||||
copy_bom -f ${INIT_BOM} --root initfs --include-dir /opt/occlum/etc/template
|
||||
|
||||
occlum build
|
||||
|
||||
popd
|
||||
}
|
||||
|
||||
build
|
||||
|
||||
|
1080
demos/remote_attestation/azure_attestation/maa_init/init/Cargo.lock
generated
Normal file
1080
demos/remote_attestation/azure_attestation/maa_init/init/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "init"
|
||||
version = "0.0.1"
|
||||
authors = ["LI Qing geding.lq@antgroup.com"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.84"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
base64 = "0.9"
|
||||
sha2 = "0.9.5"
|
||||
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
||||
occlum_dcap = { path = "../../../../../tools/toolchains/dcap_lib" }
|
||||
|
@ -0,0 +1,16 @@
|
||||
include ../../src/sgxenv.mk
|
||||
|
||||
SRC_FILES := $(shell find . -type f -name '*.rs') Cargo.toml
|
||||
RUST_TARGET_DIR := $(BUILD_DIR)/internal/tools/init/cargo-target
|
||||
RUST_OUT_DIR := $(BUILD_DIR)/bin
|
||||
TARGET_BINARY := $(RUST_OUT_DIR)/init
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(SRC_FILES)
|
||||
@RUSTC_BOOTSTRAP=1 occlum-cargo build --release --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR)
|
||||
@echo "CARGO (release) => init"
|
||||
|
||||
clean:
|
||||
@occlum-cargo clean --target-dir=$(RUST_TARGET_DIR)
|
||||
@-$(RM) -f $(TARGET_BINARY)
|
@ -0,0 +1,82 @@
|
||||
use serde_json::json;
|
||||
use sha2::{Digest, Sha256};
|
||||
use reqwest::blocking::Client;
|
||||
use occlum_dcap::*;
|
||||
|
||||
|
||||
pub const MAX_REPORT_DATA_SIZE: usize = 64;
|
||||
|
||||
fn maa_get_quote_base64(user_data: &[u8]) -> Result<String, &'static str> {
|
||||
let mut dcap = DcapQuote::new();
|
||||
let quote_size = dcap.get_quote_size();
|
||||
let mut quote_buf: Vec<u8> = vec![0; quote_size as usize];
|
||||
let mut report_data = sgx_report_data_t::default();
|
||||
|
||||
//fill in the report data array
|
||||
let len = {
|
||||
if user_data.len() > MAX_REPORT_DATA_SIZE {
|
||||
MAX_REPORT_DATA_SIZE
|
||||
} else {
|
||||
user_data.len()
|
||||
}
|
||||
};
|
||||
|
||||
for i in 0..len {
|
||||
report_data.d[i] = user_data[i];
|
||||
}
|
||||
|
||||
dcap.generate_quote(quote_buf.as_mut_ptr(), &mut report_data).unwrap();
|
||||
dcap.close();
|
||||
let quote = base64::encode("e_buf);
|
||||
|
||||
Ok(quote)
|
||||
}
|
||||
|
||||
pub fn maa_generate_json(user_data: &[u8]) -> Result<serde_json::Value, &'static str> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(user_data);
|
||||
let hash = hasher.finalize();
|
||||
|
||||
let quote_base64 = maa_get_quote_base64(&hash).unwrap();
|
||||
|
||||
// Format to MAA rest attestation API request body
|
||||
// https://docs.microsoft.com/en-us/rest/api/attestation/attestation/attest-sgx-enclave#request-body
|
||||
let mut maa_json: serde_json::Value = json!({
|
||||
"quote": "0",
|
||||
"runtimeData": {
|
||||
"data": "0",
|
||||
"dataType":"Binary"
|
||||
}
|
||||
});
|
||||
|
||||
*maa_json
|
||||
.pointer_mut("/quote")
|
||||
.unwrap() = serde_json::Value::String(quote_base64);
|
||||
|
||||
*maa_json
|
||||
.pointer_mut("/runtimeData/data")
|
||||
.unwrap() = serde_json::Value::String(base64::encode(&user_data));
|
||||
|
||||
Ok(maa_json.to_owned())
|
||||
}
|
||||
|
||||
|
||||
pub fn maa_attestation(url: String, request_body: serde_json::Value) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
|
||||
let client = Client::new();
|
||||
let att_url = format!("{}/attest/SgxEnclave?api-version=2020-10-01", url);
|
||||
|
||||
let resp = client.post(att_url)
|
||||
.json(&request_body)
|
||||
.send()?;
|
||||
|
||||
match resp.status() {
|
||||
reqwest::StatusCode::OK => {
|
||||
// println!("success!");
|
||||
Ok(resp.json().unwrap())
|
||||
},
|
||||
s => {
|
||||
println!("Received response status: {:?}", s);
|
||||
Err("maa attestation failed".into())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
extern crate libc;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
use libc::syscall;
|
||||
use serde::Deserialize;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::{write, File};
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::env;
|
||||
|
||||
use crate::maa::{maa_generate_json, maa_attestation};
|
||||
pub mod maa;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Load the configuration from initfs
|
||||
const IMAGE_CONFIG_FILE: &str = "/etc/image_config.json";
|
||||
let image_config = load_config(IMAGE_CONFIG_FILE)?;
|
||||
|
||||
// Get the MAC of Occlum.json.protected file
|
||||
let occlum_json_mac = {
|
||||
let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default();
|
||||
parse_str_to_bytes(&image_config.occlum_json_mac, &mut mac)?;
|
||||
mac
|
||||
};
|
||||
let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t;
|
||||
|
||||
// Get the key of FS image if needed
|
||||
let key = match &image_config.image_type[..] {
|
||||
"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();
|
||||
parse_str_to_bytes(&key_str, &mut key)?;
|
||||
Some(key)
|
||||
}
|
||||
"integrity-only" => None,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let key_ptr = key
|
||||
.as_ref()
|
||||
.map(|key| key as *const sgx_key_128bit_t)
|
||||
.unwrap_or(std::ptr::null());
|
||||
|
||||
// Do Azure attestation and save attestation json to rootfs
|
||||
// Get Attestation provider URL, rootfs token path and report data string from env
|
||||
let maa_provider_url = env::var("MAA_PROVIDER_URL")
|
||||
.unwrap_or("https://shareduks.uks.attest.azure.net".to_string());
|
||||
let maa_token_path = env::var("MAA_TOKEN_PATH")
|
||||
.unwrap_or("/root".to_string());
|
||||
let report_data_base64 = env::var("MAA_REPORT_DATA")
|
||||
.unwrap_or("example".to_string());
|
||||
let report_data = base64::decode(&report_data_base64).unwrap();
|
||||
|
||||
// Get maa quote json
|
||||
let maa_json = maa_generate_json(report_data.as_slice()).unwrap();
|
||||
let quote_base64 = serde_json::to_string(&maa_json["quote"]).unwrap();
|
||||
// Do maa attestation and get json token response
|
||||
let response = maa_attestation(maa_provider_url, maa_json).unwrap();
|
||||
let token = serde_json::to_string(&response).unwrap();
|
||||
|
||||
// Mount the image
|
||||
const SYS_MOUNT_FS: i64 = 363;
|
||||
let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, occlum_json_mac_ptr) };
|
||||
if ret < 0 {
|
||||
return Err(Box::new(std::io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
// Write the raw quote and json token to rootfs
|
||||
let quote_file = maa_token_path.clone() + "/quote_base64";
|
||||
write(quote_file, quote_base64)?;
|
||||
let token_file = maa_token_path.clone() + "/token";
|
||||
write(token_file, token)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
type sgx_key_128bit_t = [u8; 16];
|
||||
#[allow(non_camel_case_types)]
|
||||
type sgx_aes_gcm_128bit_tag_t = [u8; 16];
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct ImageConfig {
|
||||
occlum_json_mac: String,
|
||||
image_type: String,
|
||||
}
|
||||
|
||||
fn load_config(config_path: &str) -> Result<ImageConfig, Box<dyn Error>> {
|
||||
let mut config_file = File::open(config_path)?;
|
||||
let config_json = {
|
||||
let mut config_json = String::new();
|
||||
config_file.read_to_string(&mut config_json)?;
|
||||
config_json
|
||||
};
|
||||
let config: ImageConfig = serde_json::from_str(&config_json)?;
|
||||
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>> {
|
||||
let bytes_str_vec = {
|
||||
let bytes_str_vec: Vec<&str> = arg_str.split('-').collect();
|
||||
if bytes_str_vec.len() != bytes.len() {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"The length or format of Key/MAC string is invalid",
|
||||
)));
|
||||
}
|
||||
bytes_str_vec
|
||||
};
|
||||
|
||||
for (byte_i, byte_str) in bytes_str_vec.iter().enumerate() {
|
||||
bytes[byte_i] = u8::from_str_radix(byte_str, 16)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
includes:
|
||||
- base.yaml
|
||||
targets:
|
||||
- target: /bin/
|
||||
copy:
|
||||
- files:
|
||||
- ../init/target/release/init
|
||||
# copy libnss_files
|
||||
- target: /opt/occlum/glibc/lib
|
||||
copy:
|
||||
- files:
|
||||
- /opt/occlum/glibc/lib/libnss_files.so.2
|
||||
- /opt/occlum/glibc/lib/libnss_dns.so.2
|
||||
- /opt/occlum/glibc/lib/libresolv.so.2
|
||||
# copy root CA
|
||||
- target: /etc/ssl
|
||||
copy:
|
||||
- dirs:
|
||||
- /etc/ssl/
|
BIN
demos/remote_attestation/azure_attestation/maa_init/maa_init.png
Normal file
BIN
demos/remote_attestation/azure_attestation/maa_init/maa_init.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
Loading…
Reference in New Issue
Block a user