feat: initial commit

Signed-off-by: Harald Hoyer <harald@matterlabs.dev>
This commit is contained in:
Harald Hoyer 2024-02-09 10:10:53 +01:00
parent aff4dd30bd
commit 89ffbd35a8
Signed by: harald
GPG key ID: F519A1143B3FBE32
123 changed files with 16508 additions and 0 deletions

View file

@ -0,0 +1,26 @@
[package]
name = "tee-vault-admin"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
actix-web.workspace = true
anyhow.workspace = true
awc.workspace = true
base64.workspace = true
bytemuck.workspace = true
clap.workspace = true
hex.workspace = true
mio.workspace = true
rustls.workspace = true
serde.workspace = true
serde_json.workspace = true
sha2.workspace = true
teepot.workspace = true
tracing-actix-web.workspace = true
tracing-log.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true

View file

@ -0,0 +1,85 @@
FROM docker.io/ubuntu:20.04 AS azuredcap
WORKDIR /build
ADD https://github.com/microsoft/Azure-DCAP-Client/archive/refs/tags/1.12.0.tar.gz ./Azure-DCAP-Client.tar.gz
RUN tar -xvf Azure-DCAP-Client.tar.gz
COPY assets/Azure-DCAP-Client.patch ./Azure-DCAP-Client.patch
RUN set -eux; \
apt-get update; \
apt-get install -y software-properties-common; \
add-apt-repository ppa:team-xbmc/ppa -y; \
apt-get update; \
apt-get install -y \
build-essential \
cmake \
libssl-dev \
libcurl4-openssl-dev \
pkg-config \
nlohmann-json3-dev \
wget \
dos2unix \
;
WORKDIR /build/Azure-DCAP-Client-1.12.0
RUN dos2unix src/dcap_provider.cpp && patch -p1 < ../Azure-DCAP-Client.patch
WORKDIR /build/Azure-DCAP-Client-1.12.0/src/Linux
RUN ./configure && make && make install
FROM docker.io/rust:1-bullseye AS buildtee
RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
cmake \
rsync \
pkg-config \
libssl-dev \
libcurl4-openssl-dev \
libprotobuf-dev \
protobuf-compiler \
clang \
libsgx-headers \
libsgx-dcap-quote-verify-dev
WORKDIR /opt/vault/plugins
WORKDIR /build
RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-admin.manifest.template' -av /data/ ./
RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \
RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \
cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-vault-admin --bin tee-vault-admin \
&& mv ./target/x86_64-unknown-linux-gnu/release/tee-vault-admin ./
FROM docker.io/gramineproject/gramine:v1.5
RUN curl -fsSLo /usr/share/keyrings/microsoft.asc https://packages.microsoft.com/keys/microsoft.asc \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.asc] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/msprod.list \
&& apt-get update \
&& apt purge -y libsgx-dcap-default-qpl \
&& apt-get install -y az-dcap-client
RUN apt purge -y libsgx-ae-qve
# libsgx-urts
RUN rm -rf /var/lib/apt/lists/*
# So we only have to use one gramine template
RUN touch /etc/sgx_default_qcnl.conf
WORKDIR /app
COPY --from=buildtee /build/tee-vault-admin .
COPY ./bin/tee-vault-admin/tee-vault-admin.manifest.template .
COPY vault/enclave-key.pem .
# The original Azure library is still delivering expired collateral, so we have to use a patched version
COPY --from=azuredcap /usr/local/lib/libdcap_quoteprov.so /usr/lib/
RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-vault-admin.manifest.template tee-vault-admin.manifest \
&& gramine-sgx-sign --manifest tee-vault-admin.manifest --output tee-vault-admin.manifest.sgx --key enclave-key.pem \
&& rm enclave-key.pem
EXPOSE 8443
ENTRYPOINT ["/bin/sh", "-c"]
CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-vault-admin" ]

View file

@ -0,0 +1,58 @@
FROM docker.io/rust:1-bullseye AS buildtee
RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
cmake \
rsync \
pkg-config \
libssl-dev \
libcurl4-openssl-dev \
libprotobuf-dev \
protobuf-compiler \
clang \
libsgx-headers \
libsgx-dcap-quote-verify-dev
WORKDIR /opt/vault/plugins
WORKDIR /build
RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-admin.manifest.template' -av /data/ ./
RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \
RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \
cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-vault-admin --bin tee-vault-admin \
&& mv ./target/x86_64-unknown-linux-gnu/release/tee-vault-admin ./
FROM docker.io/gramineproject/gramine:v1.5
RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
libsgx-dcap-default-qpl \
libsgx-urts \
libsgx-enclave-common \
libsgx-dcap-quote-verify
RUN apt purge -y libsgx-ae-qve
RUN rm -rf /var/lib/apt/lists/*
# So we only have to use one gramine template
RUN touch /lib/libdcap_quoteprov.so
WORKDIR /app
COPY --from=buildtee /build/tee-vault-admin .
COPY ./bin/tee-vault-admin/tee-vault-admin.manifest.template .
COPY vault/enclave-key.pem .
COPY assets/sgx_default_qcnl.conf.json /etc/sgx_default_qcnl.conf
RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-vault-admin.manifest.template tee-vault-admin.manifest \
&& gramine-sgx-sign --manifest tee-vault-admin.manifest --output tee-vault-admin.manifest.sgx --key enclave-key.pem \
&& rm enclave-key.pem
EXPOSE 8443
ENTRYPOINT ["/bin/sh", "-c"]
CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-vault-admin" ]

View file

@ -0,0 +1,25 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs
//! attestation
use crate::ServerState;
use actix_web::http::StatusCode;
use actix_web::web::{Data, Json};
use anyhow::{Context, Result};
use std::sync::Arc;
use teepot::json::http::AttestationResponse;
use teepot::server::attestation::get_quote_and_collateral;
use teepot::server::{HttpResponseError, Status};
use tracing::instrument;
/// Get attestation
#[instrument(level = "info", name = "/v1/sys/attestation", skip_all)]
pub async fn get_attestation(
worker: Data<Arc<ServerState>>,
) -> Result<Json<AttestationResponse>, HttpResponseError> {
get_quote_and_collateral(None, &worker.report_data)
.context("Error getting attestation")
.map(Json)
.status(StatusCode::INTERNAL_SERVER_ERROR)
}

View file

@ -0,0 +1,89 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs
//! post commands
use crate::ServerState;
use actix_web::web;
use anyhow::{anyhow, Context, Result};
use awc::http::StatusCode;
use sha2::{Digest, Sha256};
use std::sync::Arc;
use teepot::client::vault::VaultConnection;
use teepot::json::http::{
VaultCommandRequest, VaultCommandResponse, VaultCommands, VaultCommandsResponse,
};
use teepot::json::secrets::{AdminConfig, AdminState};
use teepot::server::{signatures::VerifySig, HttpResponseError, Status};
use tracing::instrument;
/// Post command
#[instrument(level = "info", name = "/v1/command", skip_all)]
pub async fn post_command(
state: web::Data<Arc<ServerState>>,
item: web::Json<VaultCommandRequest>,
) -> Result<web::Json<VaultCommandsResponse>, HttpResponseError> {
let conn = VaultConnection::new(&state.vault_attestation.clone().into(), "admin".to_string())
.await
.context("connecting to vault")
.status(StatusCode::BAD_GATEWAY)?;
let mut admin_state: AdminState = conn
.load_secret("state")
.await?
.context("empty admin state")
.status(StatusCode::BAD_GATEWAY)?;
let commands: VaultCommands = serde_json::from_str(&item.commands)
.context("parsing commands")
.status(StatusCode::BAD_REQUEST)?;
if admin_state.last_digest.to_ascii_lowercase() != commands.last_digest {
return Err(anyhow!(
"last digest does not match {} != {}",
admin_state.last_digest.to_ascii_lowercase(),
commands.last_digest
))
.status(StatusCode::BAD_REQUEST);
}
let admin_config: AdminConfig = conn
.load_secret("config")
.await?
.context("empty admin config")
.status(StatusCode::BAD_GATEWAY)?;
admin_config.check_sigs(&item.signatures, item.commands.as_bytes())?;
let mut hasher = Sha256::new();
hasher.update(item.commands.as_bytes());
let hash = hasher.finalize();
let digest = hex::encode(hash);
admin_state.last_digest = digest.clone();
conn.store_secret(admin_state, "state").await?;
let mut responds = VaultCommandsResponse {
digest,
results: vec![],
};
for (pos, command) in commands.commands.iter().enumerate() {
let resp = conn
.vault_put(
&format!("Executing command {pos}"),
&command.url,
&command.data,
)
.await?;
let vcr = VaultCommandResponse {
status_code: resp.0.as_u16(),
value: resp.1,
};
responds.results.push(vcr);
}
let _ = conn.revoke_token().await;
Ok(web::Json(responds))
}

View file

@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs
//! digest
use crate::ServerState;
use actix_web::{web, HttpResponse};
use anyhow::{Context, Result};
use awc::http::StatusCode;
use serde_json::json;
use std::sync::Arc;
use teepot::client::vault::VaultConnection;
use teepot::json::secrets::AdminState;
use teepot::server::{HttpResponseError, Status};
use tracing::instrument;
/// Get last digest
#[instrument(level = "info", name = "/v1/digest", skip_all)]
pub async fn get_digest(
state: web::Data<Arc<ServerState>>,
) -> Result<HttpResponse, HttpResponseError> {
let conn = VaultConnection::new(&state.vault_attestation.clone().into(), "admin".to_string())
.await
.context("connecting to vault")
.status(StatusCode::BAD_GATEWAY)?;
let admin_state: AdminState = conn
.load_secret("state")
.await?
.context("empty admin state")
.status(StatusCode::BAD_GATEWAY)?;
Ok(HttpResponse::Ok().json(json!({"last_digest": admin_state.last_digest })))
}

View file

@ -0,0 +1,148 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs
//! Server to handle requests to the Vault TEE
#![deny(missing_docs)]
#![deny(clippy::all)]
mod attestation;
mod command;
mod digest;
mod sign;
use actix_web::web::Data;
use actix_web::{web, App, HttpServer};
use anyhow::{Context, Result};
use attestation::get_attestation;
use clap::Parser;
use command::post_command;
use digest::get_digest;
use rustls::ServerConfig;
use sign::post_sign;
use std::net::Ipv6Addr;
use std::sync::Arc;
use teepot::json::http::{SignRequest, VaultCommandRequest, ATTESTATION_URL, DIGEST_URL};
use teepot::server::attestation::{get_quote_and_collateral, VaultAttestationArgs};
use teepot::server::new_json_cfg;
use teepot::server::pki::make_self_signed_cert;
use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel};
use tracing::{error, info};
use tracing_actix_web::TracingLogger;
use tracing_log::LogTracer;
use tracing_subscriber::Registry;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
/// Server state
pub struct ServerState {
/// Server TLS public key hash
pub report_data: [u8; 64],
/// Vault attestation args
pub vault_attestation: VaultAttestationArgs,
}
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Arguments {
/// allowed TCB levels, comma separated
#[arg(long, value_parser = parse_tcb_levels, env = "ALLOWED_TCB_LEVELS", default_value = "Ok")]
server_sgx_allowed_tcb_levels: EnumSet<TcbLevel>,
/// port to listen on
#[arg(long, env = "PORT", default_value = "8444")]
port: u16,
#[clap(flatten)]
pub attestation: VaultAttestationArgs,
}
#[actix_web::main]
async fn main() -> Result<()> {
LogTracer::init().context("Failed to set logger")?;
let subscriber = Registry::default()
.with(EnvFilter::from_default_env())
.with(fmt::layer().with_writer(std::io::stderr));
tracing::subscriber::set_global_default(subscriber).unwrap();
let args = Arguments::parse();
let (report_data, cert_chain, priv_key) = make_self_signed_cert()?;
if let Err(e) = get_quote_and_collateral(Some(args.server_sgx_allowed_tcb_levels), &report_data)
{
error!("failed to get quote and collateral: {e:?}");
// don't return for now, we can still serve requests but we won't be able to attest
}
// init server config builder with safe defaults
let config = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert([cert_chain].into(), priv_key)
.context("Failed to load TLS key/cert files")?;
info!("Starting HTTPS server at port {}", args.port);
info!("Quote verified! Connection secure!");
let server_state = Arc::new(ServerState {
report_data,
vault_attestation: args.attestation,
});
let server = match HttpServer::new(move || {
App::new()
// enable logger
.wrap(TracingLogger::default())
.app_data(new_json_cfg())
.app_data(Data::new(server_state.clone()))
.service(web::resource(ATTESTATION_URL).route(web::get().to(get_attestation)))
.service(web::resource(VaultCommandRequest::URL).route(web::post().to(post_command)))
.service(web::resource(SignRequest::URL).route(web::post().to(post_sign)))
.service(web::resource(DIGEST_URL).route(web::get().to(get_digest)))
})
.bind_rustls_0_22((Ipv6Addr::UNSPECIFIED, args.port), config)
{
Ok(c) => c,
Err(e) => {
error!("Failed to bind to port {}: {e:?}", args.port);
return Err(e).context(format!("Failed to bind to port {}", args.port));
}
};
if let Err(e) = server.worker_max_blocking_threads(2).workers(8).run().await {
error!("failed to start HTTPS server: {e:?}");
return Err(e).context("Failed to start HTTPS server");
}
Ok(())
}
#[cfg(test)]
mod tests {
use serde_json::json;
use teepot::json::http::{VaultCommand, VaultCommands};
const TEST_DATA: &str = include_str!("../../../tests/data/test.json");
#[test]
fn test_vault_commands() {
let cmd = VaultCommand {
url: "/v1/auth/tee/tees/test".to_string(),
data: json!({
"lease": "1000",
"name": "test",
"types": "sgx",
"sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded",
"sgx_mrsigner": "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d",
"token_policies": "test"
}),
};
let cmds = VaultCommands {
commands: vec![cmd],
last_digest: "".into(),
};
let test_data_cmds: VaultCommands = serde_json::from_str(TEST_DATA).unwrap();
assert_eq!(cmds, test_data_cmds);
}
}

View file

@ -0,0 +1,149 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs
//! post signing request
use crate::ServerState;
use actix_web::http::StatusCode;
use actix_web::web;
use anyhow::{anyhow, Context, Result};
use sha2::{Digest, Sha256};
use std::sync::Arc;
use teepot::client::vault::VaultConnection;
use teepot::json::http::{SignRequest, SignRequestData, SignResponse};
use teepot::json::secrets::{AdminConfig, AdminState, SGXSigningKey};
use teepot::server::signatures::VerifySig as _;
use teepot::server::{HttpResponseError, Status};
use teepot::sgx::sign::PrivateKey as _;
use teepot::sgx::sign::{Author, Signature};
use teepot::sgx::sign::{Body, RS256PrivateKey};
use tracing::instrument;
/// Sign command
#[instrument(level = "info", name = "/v1/sign", skip_all)]
pub async fn post_sign(
state: web::Data<Arc<ServerState>>,
item: web::Json<SignRequest>,
) -> Result<web::Json<SignResponse>, HttpResponseError> {
let conn = VaultConnection::new(&state.vault_attestation.clone().into(), "admin".to_string())
.await
.context("connecting to vault")
.status(StatusCode::BAD_GATEWAY)?;
let mut admin_state: AdminState = conn
.load_secret("state")
.await?
.context("empty admin state")
.status(StatusCode::BAD_GATEWAY)?;
let sign_request: SignRequestData = serde_json::from_str(&item.sign_request_data)
.context("parsing sign request data")
.status(StatusCode::BAD_REQUEST)?;
// Sanity checks
if sign_request.tee_type != "sgx" {
return Err(anyhow!("tee_type not supported")).status(StatusCode::BAD_REQUEST);
}
let tee_name = sign_request.tee_name;
if !tee_name.is_ascii() {
return Err(anyhow!("tee_name is not ascii")).status(StatusCode::BAD_REQUEST);
}
// check if tee_name is alphanumeric
if !tee_name.chars().all(|c| c.is_alphanumeric()) {
return Err(anyhow!("tee_name is not alphanumeric")).status(StatusCode::BAD_REQUEST);
}
// check if tee_name starts with an alphabetic char
if !tee_name.chars().next().unwrap().is_alphabetic() {
return Err(anyhow!("tee_name does not start with an alphabetic char"))
.status(StatusCode::BAD_REQUEST);
}
if admin_state.last_digest != sign_request.last_digest {
return Err(anyhow!(
"last digest does not match {} != {}",
admin_state.last_digest.to_ascii_lowercase(),
sign_request.last_digest
))
.status(StatusCode::BAD_REQUEST);
}
let admin_config: AdminConfig = conn
.load_secret("config")
.await?
.context("empty admin config")
.status(StatusCode::BAD_GATEWAY)?;
admin_config.check_sigs(&item.signatures, item.sign_request_data.as_bytes())?;
let mut hasher = Sha256::new();
hasher.update(item.sign_request_data.as_bytes());
let hash = hasher.finalize();
let digest = hex::encode(hash);
admin_state.last_digest = digest.clone();
conn.store_secret(admin_state, "state").await?;
// Sign SGX enclave
let key_path = format!("signing_keys/{}", tee_name);
let sgx_key = match conn
.load_secret::<SGXSigningKey>(&key_path)
.await
.context("Error loading signing key")
.status(StatusCode::INTERNAL_SERVER_ERROR)?
{
Some(key) => RS256PrivateKey::from_pem(&key.pem_pk)
.context("Failed to parse private key")
.status(StatusCode::INTERNAL_SERVER_ERROR)?,
None => {
let private_key = RS256PrivateKey::generate(3)
.context("Failed to generate private key")
.status(StatusCode::INTERNAL_SERVER_ERROR)?;
let pem_pk = private_key
.to_pem()
.context("Failed to convert private key to pem")
.status(StatusCode::INTERNAL_SERVER_ERROR)?;
let key = SGXSigningKey { pem_pk };
conn.store_secret(key.clone(), &key_path)
.await
.context("Error storing generated private key")
.status(StatusCode::INTERNAL_SERVER_ERROR)?;
private_key
}
};
let signed_data = sign_sgx(&sign_request.data, &sgx_key)?;
let respond = SignResponse {
digest,
signed_data,
};
let _ = conn.revoke_token().await;
Ok(web::Json(respond))
}
fn sign_sgx(body_bytes: &[u8], sgx_key: &RS256PrivateKey) -> Result<Vec<u8>, HttpResponseError> {
let body: Body = bytemuck::try_pod_read_unaligned(body_bytes)
.context("Invalid SGX input data")
.status(StatusCode::INTERNAL_SERVER_ERROR)?;
if body.can_set_debug() {
return Err(anyhow!("Not signing SGX enclave with debug flag"))
.status(StatusCode::BAD_REQUEST);
}
// FIXME: do we need the date and sw defined value?
let author = Author::new(0, 0);
let sig = Signature::new(sgx_key, author, body)
.context("Failed to create RSA signature")
.status(StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(bytemuck::bytes_of(&sig).to_vec())
}

View file

@ -0,0 +1,66 @@
libos.entrypoint = "/app/tee-vault-admin"
[loader]
argv = [ "/app/tee-vault-admin" ]
entrypoint = "file:{{ gramine.libos }}"
env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}:/lib"
env.HOME = "/app"
env.MALLOC_ARENA_MAX = "1"
env.AZDCAP_DEBUG_LOG_LEVEL = "ignore"
env.AZDCAP_COLLATERAL_VERSION = "v4"
### Admin Config ###
env.PORT = { passthrough = true }
### VAULT attestation ###
env.VAULT_ADDR = { passthrough = true }
env.VAULT_SGX_MRENCLAVE = { passthrough = true }
env.VAULT_SGX_MRSIGNER = { passthrough = true }
env.VAULT_SGX_ALLOWED_TCB_LEVELS = { passthrough = true }
### DEBUG ###
env.RUST_BACKTRACE = "1"
env.RUST_LOG="info,tee_vault_admin=trace,teepot=trace,vault_tee_client=trace,tee_client=trace,awc=debug"
[fs]
root.uri = "file:/"
start_dir = "/app"
mounts = [
{ path = "{{ execdir }}", uri = "file:{{ execdir }}" },
{ path = "/lib", uri = "file:{{ gramine.runtimedir() }}" },
{ path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" },
{ path = "/etc", uri = "file:/etc" },
{ type = "tmpfs", path = "/var/tmp" },
{ type = "tmpfs", path = "/tmp" },
{ type = "tmpfs", path = "/app/.dcap-qcnl" },
{ type = "tmpfs", path = "/app/.az-dcap-client" },
{ path = "/lib/libdcap_quoteprov.so", uri = "file:/lib/libdcap_quoteprov.so" },
]
[sgx]
trusted_files = [
"file:/etc/ld.so.cache",
"file:/app/",
"file:{{ execdir }}/",
"file:{{ arch_libdir }}/",
"file:/usr/{{ arch_libdir }}/",
"file:{{ gramine.libos }}",
"file:{{ gramine.runtimedir() }}/",
"file:/usr/lib/ssl/openssl.cnf",
"file:/etc/ssl/",
"file:/etc/sgx_default_qcnl.conf",
"file:/lib/libdcap_quoteprov.so",
]
remote_attestation = "dcap"
max_threads = 64
edmm_enable = false
## max enclave size
enclave_size = "8G"
[sys]
enable_extra_runtime_domain_names_conf = true
enable_sigterm_injection = true
# possible tweak option, if problems with mio
# currently mio is compiled with `mio_unsupported_force_waker_pipe`
# insecure__allow_eventfd = true