First Steps with AWS Nitro: hello-world
At its core, the process of starting an AWS Nitro Enclave includes the following steps:
-
identify a Docker image that contains an application,
-
convert the Docker image into an Enclave Image File (EIF),
-
start an AWS Nitro Enclave using the previously created Enclave Image File.
Using the Anjuna Nitro Runtime, you can automatically start many of the existing containers in an AWS Nitro Enclave, even if the applications in those containers were not updated to run on AWS Nitro. The first benefit of using the Anjuna Nitro Runtime tools is that it allows you to lift-and-shift many of the existing containers into an AWS Nitro Enclave. Without the Anjuna Nitro Runtime, the applications in those containers would have to be modified to be compatible with AWS Nitro.
Depending on the needs of the application, other optional steps will be needed:
-
starting and configuring specific services (networking, configuration) designed to securely support the software running in the AWS Nitro Enclaves
-
creating secrets (using KMS) that can securely be passed into the enclave for the application to use
-
automatically creating enclaves in an AWS EKS cluster
In this section, you will learn about the basic usage of the Anjuna Nitro Runtime tools to build and run a simple enclave.
Identify a Simple Docker Image
The Anjuna Nitro Runtime includes a sample application (hello) to get started with AWS Nitro. It is a minimal application that continuously prints Hello from the enclave side every 5 seconds, until the enclave is terminated.
It is important that the application running in the enclave does not exit immediately. When the application defined in the ENTRYPOINT or CMD directives finishes, the enclave also terminates, which will prevent us from observing its existence. |
Build the Docker Image
The sample application is located in the following folder:
/usr/share/nitro_enclaves/examples/hello
To build the container, run the following command:
$ docker build /usr/share/nitro_enclaves/examples/hello -t hello-enclave
If the command succeeded, you should see the newly built Docker image (which was tagged as hello-enclave) when running this command:
$ docker image ls hello-enclave
Build an enclave image file (EIF)
Once the Docker image is available, you can build an Enclave Image File from it:
$ anjuna-nitro-cli build-enclave --docker-uri hello-enclave:latest --output-file hello-enclave.eif
The command above should produce some output that looks like this:
Start building the Enclave Image... Enclave Image successfully created. { "Measurements": { "HashAlgorithm": "Sha384 { ... }", "PCR0": "00bad9b9d306537bc8b7059fa2f9c9e8a6501552f1325bda0454f28b0d2eb45c0782055f11c86275281f5b54be53511c", "PCR1": "cde04bd3a43c742edee3a7e9a323f67cbbaca4c765221419d1b53dd5eea1998ffaf65b324947f26655c25ebba2deec0a", "PCR2": "413bd40f7184f9ec42599ea2113da16eb8408f8491245e8aef05c3f3fcb435eb01a1f36b71f8716b379bf9e2b18cadcd" } }
If the command succeeds, it will print the enclave measurements, which are the hashes that uniquely identify an enclave. To learn more about enclave measurements, see this page: https://docs.aws.amazon.com/enclaves/latest/user/set-up-attestation.html#where
Any combination of the measurement values can be used to create policies that describe which operations are allowed by this enclave on AWS objects stored in services that are integrated with AWS Nitro Attestation (AWS KMS, for example).
Enable Networking for the AWS Nitro Enclave
This command needs to be run once (it’s not necessary to run the command every time an enclave is created), but since the changes are not persistent, if the parent host is rebooted, it should be run again.
$ /opt/anjuna/nitro/bin/anjuna-nitro-netd-parent --daemonize
Run the enclave
Now that you have built the Enclave Image File, you can create and start an enclave that will run this hello-enclave application:
$ anjuna-nitro-cli run-enclave --cpu-count 2 --memory 1024 --eif-path hello-enclave.eif --debug-mode
The previous command is reserving 2 vCPUs for running the enclave, as well as 1024MB of RAM. These values are appropriate for the sample application. The number of vCPU cores must be an even number due to hyperthreading. |
If the command above succeeded, your should see some output that looks like this:
Start allocating memory... Started enclave with enclave-cid: 17, memory: 1024 MiB, cpu-ids: [1, 3] { "EnclaveID": "i-0f2c4b721470e92c4-enc1776bc0278e90b9", "ProcessID": 13823, "EnclaveCID": 17, "NumberOfCPUs": 2, "CPUIDs": [ 1, 3 ], "MemoryMiB": 1024 }
The EnclaveID value may be needed when it’s time to terminate the enclave. When an enclave is running, its basic attributes can be retrieved with the following command:
$ anjuna-nitro-cli describe-enclaves
Instead of using copy/paste to specify the value of EnclaveID, the rest of this document will automatically retrieve it by using the following command:
This command simply captures the description of the currently running enclave
( |
Since the enclave was started in debug mode (the anjuna-nitro-cli run-enclave
command was invoked with
the --debug-mode
flag), you can view the output of the application using the following command:
$ anjuna-nitro-cli console --enclave-id $(anjuna-nitro-cli describe-enclaves | jq -r .[0].EnclaveID)
If the enclave is running, you will see some output that looks like this:
[ 40] Hello from the enclave side! [ 41] Hello from the enclave side! [ 42] Hello from the enclave side! [ 43] Hello from the enclave side! [ 44] Hello from the enclave side! [ 45] Hello from the enclave side!
Press CTRL+C to stop watching the application output (this won’t stop the enclave, it will just stop inspecting the console log).
Congratulations, you have created a simple AWS Nitro Enclave! |
Finally, to terminate the enclave, run the following command:
$ anjuna-nitro-cli terminate-enclave --all