Summary
Setting up EC2
First we need to launch an EC2 instance to host our secure enclave. We call this instance a Parent instance.
Enclaves could run on most of the Linux and Windows EC2 instances. But you need to have enough vCPUs to allow hypervisor to use some of it for the isolated environment. Technically you can run up to 4 Enclaves inside a single Parent instance.
- Navigate to EC2 Dashboard in AWS and click on Launch Instance.
- Choose Amazon Linux as operating system and choose
c5.xlargefor instance type - Make sure to set Enclave to
enabled - Make sure the instance has a public IP address and allows traffic to SSH
Launch the instance and take note of the IP address.
Connect with SSH
In this step we want to make sure our computer is able to connect to SSH properly and then we use VS Code to connect through SSH.
Copy the keypair you downloaded from AWS to your SSH directory and adjust file permissions:
cp my-keypair-2025.pem ~/.ssh/
chmod 400 my-keypair-2025.pem
Open the file ~/.ssh/config with your editor of choice (create the file if it’
s not there) and add this block:
Host ec2-enclave
HostName Your EC2 Public IP
Port 22
IdentityFile ~/.ssh/my-keypair-2025.pem
User ec2-user~/.ssh/config
Open the VsCode and press Option+Shift+p and type Remote SSH: Connect to Host and press enter. Select the ec2-enclave from the list and should be connected to the new EC2 environment.
Writing the Code
In this example we write a very basic code in Go to process the encrypted data without revealing it to the outside world.
package main
import (
"context"
"encoding/base64"
"fmt"
"io"
"log"
"os"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/kms"
)
func main() {
ctx := context.Background()
input := ""
encrypted, err := base64.StdEncoding.DecodeString(input)
if err != nil {
log.Fatal("Failed to decode base64:", err)
}
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatal("Failed to load config:", err)
}
client := kms.NewFromConfig(cfg)
// Decrypt with KMS
result, err := client.Decrypt(ctx, &kms.DecryptInput{
CiphertextBlob: encrypted,
})
if err != nil {
log.Fatal("Decryption failed:", err)
}
// Check if matches secret
decrypted := string(result.Plaintext)
if decrypted == "This is my secret" {
fmt.Println("SUCCESS: Secret validated!")
} else {
fmt.Println("FAILURE: Secret does not match")
os.Exit(1)
}
}main.go
Building Enclave Image with Nitro CLI
We need the Nitro CLI to build and run our Enclaves. Build step could be done on another host as well, which in a proper DevOps setup it will be likely the same place you build your dockers. Most likely a CI/CD environment, but it could only be built on a Linux machine!
You can run your enclaves on both Windows and Linux environments (not Mac).
Install Nitro CLI with this command if you are on Amazon Linux 2023 (or other RHEL variants). Otherwise, check out this link to learn more for other options.
sudo dnf install aws-nitro-enclaves-cli -y
Use the CLI to build the image:
docker build -t enclave-server .
# Convert to EIF
nitro-cli build-enclave \
--docker-uri enclave-server:latest \
--output-file server.eif
Multiparty Scenario
Customer A
In this scenario, customer A has some encrypted data which they are not willing to share with Company B. However, they need company B to process this data in a mutually trusted execution environment. Customer A audit the code for an enclave running by Company B and grant this enclave access to their KMS.
Company B is not able to deploy a different code to their enclave after the audit process, because KMS permission is only granted to the enclave that is running the audited code. This is possible because IAM policy is granted to a cryptographic hash of the specific image that is retrived through a process called attestation. (Don’t worry about it now)
Customer visits their AWS account and create a customer managed key in KMS. Create a Symmetric key and leave everything else as default. Remember to copy the ARN of the key.
- Now customer tries to encrypt some data:
aws kms encrypt \
--key-id arn:aws:kms:eu-central-1:CUSTOMER_A_ACCOUNT_ID:key/c7567937-ee1e-407b-9f24-b1ca5e0f1b36 \
--plaintext fileb://<(echo -n "My sensitive data only for Enclave") \
--output text \
--query CiphertextBlob
## Encrypted data: AQICAHjkYU6WdTvfaXb/Y2BFhtstonly25KuB8vKCPoIfVJ0KgGCfWVY...
Now customer is ready to share their data for processing to Company B!
Use envelope encryption in production! The process is similar but this is easier to demonstrate.
Company B
In this side, company is received encrypted data from their customer and the only way they can access this data is within the Enclave. They are not able to view the data, SSH into the enclave, transfer it throuhg the network or log it anywhere unless this is included as part of the code that Customer A audited!
All company B has to do is to transfer the data into the Parent Host and run the Enclave to process the data:
Use the terminal in our SSH connected VS Code and run this:
nitro-cli run-enclave \
--eif-path server.eif \
--memory 512 \
--cpu-count 2