diff --git a/lib/default.nix b/lib/default.nix deleted file mode 100644 index 494d928..0000000 --- a/lib/default.nix +++ /dev/null @@ -1,242 +0,0 @@ -# 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" - , appName ? "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 - manifestRecursiveMerge = - base: mod: with lib.attrsets; let - mergeByPathWithOp = path: action: setAttrByPath path ( - if hasAttrByPath path mod - then action (getAttrFromPath path base) (getAttrFromPath path mod) - else getAttrFromPath path base - ); - mergeListByPath = path: mergeByPathWithOp path (a: b: a ++ b); - mergeEnvPathByPath = path: mergeByPathWithOp path (a: b: a + ":" + b); - in - recursiveUpdate base (recursiveUpdate mod ( - # manually merge the relevant lists / strings - mergeListByPath [ "fs" "mounts" ] - // mergeListByPath [ "sgx" "trusted_files" ] - // mergeEnvPathByPath [ "loader" "env" "LD_LIBRARY_PATH" ] - )); - 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 manifestRecursiveMerge else customRecursiveMerge) manifest_base 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}/${appName}.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}; - if [ -n "$GRAMINE_DIRECT" ]; then - exec gramine-direct ${appName}; - else - [[ -r /var/run/aesmd/aesm.socket ]] || restart-aesmd >&2; - exec gramine-sgx ${appName}; - fi - '' - ]; - 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} ${appName}.manifest; - ${nixsgx.gramine}/bin/gramine-sgx-sign \ - --manifest ${appName}.manifest \ - --output ${appName}.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 ${appDir} - cp ${sigFile} ${appDir}/${appName}.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/overlays/nixsgxLib/default.nix b/overlays/nixsgxLib/default.nix new file mode 100644 index 0000000..9b6dee9 --- /dev/null +++ b/overlays/nixsgxLib/default.nix @@ -0,0 +1,248 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ ... }: +final: _: +{ + nixsgxLib = { + mkSGXContainer = args: final.callPackage + ( + { 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" + , appName ? "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 + manifestRecursiveMerge = + base: mod: with lib.attrsets; let + mergeByPathWithOp = path: action: setAttrByPath path ( + if hasAttrByPath path mod + then action (getAttrFromPath path base) (getAttrFromPath path mod) + else getAttrFromPath path base + ); + mergeListByPath = path: mergeByPathWithOp path (a: b: a ++ b); + mergeEnvPathByPath = path: mergeByPathWithOp path (a: b: a + ":" + b); + in + recursiveUpdate base (recursiveUpdate mod ( + # manually merge the relevant lists / strings + mergeListByPath [ "fs" "mounts" ] + // mergeListByPath [ "sgx" "trusted_files" ] + // mergeEnvPathByPath [ "loader" "env" "LD_LIBRARY_PATH" ] + )); + 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 manifestRecursiveMerge else customRecursiveMerge) manifest_base manifest; + + tomlFormat = pkgs.formats.toml { }; + manifestFile = tomlFormat.generate "${name}.manifest.toml" mergedManifest; + + contents = pkgs.buildEnv { + name = "image-root-${appName}"; + + 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}/${appName}.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-${appName}"; + + 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}; + if [ -n "$GRAMINE_DIRECT" ]; then + exec gramine-direct ${appName}; + else + [[ -r /var/run/aesmd/aesm.socket ]] || restart-aesmd >&2; + exec gramine-sgx ${appName}; + fi + '' + ]; + 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-${appName}"; + inherit tag; + inherit contents; + inherit fromImage; + + includeStorePaths = false; + enableFakechroot = true; + fakeRootCommands = '' + ( + set -e + cd ${appDir} + HOME=${appDir} ${nixsgx.gramine}/bin/gramine-manifest ${manifestFile} ${appName}.manifest; + ${nixsgx.gramine}/bin/gramine-sgx-sign \ + --manifest ${appName}.manifest \ + --output ${appName}.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 ${appDir} + cp ${sigFile} ${appDir}/${appName}.sig + ''; + } + else fromImage; + + extendImage = fromImage: + pkgs.dockerTools.buildLayeredImage + { + inherit name; + inherit tag; + inherit config; + inherit fromImage; + contents = extendedContents; + }; + in + injectSigFile (extendImage (addGramineManifest appImage)) + ) + args; + }; +} diff --git a/lib/test-enclave-key.pem b/overlays/nixsgxLib/test-enclave-key.pem similarity index 100% rename from lib/test-enclave-key.pem rename to overlays/nixsgxLib/test-enclave-key.pem diff --git a/packages/nixsgx-test-sgx-dcap/default.nix b/packages/nixsgx-test-sgx-dcap/default.nix index 245af4c..6074906 100644 --- a/packages/nixsgx-test-sgx-dcap/default.nix +++ b/packages/nixsgx-test-sgx-dcap/default.nix @@ -1,15 +1,13 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs { lib -, pkgs -, inputs -, nixsgx +, nixsgxLib , hello , isAzure ? false , container-name ? "nixsgx-test-sgx-dcap" , tag ? "latest" }: -pkgs.callPackage lib.nixsgx.mkSGXContainer { +nixsgxLib.mkSGXContainer { name = container-name; inherit tag isAzure;