Best Practices

Enclaves are designed to be flexible to fit your development process. Here are a few best practices to set you up for success.

Writing the Dockerfile

Since Enclaves are built using Docker, a good place to start is making sure that you are formatting your Dockerfile correctly.

First you need to use the FROM command which will create a layer from the Docker image you wish to use. It’s best to use one of the container images available on Docker Hub to ensure you are using a trusted source. You can also opt for using the slim version of the container which can help reduce the image size, however the slim versions may not contain all of the common packages in the default tag.

Next you will need to copy any files from your local source to the filesystem of the container. It’s best to use absolute paths in the Dockerfile. When your Docker container is converted to an Enclave, your commands might not be run in the directory you expect them to be, so it is safer to reference your files as absolute paths.

Make sure that you are exposing the non-reserved port you want to listen on since that is where traffic within the Enclave will be forwarded. The Enclaves documentation uses PORT 8008 as an example, but this can be any available port that you define.

Here are some examples of what your Dockerfile might look like.

Node.js

Java

For Java and other compiled languages, you may need to use a multi-stage build that involves first creating a build stage and then a package stage.

Ruby

Docker will then build images by reading the instructions from your Dockerfile. The default instance size supports up to 2GB Docker images.

You can check the size of your Docker image using the docker inspect command

Run Your Server Locally with Docker

One helpful step you can take is to try containerizing your application before deploying the container inside a Enclave. If it can run with Docker, it should be able to run in a Enclave, and it will help you debug errors that may exist from the Docker build before you attempt to run it in a Enclave.

Once you have your app ready including the Dockerfile, navigate to the directory containing the Dockerfile, then run the following command:

Next, you can start the container using docker run along with the name of your image and the container port that you exposed in the Dockerfile mapped to the host port.

Now if you go to the host port http://localhost:8080 you should see your app running. You can also check the Docker Desktop app or CLI to confirm that the container is running.

Package Management

Some of the instructions in your Dockerfile will install required packages. You can use whichever package manager makes sense for your application.

In some cases, you may want to use a manifest file that will contain the required packages and their versions, like a package.json for Node or requirements.txt for Python.

For Python specifically, it can also be helpful to use a virtual environment. You can run the virtual environment within the container and then install the packages within the environment. This will also help with minimizing image size.

Here is an example:

Encrypting and Decrypting within the Enclave

By design, data that is encrypted with Evervault that passes into the Enclave will automatically decrypt. There is no further action required to decrypt and start using the data.

You also can utilize /encrypt and /decrypt endpoints that are exposed on an in-Enclave API listening on port 9999 within the enclave. These are not available outside of the enclave, so if you have publicly available endpoints within your app that use the same naming, there should not be any conflict.

These endpoints are available for all Enclaves. Here is an example of how you might implement it in Node.

To encrypt data, you can make a request to /encrypt and pass in any data that you wish to encrypt as JSON.

The purpose of the decryption API is to offer flexibility with applications built inside the Enclave. Examples could be if you need to upload a list of large files of encrypted data to be decrypted on start up of the Enclave or a process that pulls in encrypted data from an external source.

Another point to note is that when TLS termination is turned off in the data plane, it’s not possible for the request to be scanned for encrypted strings. This is another instance where the Decrypt API could be used.

Here is an example of how to consume the Decrypt API.

To decrypt data you can make another request to /decrypt and pass in the encrypted string as JSON.

Attest your Connection

The Evervault Client SDKs for Node, Python, Go, iOS and Android all expose attestation helpers which will perform attestation on every connection to your Enclave. This is done by pulling an attestation document from the Enclave, and comparing its signed PCRs against the set of PCRs provided to the SDKs. If the PCRs are found to match, the challenge from the attestation document is compared against the certificate public key to confirm that the TLS connection is being terminated inside the Enclave. A more detailed discussion of our attestation in TLS can be found here.

Note: When running your Enclave in debug mode, every value in the attestation document returned will be 0, so if you need to check the attestation measures do not use the --debug flag when initializing the Enclave.

Below are code snippets showing how to configure your Evervault SDK to enable attestation.

Node.js

This takes in a set of expected PCRs and validates they are returned in the TLS handshake of requests sent to the Enclave. You can pass in a single PCR value as an object or multiple PCR values as an array of objects.

Python

This is the same behavior in Python. You can pass in a single PCR value as a dictionary or multiple PCR values as a list of dictionaries.

You can then validate it locally using the ev enclave attest command in the CLI. This will validate that the PCRs in the enclave.toml file match the PCRs returned in the handshake.

The attestation doc for an Enclave is publicly accessible through the /.well-known/attestation endpoint. This allows the Evervault SDKs to poll the attestation document and detect any changes resulting from deployments.

You can request the attestation document using the following curl command:

Enable Transaction Logging

To turn logging off or on, you will need to define trx_logging = true or trx_logging = false in your enclave.toml. You can also leave it undefined and it will be turned on because the default state is set to true.

From there you should be able to see all of your calls to the Enclave in the Enclaves Dashboard under Activity.

Screenshot of the Enclaves Activity Log

You can also find a unique ID from the request and can use that ID to search for a specific call in case you have many calls to look through.

Screenshot of the Enclaves Activity Log with ID

Access Client IP Addresses

There are two ways to see the original IP on the connection.

When using TLS Termination, the IP will be included in the HTTP X-Forwarded-For header.

If you have TLS Termination disabled, you can receive the client IP via proxy protocol by setting the FORWARD_PROXY_PROTOCOL environment variable in your Enclave.