Merge pull request #34 from matter-labs/mkSGXContainer

feat: add `mkSGXContainer` nix function
This commit is contained in:
Harald Hoyer 2024-06-05 14:10:20 +02:00 committed by GitHub
commit b6e9f1e229
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 322 additions and 55 deletions

233
lib/default.nix Normal file
View file

@ -0,0 +1,233 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2024 Matter Labs
_:
{
mkSGXContainer =
{ lib
, pkgs
, coreutils
, curl
, nixsgx
, openssl
, packages
, entrypoint
, name
, tag ? null
, keyfile ? ./test-enclave-key.pem
, isAzure ? false
, manifest ? { }
, sgx_default_qcnl_conf ? null
, extraCmd ? ":"
, extraPostBuild ? ""
, extraChrootCommands ? ""
, appDir ? "/app"
, sigFile ? null
, extendedPackages ? [ ]
, customRecursiveMerge ? null
}:
assert lib.assertMsg (!(isAzure && sgx_default_qcnl_conf != null)) "sgx_default_qcnl_conf can't be set for Azure";
let
recursiveMerge = attrList:
with lib;
let
f = attrPath:
zipAttrsWith (n: values:
if tail values == [ ]
then head values
else if all isList values
then unique (concatLists values)
else if all isAttrs values
then f (attrPath ++ [ n ]) values
else last values
);
in
f [ ] attrList;
manifest_base = {
libos = { inherit entrypoint; };
fs = {
mounts = [
{ path = "/var/tmp"; type = "tmpfs"; }
{ path = "/tmp"; type = "tmpfs"; }
{ path = "${appDir}/.dcap-qcnl"; type = "tmpfs"; }
{ path = "${appDir}/.az-dcap-client"; type = "tmpfs"; }
];
root = { uri = "file:/"; };
start_dir = "${appDir}";
};
loader = {
argv = [ entrypoint ];
entrypoint = "file:{{ gramine.libos }}";
env = {
AZDCAP_COLLATERAL_VERSION = "v4";
AZDCAP_DEBUG_LOG_LEVEL = "ignore";
HOME = "${appDir}";
LD_LIBRARY_PATH = (lib.makeLibraryPath [
(if isAzure then nixsgx.azure-dcap-client.out else nixsgx.sgx-dcap.default_qpl)
pkgs.curl.out
]) + ":{{ gramine.runtimedir() }}:/lib";
MALLOC_ARENA_MAX = "1";
PATH = "/bin";
SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
};
log_level = "error";
};
sgx = {
remote_attestation = "dcap";
trusted_files = [
"file:${appDir}/"
"file:/bin/"
"file:/etc/gai.conf"
"file:/etc/ssl/certs/ca-bundle.crt"
"file:/lib/"
"file:/nix/"
"file:{{ gramine.libos }}"
"file:{{ gramine.runtimedir() }}/"
] ++ (if !isAzure then [
"file:/etc/sgx_default_qcnl.conf"
] else [ ]);
};
sys = {
enable_extra_runtime_domain_names_conf = true;
enable_sigterm_injection = true;
};
};
mergedManifest = ((if customRecursiveMerge == null then recursiveMerge else customRecursiveMerge) [ manifest_base manifest ])
# Don't merge the `loader.argv` array
// { loader.argv = lib.attrsets.attrByPath [ "loader" "argv" ] manifest_base.loader.argv manifest; };
tomlFormat = pkgs.formats.toml { };
manifestFile = tomlFormat.generate "${name}.manifest.toml" mergedManifest;
contents = pkgs.buildEnv {
name = "image-root";
paths = with pkgs.dockerTools; with nixsgx;[
openssl.out
curl.out
gramine
sgx-dcap.quote_verify
caCertificates
]
++ (if isAzure then [
azure-dcap-client
] else [
sgx-dcap.default_qpl
])
++ packages;
pathsToLink = [ "/bin" "/lib" "/etc" "/share" "${appDir}" ];
postBuild = ''
(
set -e
mkdir -p $out/{etc,var/run}
mkdir -p $out/${appDir}/{.dcap-qcnl,.az-dcap-client}
ln -s ${manifestFile} $out/${appDir}/${name}.manifest.toml
# Increase IPv4 address priority
printf "precedence ::ffff:0:0/96 100\n" > $out/etc/gai.conf
${
if sgx_default_qcnl_conf != null then
"rm -f $out/etc/sgx_default_qcnl.conf; ln -s ${sgx_default_qcnl_conf} $out/etc/sgx_default_qcnl.conf;"
else ""
}
eval "${extraPostBuild}"
)
'';
};
extendedContents = pkgs.buildEnv {
name = "extended-root";
paths = with pkgs.dockerTools; with nixsgx;[
coreutils
restart-aesmd
sgx-psw
usrBinEnv
binSh
fakeNss
] ++ extendedPackages;
pathsToLink = [ "/bin" "/lib" "/etc" "/share" ];
postBuild =
if sgx_default_qcnl_conf != null then ''
(
set -e
mkdir -p $out/etc
rm -f $out/etc/sgx_default_qcnl.conf
ln -s ${sgx_default_qcnl_conf} $out/etc/sgx_default_qcnl.conf
)
'' else null;
};
config = {
Env = [
"SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"
"HOME=${appDir}"
"LD_LIBRARY_PATH=${lib.makeLibraryPath [ pkgs.curl.out (if isAzure then nixsgx.azure-dcap-client.out else nixsgx.sgx-dcap.default_qpl)]}"
];
Entrypoint = [ "/bin/sh" "-c" ];
Cmd = [ "${extraCmd}; [[ -r /var/run/aesmd/aesm.socket ]] || restart-aesmd >&2; exec gramine-sgx ${name}" ];
WorkingDir = "${appDir}";
};
# create a base image with the nix store included, because the derived image
# will run gramine-sgx-sign and has does not include store paths,
# otherwise all store paths from the `fakeRootCommands` will be included.
appImage = pkgs.dockerTools.buildLayeredImage { name = "${name}-app"; inherit contents; };
addGramineManifest = fromImage:
pkgs.dockerTools.buildLayeredImage
{
name = "${name}-manifest";
inherit tag;
inherit contents;
inherit fromImage;
includeStorePaths = false;
enableFakechroot = true;
fakeRootCommands = ''
(
set -e
cd ${appDir}
HOME=${appDir} ${nixsgx.gramine}/bin/gramine-manifest ${manifestFile} ${name}.manifest;
${nixsgx.gramine}/bin/gramine-sgx-sign \
--manifest ${name}.manifest \
--output ${name}.manifest.sgx \
--key ${keyfile};
eval "${extraChrootCommands}"
)
'';
};
injectSigFile = fromImage:
if sigFile != null then
pkgs.dockerTools.buildLayeredImage
{
inherit name;
inherit config;
inherit tag;
inherit fromImage;
includeStorePaths = false;
extraCommands = ''
mkdir -p app
cp ${sigFile} app/nixsgx-test-sgx-azure.sig
'';
}
else fromImage;
extendImage = fromImage:
pkgs.dockerTools.buildLayeredImage
{
inherit name;
inherit tag;
inherit config;
inherit fromImage;
contents = extendedContents;
};
in
injectSigFile (extendImage (addGramineManifest appImage));
}

