Familiarity with the basic concepts of Intel® SGX and SCONE framework.
Please make sure you have already checked the quickstart and Your first application tutorials before building your trusted application on iExec.
After understanding the fundamentals of Confidential Computing and explaining the technologies behind it, it is time to roll up our sleeves and get hands-on with enclaves. In this guide, we will focus on protecting an application - that is already compatible with the iExec platform - using SGX, and without changing the source code. That means we will use the same code we previously deployed for a basic iExec application.
How would the enclave verify the integrity of the code?
The short answer is: the application is protected by taking a snapshot of the file system's state. The TEE image will use the fspf feature of SCONE to authenticate the file system directories that would be used by the application (/bin, /lib...) as well as the code itself. It takes a snapshot of their state that will be later shared with the worker (via the Blockchain) to make sure everything is under control. If we change one bit of one of the authenticated files, the file system's state changes completely and the enclave will refuse to boot since it considers it as a possible attack.
Prepare your application
Create a directory tree for your application in ~/iexec-projects/.
constfsPromises=require("fs").promises;constfiglet=require("figlet");(async () => {try {constiexecOut=process.env.IEXEC_OUT;// Do whatever you want (let's write hello world here)constmessage=process.argv.length>2?process.argv[2] :"World";consttext=figlet.textSync(`Hello, ${message}!`); // Let's add some art for e.g.console.log(text);// Append some results in /iexec_out/awaitfsPromises.writeFile(`${iexecOut}/result.txt`, text);// Declare everything is computedconstcomputedJsonObj= {"deterministic-output-path":`${iexecOut}/result.txt`, };awaitfsPromises.writeFile(`${iexecOut}/computed.json`,JSON.stringify(computedJsonObj) ); } catch (e) {console.log(e);process.exit(1); }})();
src/app.py
import osimport sysimport jsonfrom pyfiglet import Figletiexec_out = os.environ['IEXEC_OUT']# Do whatever you want (let's write hello world here)text ='Hello, {}!'.format(sys.argv[1] iflen(sys.argv) >1else"World")text =Figlet().renderText(text)# Let's add some art for e.g.print(text)# Append some results in /iexec_out/withopen(iexec_out +'/result.txt', 'w+')as fout: fout.write(text)# Declare everything is computedwithopen(iexec_out +'/computed.json', 'w+')as f: json.dump({ "deterministic-output-path" : iexec_out +'/result.txt' }, f)
As we mentioned earlier, the advantage of using SCONE is the ability to make the application Intel® SGX-enabled without changing the source code. The only thing we are going to do is rebuilding the app using the Trusted-Execution-Environment tooling provided by SCONE.
SCONE provides TEE conversion tooling (Python, Java, ..) plus eventually TEE base images for other languages (NodeJs).
Copy the Dockerfile of the non-TEE app:
Dockerfile
# Starting from a base image supported by SCONEFROMnode:14-alpine3.11# install your dependenciesRUNmkdir/app&&cd/app&&npminstallfiglet@1.xCOPY./src/appENTRYPOINT [ "node","/app/app.js"]
Dockerfile
FROMpython:3.7.3-alpine3.10### install python dependencies if you have someRUNpip3installpyfigletCOPY./src/appENTRYPOINT ["python3", "/app/app.py"]
# when your account is ready, run `docker login` to connect the SCONE registrydockerloginregistry.scontain.com
We will use the following script to wrap the sconification process, copy the sconify.sh script in the current directory:
sconify.sh
#!/bin/bash# declare the app entrypointENTRYPOINT="node /app/app.js"# declare an image nameIMG_NAME=tee-hello-worldIMG_FROM=${IMG_NAME}:temp-non-teeIMG_TO=${IMG_NAME}:tee-debug# build the regular non-TEE imagedockerbuild.-t ${IMG_FROM}# pull the SCONE curated image corresponding to our base imagedockerpullregistry.scontain.com/sconecuratedimages/node:14.4.0-alpine3.11# run the sconifier to build the TEE image based on the non-TEE imagedockerrun-it--rm \-v/var/run/docker.sock:/var/run/docker.sock \registry.scontain.com/scone-production/iexec-sconify-image:5.3.15-v12 \sconify_iexec \--name=${IMG_NAME} \--from=${IMG_FROM} \--to=${IMG_TO} \--binary-fs \--fs-dir=/app \--host-path=/etc/hosts \--host-path=/etc/resolv.conf \--binary=/usr/local/bin/node \--heap=1G \--dlopen=2 \--no-color \--verbose \--command=${ENTRYPOINT} \&&echo-e"\n------------------\n" \&&echo"successfully built TEE docker image => ${IMG_TO}" \&&echo"application mrenclave.fingerprint is $(dockerrun-it--rm-eSCONE_HASH=1 ${IMG_TO})"
sconify.sh
#!/bin/bash# declare the app entrypointENTRYPOINT="python3 /app/app.py"# declare an image nameIMG_NAME=tee-hello-worldIMG_FROM=${IMG_NAME}:temp-non-teeIMG_TO=${IMG_NAME}:tee-debug# build the regular non-TEE imagedockerbuild.-t ${IMG_FROM}# run the sconifier to build the TEE image based on the non-TEE imagedockerrun-it \-v/var/run/docker.sock:/var/run/docker.sock \registry.scontain.com/scone-production/iexec-sconify-image:5.3.15-v12 \sconify_iexec \--name=${IMG_NAME} \--from=${IMG_FROM} \--to=${IMG_TO} \--binary-fs \--fs-dir=/app \--host-path=/etc/hosts \--host-path=/etc/resolv.conf \--binary=/usr/local/bin/python3.7 \--heap=1G \--dlopen=2 \--no-color \--verbose \--command=${ENTRYPOINT} \&&echo-e"\n------------------\n" \&&echo"successfully built TEE docker image => ${IMG_TO}" \&&echo"application mrenclave.fingerprint is $(dockerrun-it--rm-eSCONE_HASH=1 ${IMG_TO})"
# make the script executablechmod+xsconify.sh# run the sconify script./sconify.sh
Congratulation you just built your first TEE application.
The sconify.sh script prints the generated docker image name, you must retag this image and push it on dockerhub.
You may have noticed the tee-debug flag in the image name, the built image is actually in TEE debug mode, this allows you to have some debug features while developping the app. Once you are happy with the debug app, contact us to go to production!
Test your app on iExec
At this stage, your application is ready to be tested on iExec. The process is similar to testing any type of application on the platform, with these minor exceptions:
Deploy the TEE app on iExec
TEE applications require some additional information to be filled in during deployment.
# prepare the TEE application templateiexecappinit--tee
Edit iexec.json and fill in the standard keys and the mrenclave object:
{ ..."app": {"owner":"0xF048eF3d7E3B33A465E0599E641BB29421f7Df92",// your address"name":"tee-hello-world",// application name"type":"DOCKER","multiaddr":"docker.io/username/tee-hello-world:1.0.0",// app image"checksum":"0x15bed530c76f1f3b05b2db8d44c417128b8934899bc85804a655a01b441bfa78",// image digest"mrenclave": {"provider":"SCONE",// TEE provider (keep default value)"version":"v5",// Scone version (keep default value)"entrypoint":"node /app/app.js" OR "python3 /app/app.py",// your app image entrypoint"heapSize":1073741824,// heap size in bytes (1GB) "fingerprint": "eca3ace86f1e8a5c47123c8fd271319e9eb25356803d36666dc620f30365c0c1" // fingerprint of the enclave code (mrenclave), see how to retrieve it below
} }, ...}
Run your TEE image with SCONE_HASH=1 to get the enclave fingerprint (mrenclave):
Specify the tag --tag tee in iexec app run command to run a tee app.
One last thing, in order to run a TEE-debug app you will also need to select a debug workerpool, use the debug workerpool v7-debug.main.pools.iexec.eth.
The debug workerpool is connected to a debug Secret Management Service (this is fine for debugging but do not use to store production secrets), we will need to init the storage token on this SMS.
These sed commands will do the trick:
# set a custom bellecour SMS in chain.jsonsed-i's|"bellecour": {},|"bellecour": { "sms": "https://v7.sms.debug-tee-services.bellecour.iex.ec" },|g'chain.json
# initialize the storageiexecstorageinit--chainbellecour
# restore the default configuration in chain.jsonsed-i's|"bellecour": { "sms": "https://v7.sms.debug-tee-services.bellecour.iex.ec" },|"bellecour": {},|g'chain.json
You noticed we used v7-debug.main.pools.iexec.eth instead of an ethereum address, this is an ENS name. The ENS (Ethereum Name Service) protocol enables associating decentralized naming to ethereum addresses.
Next step?
In this tutorial, you learned how to leverage your application with the power of Trusted Execution Environments using iExec. But according to your use case, you may need to use some confidential data to get the full potential of the Confidential Computing paradigm. Check out the next chapter to see how.