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