258 lines
8.3 KiB
Nix
258 lines
8.3 KiB
Nix
{ config, options, pkgs, lib, ... }:
|
|
let
|
|
inherit (lib) concatStringsSep literalExpression makeLibraryPath mkEnableOption
|
|
mkForce mkIf mkOption mkPackageOption mkRemovedOptionModule optional types;
|
|
|
|
cfg = config.services.aesmd;
|
|
opt = options.services.aesmd;
|
|
|
|
sgx-psw = cfg.package;
|
|
|
|
configFile = with cfg.settings; pkgs.writeText "aesmd.conf" (
|
|
concatStringsSep "\n" (
|
|
optional (whitelistUrl != null) "whitelist url = ${whitelistUrl}" ++
|
|
optional (proxy != null) "aesm proxy = ${proxy}" ++
|
|
optional (proxyType != null) "proxy type = ${proxyType}" ++
|
|
optional (defaultQuotingType != null) "default quoting type = ${defaultQuotingType}" ++
|
|
# Newline at end of file
|
|
[ "" ]
|
|
)
|
|
);
|
|
in
|
|
{
|
|
imports = [
|
|
(mkRemovedOptionModule [ "debug" ] ''
|
|
Enable debug mode by overriding the aesmd package directly:
|
|
|
|
services.aesmd.package = pkgs.sgx-psw.override { debug = true; };
|
|
'')
|
|
];
|
|
|
|
options.services.aesmd = {
|
|
enable = mkEnableOption "Intel's Architectural Enclave Service Manager (AESM) for Intel SGX";
|
|
package = mkPackageOption pkgs "sgx-psw" { };
|
|
environment = mkOption {
|
|
type = with types; attrsOf str;
|
|
default = { };
|
|
description = "Additional environment variables to pass to the AESM service.";
|
|
# Example environment variable for `sgx-azure-dcap-client` provider library
|
|
example = {
|
|
AZDCAP_COLLATERAL_VERSION = "v2";
|
|
AZDCAP_DEBUG_LOG_LEVEL = "INFO";
|
|
};
|
|
};
|
|
quoteProviderLibrary = mkOption {
|
|
type = with types; nullOr path;
|
|
default = null;
|
|
example = literalExpression "pkgs.sgx-azure-dcap-client";
|
|
description = "Custom quote provider library to use.";
|
|
};
|
|
settings = mkOption {
|
|
description = "AESM configuration";
|
|
default = { };
|
|
type = types.submodule {
|
|
options.whitelistUrl = mkOption {
|
|
type = with types; nullOr str;
|
|
default = null;
|
|
example = "http://whitelist.trustedservices.intel.com/SGX/LCWL/Linux/sgx_white_list_cert.bin";
|
|
description = "URL to retrieve authorized Intel SGX enclave signers.";
|
|
};
|
|
options.proxy = mkOption {
|
|
type = with types; nullOr str;
|
|
default = null;
|
|
example = "http://proxy_url:1234";
|
|
description = "HTTP network proxy.";
|
|
};
|
|
options.proxyType = mkOption {
|
|
type = with types; nullOr (enum [ "default" "direct" "manual" ]);
|
|
default = if (cfg.settings.proxy != null) then "manual" else null;
|
|
defaultText = literalExpression ''
|
|
if (config.${opt.settings}.proxy != null) then "manual" else null
|
|
'';
|
|
example = "default";
|
|
description = ''
|
|
Type of proxy to use. The `default` uses the system's default proxy.
|
|
If `direct` is given, uses no proxy.
|
|
A value of `manual` uses the proxy from
|
|
{option}`services.aesmd.settings.proxy`.
|
|
'';
|
|
};
|
|
options.defaultQuotingType = mkOption {
|
|
type = with types; nullOr (enum [ "ecdsa_256" "epid_linkable" "epid_unlinkable" ]);
|
|
default = null;
|
|
example = "ecdsa_256";
|
|
description = "Attestation quote type.";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
assertions = [{
|
|
assertion = !(config.boot.specialFileSystems."/dev".options ? "noexec");
|
|
message = "SGX requires exec permission for /dev";
|
|
}];
|
|
|
|
hardware.cpu.intel.sgx.provision.enable = true;
|
|
|
|
# Make sure the AESM service can find the SGX devices until
|
|
# https://github.com/intel/linux-sgx/issues/772 is resolved
|
|
# and updated in nixpkgs.
|
|
hardware.cpu.intel.sgx.enableDcapCompat = mkForce true;
|
|
|
|
systemd.services.aesmd =
|
|
let
|
|
storeAesmFolder = "${sgx-psw}/aesm";
|
|
# Hardcoded path AESM_DATA_FOLDER in psw/ae/aesm_service/source/oal/linux/aesm_util.cpp
|
|
aesmDataFolder = "/var/opt/aesmd/data";
|
|
in
|
|
{
|
|
description = "Intel Architectural Enclave Service Manager";
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [
|
|
"auditd.service"
|
|
"network.target"
|
|
"syslog.target"
|
|
];
|
|
|
|
environment = {
|
|
NAME = "aesm_service";
|
|
AESM_PATH = storeAesmFolder;
|
|
LD_LIBRARY_PATH = makeLibraryPath [ cfg.quoteProviderLibrary ];
|
|
} // cfg.environment;
|
|
|
|
# Make sure any of the SGX application enclave devices is available
|
|
unitConfig.AssertPathExists = [
|
|
# legacy out-of-tree driver
|
|
"|/dev/isgx"
|
|
# DCAP driver
|
|
"|/dev/sgx/enclave"
|
|
# in-tree driver
|
|
"|/dev/sgx_enclave"
|
|
];
|
|
|
|
serviceConfig = {
|
|
ExecStartPre = pkgs.writeShellScript "copy-aesmd-data-files.sh" ''
|
|
set -euo pipefail
|
|
whiteListFile="${aesmDataFolder}/white_list_cert_to_be_verify.bin"
|
|
if [[ ! -f "$whiteListFile" ]]; then
|
|
${pkgs.coreutils}/bin/install -m 644 -D \
|
|
"${storeAesmFolder}/data/white_list_cert_to_be_verify.bin" \
|
|
"$whiteListFile"
|
|
fi
|
|
'';
|
|
ExecStart = "${sgx-psw}/bin/aesm_service --no-daemon";
|
|
ExecReload = ''${pkgs.coreutils}/bin/kill -SIGHUP "$MAINPID"'';
|
|
|
|
Restart = "on-failure";
|
|
RestartSec = "15s";
|
|
|
|
DynamicUser = true;
|
|
Group = "sgx";
|
|
SupplementaryGroups = [
|
|
config.hardware.cpu.intel.sgx.provision.group
|
|
];
|
|
|
|
Type = "simple";
|
|
|
|
WorkingDirectory = storeAesmFolder;
|
|
StateDirectory = "aesmd";
|
|
StateDirectoryMode = "0700";
|
|
RuntimeDirectory = "aesmd";
|
|
RuntimeDirectoryMode = "0750";
|
|
|
|
# Hardening
|
|
|
|
# chroot into the runtime directory
|
|
RootDirectory = "%t/aesmd";
|
|
BindReadOnlyPaths = [
|
|
builtins.storeDir
|
|
# Hardcoded path AESM_CONFIG_FILE in psw/ae/aesm_service/source/utils/aesm_config.cpp
|
|
"${configFile}:/etc/aesmd.conf"
|
|
];
|
|
BindPaths = [
|
|
# Hardcoded path CONFIG_SOCKET_PATH in psw/ae/aesm_service/source/core/ipc/SocketConfig.h
|
|
"%t/aesmd:/var/run/aesmd"
|
|
"%S/aesmd:/var/opt/aesmd"
|
|
];
|
|
|
|
# PrivateDevices=true will mount /dev noexec which breaks AESM
|
|
PrivateDevices = false;
|
|
DevicePolicy = "closed";
|
|
DeviceAllow = [
|
|
# legacy out-of-tree driver
|
|
"/dev/isgx rw"
|
|
# DCAP driver
|
|
"/dev/sgx rw"
|
|
# in-tree driver
|
|
"/dev/sgx_enclave rw"
|
|
"/dev/sgx_provision rw"
|
|
];
|
|
|
|
# Requires Internet access for attestation
|
|
PrivateNetwork = false;
|
|
|
|
RestrictAddressFamilies = [
|
|
# Allocates the socket /var/run/aesmd/aesm.socket
|
|
"AF_UNIX"
|
|
# Uses the HTTP protocol to initialize some services
|
|
"AF_INET"
|
|
"AF_INET6"
|
|
];
|
|
|
|
# True breaks stuff
|
|
MemoryDenyWriteExecute = false;
|
|
|
|
# needs the ipc syscall in order to run
|
|
SystemCallFilter = [
|
|
"@system-service"
|
|
"~@aio"
|
|
"~@chown"
|
|
"~@clock"
|
|
"~@cpu-emulation"
|
|
"~@debug"
|
|
"~@keyring"
|
|
"~@memlock"
|
|
"~@module"
|
|
"~@mount"
|
|
"~@privileged"
|
|
"~@raw-io"
|
|
"~@reboot"
|
|
"~@resources"
|
|
"~@setuid"
|
|
"~@swap"
|
|
"~@sync"
|
|
"~@timer"
|
|
];
|
|
SystemCallArchitectures = "native";
|
|
SystemCallErrorNumber = "EPERM";
|
|
|
|
CapabilityBoundingSet = "";
|
|
KeyringMode = "private";
|
|
LockPersonality = true;
|
|
NoNewPrivileges = true;
|
|
NotifyAccess = "none";
|
|
PrivateMounts = true;
|
|
PrivateTmp = true;
|
|
PrivateUsers = true;
|
|
ProcSubset = "pid";
|
|
ProtectClock = true;
|
|
ProtectControlGroups = true;
|
|
ProtectHome = true;
|
|
ProtectHostname = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectKernelModules = true;
|
|
ProtectKernelTunables = true;
|
|
ProtectProc = "invisible";
|
|
ProtectSystem = "strict";
|
|
RemoveIPC = true;
|
|
RestrictNamespaces = true;
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
UMask = "0066";
|
|
};
|
|
};
|
|
};
|
|
}
|