From d2b836216bb1f8446685e5ae878828b8d35b8228 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 4 Jun 2024 13:36:42 +0200 Subject: [PATCH] feat: add `mkSGXContainer` nix function to build SGX container in one go. Signed-off-by: Harald Hoyer --- lib/default.nix | 233 +++++++++++++++++++++ lib/test-enclave-key.pem | 39 ++++ packages/docker-gramine-azure/default.nix | 28 --- packages/docker-gramine-dcap/default.nix | 27 --- packages/nixsgx-test-sgx-azure/default.nix | 25 +++ packages/nixsgx-test-sgx-dcap/default.nix | 25 +++ 6 files changed, 322 insertions(+), 55 deletions(-) create mode 100644 lib/default.nix create mode 100644 lib/test-enclave-key.pem delete mode 100644 packages/docker-gramine-azure/default.nix delete mode 100644 packages/docker-gramine-dcap/default.nix create mode 100644 packages/nixsgx-test-sgx-azure/default.nix create mode 100644 packages/nixsgx-test-sgx-dcap/default.nix diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..0de8b6e --- /dev/null +++ b/lib/default.nix @@ -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)); +} diff --git a/lib/test-enclave-key.pem b/lib/test-enclave-key.pem new file mode 100644 index 0000000..53b317a --- /dev/null +++ b/lib/test-enclave-key.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/packages/docker-gramine-azure/default.nix b/packages/docker-gramine-azure/default.nix deleted file mode 100644 index 9ecb888..0000000 --- a/packages/docker-gramine-azure/default.nix +++ /dev/null @@ -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 - ''; - }; -} diff --git a/packages/docker-gramine-dcap/default.nix b/packages/docker-gramine-dcap/default.nix deleted file mode 100644 index cd116e0..0000000 --- a/packages/docker-gramine-dcap/default.nix +++ /dev/null @@ -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 - ''; - }; -} diff --git a/packages/nixsgx-test-sgx-azure/default.nix b/packages/nixsgx-test-sgx-azure/default.nix new file mode 100644 index 0000000..84d4e17 --- /dev/null +++ b/packages/nixsgx-test-sgx-azure/default.nix @@ -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; + }; + }; +} diff --git a/packages/nixsgx-test-sgx-dcap/default.nix b/packages/nixsgx-test-sgx-dcap/default.nix new file mode 100644 index 0000000..82334b5 --- /dev/null +++ b/packages/nixsgx-test-sgx-dcap/default.nix @@ -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; + }; + }; +}