at 23.11-pre 8.4 kB view raw
1{ config, options, pkgs, lib, ... }: 2with lib; 3let 4 cfg = config.services.aesmd; 5 opt = options.services.aesmd; 6 7 sgx-psw = pkgs.sgx-psw.override { inherit (cfg) debug; }; 8 9 configFile = with cfg.settings; pkgs.writeText "aesmd.conf" ( 10 concatStringsSep "\n" ( 11 optional (whitelistUrl != null) "whitelist url = ${whitelistUrl}" ++ 12 optional (proxy != null) "aesm proxy = ${proxy}" ++ 13 optional (proxyType != null) "proxy type = ${proxyType}" ++ 14 optional (defaultQuotingType != null) "default quoting type = ${defaultQuotingType}" ++ 15 # Newline at end of file 16 [ "" ] 17 ) 18 ); 19in 20{ 21 options.services.aesmd = { 22 enable = mkEnableOption (lib.mdDoc "Intel's Architectural Enclave Service Manager (AESM) for Intel SGX"); 23 debug = mkOption { 24 type = types.bool; 25 default = false; 26 description = lib.mdDoc "Whether to build the PSW package in debug mode."; 27 }; 28 environment = mkOption { 29 type = with types; attrsOf str; 30 default = { }; 31 description = mdDoc "Additional environment variables to pass to the AESM service."; 32 # Example environment variable for `sgx-azure-dcap-client` provider library 33 example = { 34 AZDCAP_COLLATERAL_VERSION = "v2"; 35 AZDCAP_DEBUG_LOG_LEVEL = "INFO"; 36 }; 37 }; 38 quoteProviderLibrary = mkOption { 39 type = with types; nullOr path; 40 default = null; 41 example = literalExpression "pkgs.sgx-azure-dcap-client"; 42 description = lib.mdDoc "Custom quote provider library to use."; 43 }; 44 settings = mkOption { 45 description = lib.mdDoc "AESM configuration"; 46 default = { }; 47 type = types.submodule { 48 options.whitelistUrl = mkOption { 49 type = with types; nullOr str; 50 default = null; 51 example = "http://whitelist.trustedservices.intel.com/SGX/LCWL/Linux/sgx_white_list_cert.bin"; 52 description = lib.mdDoc "URL to retrieve authorized Intel SGX enclave signers."; 53 }; 54 options.proxy = mkOption { 55 type = with types; nullOr str; 56 default = null; 57 example = "http://proxy_url:1234"; 58 description = lib.mdDoc "HTTP network proxy."; 59 }; 60 options.proxyType = mkOption { 61 type = with types; nullOr (enum [ "default" "direct" "manual" ]); 62 default = if (cfg.settings.proxy != null) then "manual" else null; 63 defaultText = literalExpression '' 64 if (config.${opt.settings}.proxy != null) then "manual" else null 65 ''; 66 example = "default"; 67 description = lib.mdDoc '' 68 Type of proxy to use. The `default` uses the system's default proxy. 69 If `direct` is given, uses no proxy. 70 A value of `manual` uses the proxy from 71 {option}`services.aesmd.settings.proxy`. 72 ''; 73 }; 74 options.defaultQuotingType = mkOption { 75 type = with types; nullOr (enum [ "ecdsa_256" "epid_linkable" "epid_unlinkable" ]); 76 default = null; 77 example = "ecdsa_256"; 78 description = lib.mdDoc "Attestation quote type."; 79 }; 80 }; 81 }; 82 }; 83 84 config = mkIf cfg.enable { 85 assertions = [{ 86 assertion = !(config.boot.specialFileSystems."/dev".options ? "noexec"); 87 message = "SGX requires exec permission for /dev"; 88 }]; 89 90 hardware.cpu.intel.sgx.provision.enable = true; 91 92 # Make sure the AESM service can find the SGX devices until 93 # https://github.com/intel/linux-sgx/issues/772 is resolved 94 # and updated in nixpkgs. 95 hardware.cpu.intel.sgx.enableDcapCompat = mkForce true; 96 97 systemd.services.aesmd = 98 let 99 storeAesmFolder = "${sgx-psw}/aesm"; 100 # Hardcoded path AESM_DATA_FOLDER in psw/ae/aesm_service/source/oal/linux/aesm_util.cpp 101 aesmDataFolder = "/var/opt/aesmd/data"; 102 in 103 { 104 description = "Intel Architectural Enclave Service Manager"; 105 wantedBy = [ "multi-user.target" ]; 106 107 after = [ 108 "auditd.service" 109 "network.target" 110 "syslog.target" 111 ]; 112 113 environment = { 114 NAME = "aesm_service"; 115 AESM_PATH = storeAesmFolder; 116 LD_LIBRARY_PATH = makeLibraryPath [ cfg.quoteProviderLibrary ]; 117 } // cfg.environment; 118 119 # Make sure any of the SGX application enclave devices is available 120 unitConfig.AssertPathExists = [ 121 # legacy out-of-tree driver 122 "|/dev/isgx" 123 # DCAP driver 124 "|/dev/sgx/enclave" 125 # in-tree driver 126 "|/dev/sgx_enclave" 127 ]; 128 129 serviceConfig = rec { 130 ExecStartPre = pkgs.writeShellScript "copy-aesmd-data-files.sh" '' 131 set -euo pipefail 132 whiteListFile="${aesmDataFolder}/white_list_cert_to_be_verify.bin" 133 if [[ ! -f "$whiteListFile" ]]; then 134 ${pkgs.coreutils}/bin/install -m 644 -D \ 135 "${storeAesmFolder}/data/white_list_cert_to_be_verify.bin" \ 136 "$whiteListFile" 137 fi 138 ''; 139 ExecStart = "${sgx-psw}/bin/aesm_service --no-daemon"; 140 ExecReload = ''${pkgs.coreutils}/bin/kill -SIGHUP "$MAINPID"''; 141 142 Restart = "on-failure"; 143 RestartSec = "15s"; 144 145 DynamicUser = true; 146 Group = "sgx"; 147 SupplementaryGroups = [ 148 config.hardware.cpu.intel.sgx.provision.group 149 ]; 150 151 Type = "simple"; 152 153 WorkingDirectory = storeAesmFolder; 154 StateDirectory = "aesmd"; 155 StateDirectoryMode = "0700"; 156 RuntimeDirectory = "aesmd"; 157 RuntimeDirectoryMode = "0750"; 158 159 # Hardening 160 161 # chroot into the runtime directory 162 RootDirectory = "%t/aesmd"; 163 BindReadOnlyPaths = [ 164 builtins.storeDir 165 # Hardcoded path AESM_CONFIG_FILE in psw/ae/aesm_service/source/utils/aesm_config.cpp 166 "${configFile}:/etc/aesmd.conf" 167 ]; 168 BindPaths = [ 169 # Hardcoded path CONFIG_SOCKET_PATH in psw/ae/aesm_service/source/core/ipc/SocketConfig.h 170 "%t/aesmd:/var/run/aesmd" 171 "%S/aesmd:/var/opt/aesmd" 172 ]; 173 174 # PrivateDevices=true will mount /dev noexec which breaks AESM 175 PrivateDevices = false; 176 DevicePolicy = "closed"; 177 DeviceAllow = [ 178 # legacy out-of-tree driver 179 "/dev/isgx rw" 180 # DCAP driver 181 "/dev/sgx rw" 182 # in-tree driver 183 "/dev/sgx_enclave rw" 184 "/dev/sgx_provision rw" 185 ]; 186 187 # Requires Internet access for attestation 188 PrivateNetwork = false; 189 190 RestrictAddressFamilies = [ 191 # Allocates the socket /var/run/aesmd/aesm.socket 192 "AF_UNIX" 193 # Uses the HTTP protocol to initialize some services 194 "AF_INET" 195 "AF_INET6" 196 ]; 197 198 # True breaks stuff 199 MemoryDenyWriteExecute = false; 200 201 # needs the ipc syscall in order to run 202 SystemCallFilter = [ 203 "@system-service" 204 "~@aio" 205 "~@chown" 206 "~@clock" 207 "~@cpu-emulation" 208 "~@debug" 209 "~@keyring" 210 "~@memlock" 211 "~@module" 212 "~@mount" 213 "~@privileged" 214 "~@raw-io" 215 "~@reboot" 216 "~@resources" 217 "~@setuid" 218 "~@swap" 219 "~@sync" 220 "~@timer" 221 ]; 222 SystemCallArchitectures = "native"; 223 SystemCallErrorNumber = "EPERM"; 224 225 CapabilityBoundingSet = ""; 226 KeyringMode = "private"; 227 LockPersonality = true; 228 NoNewPrivileges = true; 229 NotifyAccess = "none"; 230 PrivateMounts = true; 231 PrivateTmp = true; 232 PrivateUsers = true; 233 ProcSubset = "pid"; 234 ProtectClock = true; 235 ProtectControlGroups = true; 236 ProtectHome = true; 237 ProtectHostname = true; 238 ProtectKernelLogs = true; 239 ProtectKernelModules = true; 240 ProtectKernelTunables = true; 241 ProtectProc = "invisible"; 242 ProtectSystem = "strict"; 243 RemoveIPC = true; 244 RestrictNamespaces = true; 245 RestrictRealtime = true; 246 RestrictSUIDSGID = true; 247 UMask = "0066"; 248 }; 249 }; 250 }; 251}