- Nov 23, 2023
How we built EGo
Confidential computing enables the always-encrypted and verifiable processing of data --- in the cloud and elsewhere. Developing confidential apps used to require arcane knowledge and significant code changes. With EGo, you can skip that and develop your Go code as usual. With EGo, you don't need to refactor your app to run it in a secure enclave. Just use three simple commands to build, sign, and run your code --- be it 10 or 100,000 lines of Go with complex dependencies. Best thing? EGo is completely open-source.
In this blog post, we share EGo's design approach, the biggest challenges we faced while developing EGo, and some of our key principles. Furthermore, we give a small preview of what else is planned for EGo in the future.
Our design approach
When we started our work on EGo, we had already built an SDK for Trusted Execution Environments called Edgeless RT. This project was our internal solution for comprehensive Go support, but like most other SDKs, it had significant entry barriers for new users. While using RT, we asked ourselves how we could make confidential computing more accessible; especially for new users who are taking their first steps in the confidential computing community.
Our vision was clear: we wanted to create an SDK that offers meaningful ease of use. We wanted to achieve this by sticking as closely as possible to the known and proven Go UX. This would be done by carefully choosing which specifics of confidential computing to highlight and which to ignore, moving some of the more confusing aspects into the background so the most relevant features take the center stage.
After careful consideration, building the SDK based on Go felt like a natural choice. First off, Go is one of the most relevant and straightforward programming languages. On top of that, its memory safety features provide a desirable layer of security. But most of all, we wanted to provide a simple solution for developers who are interested in confidential computing security features but not necessarily in the ins and outs of the discipline. It was a logical step to tailor EGo to those use cases which can benefit from confidential computing the most --- and since the cloud-native space offers the largest potential for such implementations, we sought to support its leading programming language.
It is difficult to predict what standards will be established in confidential computing in the future, but we think it is likely that, sooner or later, most real-world apps will run most of their code within the enclave by default. By moving all code into the enclave, porting already existing applications becomes a straightforward process.
Challenges we faced during development
When porting Go to the enclave, we had to deal with some technically challenging specifics of the language and its compiler. One is how Go programs access the operating system's services like filesystems or network sockets. Most languages on Linux that compile to native code interface with libc. (libc implements the standard C library as well as the POSIX API.) libc, in turn, executes system calls to request services from the OS's kernel. Go however directly executes SYSCALLs itself. Inside an enclave, this is an illegal instruction since nothing is supposed to access anything outside the TEE by design. To solve this, we had to modify the Go compiler such that SYSCALLs are redirected to libc instead:
TEXT runtime·connect(SB),NOSPLIT,$0-28 MOVL fd+0(FP), DI MOVQ addr+8(FP), SI MOVL len+16(FP), DX MOVL $SYS_connect, AX // SYSCALL CALL runtime·invoke_libc_syscall(SB) MOVL AX, ret+24(FP) RET // EDG: This function is called in place of the SYSCALL instruction. TEXT runtime·invoke_libc_syscall(SB),NOSPLIT,$0 // syscall args in rdi, rsi, rdx, r10, r8, r9 // syscall number in rax // Switch to g0 stack. // [...] // Call // long syscall(long number, ...); // with System V AMD64 calling convention: // first 6 args in rdi, rsi, rdx, rcx, r8, r9 // additional args on the stack MOVQ R9, (SP) MOVQ R8, R9 MOVQ R10, R8 MOVQ DX, CX MOVQ SI, DX MOVQ DI, SI MOVQ AX, DI CALL libc_syscall(SB) // [...] RET
The enclave's libc/syscall layer then either handles syscalls internally or calls out to the host, e.g., to write files or send data on a network.
Additionally, we had to extend Open Enclave. Open Enclave is one of the most mature SDKs in the confidential computing realm, but it still lacks some essential POSIX features such as pthread and mmap. Luckily, we had already built an extended version of Open Enclave when we started the development of EGo: Edgeless RT. You can find Open Enclave here, it is a project with exceptional code quality.
Key approaches we followed for EGo
Think from the end: With EGo, we ignored everything we knew about workflows from other CC SDKs. Our approach puts the user first. Therefore, we kept EGo as close as possible to Go, while adding the key features of signing, attestation, and sealing.
Design tools and APIs such that they are hard to use incorrectly: EGo removes the need to take a deep dive into advanced confidential computing topics such as required crypto parameters. Instead, when a user calls "ego sign myapp", EGo simply generates a fitting key if none exists yet. The same happens with "SealWithProductKey(plaintext byte)": this API function handles all the SGX sealing details like adding some metadata to ensure that the key remains valid after a CPU microcode update. This makes development simple as well as secure and gently nudges users towards using EGo correctly from the start.
Implementation is key: With EGo, we split our development duties between three devs: One developer acted as the product owner and first created a working prototype to ensure the feasibility of the project. Further implementation was then planned in detail by all three developers, who then split the workload among themselves. Naturally, this took additional time but simultaneously ensured high quality via the common project base, which was then expanded iteratively with unit tests, integration tests, and code reviews.
What does the future hold for EGo?
Although EGo already makes it super easy to build and deploy Go confidential apps, we're just getting started. Here is a short overview of the features we are currently working on:
Reproducible builds: We think that confidential computing especially makes sense in combination with open source: the meaningfulness of a remote attestation statement over a piece of closed source code is limited. Users should be able to make a connection from an attestation report to, e.g., a Github project. Ideally, an enclave's identity should map an exact source code version. To achieve this, we will add reproducible builds to EGo so that (advanced) users can compile an app and compare the resulting enclave hash with the one from the attestation report.
Simplified attestation on machines outside the cloud: Currently, if you would like to run EGo outside of a cloud context, you have to set up some attestation infrastructure. Of course, this is tedious and does not match the simplicity we are going for. That's why we are thinking of ways to simplify attestation so that EGo can be used on dev machines or on-premises deployments without any further hassle.
Transparent file encryption: This is a feature that is still in the consideration stage. File encryption in a confidential computing context is trickier to get right than in a conventional context, which is why some SDKs don't offer it in the first place. Those that do, either have flaws or usage limitations. Currently, EGo has an unencrypted host filesystem and a temporary in-enclave-memory filesystem. Our goal would be to complement this with the ability to mount directories with transparent encryption.
Curious now? If you want to learn more about EGo you should check out our GitHub repo or just get started with the following commands:
Also, you should check out the webinar "Build Confidential Go Apps with Ease" held by EGo maintainer Moritz Eckert on June 30. Click here to register for free.
- Jul 28, 2023
- Nov 9, 2022