39
lib/test-enclave-key.pem Normal file
View file

@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View file

@ -1,28 +0,0 @@
{ lib
, buildEnv
, busybox
, python3
, dockerTools
, nixsgx
}:
dockerTools.buildLayeredImage {
name = "gramine-azure";
tag = "latest";
contents = buildEnv {
name = "image-root";
paths = [
busybox
nixsgx.azure-dcap-client
nixsgx.sgx-psw
nixsgx.sgx-dcap.quote_verify
nixsgx.gramine
];
pathsToLink = [ "/bin" "/lib" "/etc" ];
postBuild = ''
mkdir -p $out/var
ln -s /run $out/var/run
'';
};
}

View file

@ -1,27 +0,0 @@
{ lib
, buildEnv
, dockerTools
, nixsgx
, busybox
, ...
}:
dockerTools.buildLayeredImage {
name = "gramine-dcap";
tag = "latest";
contents = buildEnv {
name = "image-root";
paths = [
busybox
nixsgx.sgx-psw
nixsgx.gramine
nixsgx.sgx-dcap.default_qpl
nixsgx.restart-aesmd
];
pathsToLink = [ "/bin" "/lib" "/etc" ];
postBuild = ''
mkdir -p $out/var
ln -s /run $out/var/run
'';
};
}

View file

@ -0,0 +1,25 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2024 Matter Labs
{ lib
, pkgs
, inputs
, nixsgx
, hello
}:
pkgs.callPackage lib.nixsgx.mkSGXContainer {
name = "nixsgx-test-sgx-azure";
tag = "latest";
packages = [ hello ];
entrypoint = lib.meta.getExe hello;
isAzure = true;
manifest = {
sgx = {
edmm_enable = false;
enclave_size = "32M";
max_threads = 2;
};
};
}

View file

@ -0,0 +1,25 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2024 Matter Labs
{ lib
, pkgs
, inputs
, nixsgx
, hello
}:
pkgs.callPackage lib.nixsgx.mkSGXContainer {
name = "nixsgx-test-sgx-dcap";
tag = "latest";
packages = [ hello ];
entrypoint = lib.meta.getExe hello;
isAzure = false;
manifest = {
sgx = {
edmm_enable = false;
enclave_size = "32M";
max_threads = 2;
};
};
}