Building and measuring the AWS Nitro Enclave

In the previous section, you encrypted some data and stored it in an AWS S3 bucket or in your local filesystem as an encrypted configuration file. In this section, you will build an AWS Nitro Enclave, and you will grant this enclave permission to decrypt the encrypted configuration file.

Prerequisites

The instructions in this section assume the following:

  • You completed the steps on the previous page

  • You are running the commands in this section on an AWS Nitro-based instance that was set up with the Anjuna Nitro Runtime

Additionally, the AWS Nitro-based EC2 instance must be associated with the correct IAM role (the same IAM role used for the AWS KMS key policy).

The AWS IAM role is critical for allowing enclaves to connect to AWS KMS without using credentials. If the AWS Nitro-based EC2 instance is not granted permission to access KMS, the AWS Nitro Enclave will not be able to decrypt any data.

It is also important to note that the permissions associated with this role do not allow the parent instance to decrypt data. It just gives the EC2 instance the ability to authenticate to KMS.

You should have the following variables defined and set with the correct values:

$ export AWS_DEFAULT_REGION=<your-region>
$ export KMS_KEY_ID=<your-kms-key>
$ export AWS_S3_BUCKET=<your-s3-bucket>     # if storing secrets in an S3 bucket
$ export ENCRYPTED_CONFIG=<config-filename> # if storing secrets in a local file

Create the enclave configuration file

Create a file named enclave-config.yaml, which specifies the URI to the encrypted secrets. The sections below show two examples of enclave configuration files; one for encrypted secrets stored in an AWS S3 bucket, and another for encrypted secrets stored in a local file.

You cannot run enclaves providing encrypted secrets stored in AWS S3 and local files at the same time. Trying to do so will result in an enclave startup error.

S3 bucket secrets

If storing encrypted secrets in an AWS S3, you must specify the S3 URI in the uri of an s3 type encryptedConfig entry. You must specify an allow list in enclave-config.yaml for the environment variables and files that are allowed to be overridden by the encrypted secrets, by setting the field encryptedConfig.allowList.

version: 1.8

command: [/bin/sh, -c, "printenv|sort; cat /etc/my-application-startup.conf"]

encryptedConfig:
  type: s3
  uri: s3://<YOUR-S3-BUCKET>/kms-encrypted-data.bin
  allowList:
    environment:
      - INITDB_ROOT_USERNAME
      - INITDB_ROOT_PASSWORD
    files:
      - /etc/my-application-startup.conf
The URL specified in uri must point to the file encrypted with the anjuna-nitro-encrypt tool on the previous page.

In the example above, the command entry instructs the Anjuna Nitro Runtime to execute the command printenv | sort and show the content of the file /etc/my-application-startup.conf (instead of the default ENTRYPOINT of the Docker image used to create the enclave). It shows the content of the environment variables defined in the enclave, including the decrypted values specified from the secrets stored in the AWS S3 bucket.

If the encrypted secret file tries to set an environment variable or file that is not allowed by the allow list, the enclave will fail to start.

Local file secrets

If storing encrypted secrets in a local file, the path to the encrypted file will be provided to the enclave as a runtime parameter. The enclave configuration (enclave-config.yaml) must specify an allow list for the environment variables and files that can be overridden by the local encrypted file, by setting the field encryptedConfig.allowList.

version: 1.8

command: [/bin/sh, -c, "printenv|sort; cat /etc/my-application-startup.conf"]

encryptedConfig:
  type: local
  allowList:
    environment:
      - INITDB_ROOT_USERNAME
      - INITDB_ROOT_PASSWORD
    files:
      - /etc/my-application-startup.conf

In the example above, the command entry instructs the Anjuna Nitro Runtime to execute the command printenv | sort and show the content of the file /etc/my-application-startup.conf (instead of the default ENTRYPOINT of the Docker image used to create the enclave). It shows the content of the environment variables defined in the enclave, including the decrypted values specified from the secrets stored in the local file.

If the encrypted secret file tries to set an environment variable or file that is not allowed by the allow list, the enclave will fail to start.

Be mindful when allowing environment variables and files to be set by a local encrypted configuration file, since anyone with access to the parent instance can set those to arbitrary values. Make sure that those environment variables and files cannot alter the application behavior in way that is not desired.

One example is if your application takes a REMOTE_LOG_URL environment variable to write logs to a remote server. In this case, an attacker with access to the parent instance could start a new enclave and set REMOTE_LOG_URL to an attacker-controlled URL, exposing potentially-confidential log contents. This risk can be mitigated by techniques like cert pinning.

Building a simple AWS Nitro Enclave

$ anjuna-nitro-cli build-enclave \
    --docker-uri amazonlinux \
    --enclave-config-file enclave-config.yaml \
    --output-file nitro-kms.eif

This should produce the following output:

Start building the Enclave Image...
Enclave Image successfully created.
{
  "Measurements": {
    "HashAlgorithm": "Sha384 { ... }",
    "PCR0": "80cabd5643bccbc644bc299361b28d0fc095145733e4ef0552cf3491339d487fca325f1b497478bcf40d934051e79367",
    "PCR1": "a5b4408152040f6ec87941abc5788d63ba1e74be5714408a271c5081ede76bfdfed00b84d3f04d31e51b844d22f343b8",
    "PCR2": "fda83c68b97a328d07b7668897b34e5f705f2eec3035603fc65bbf1c93d9c240641220c8ffaa1d5d1a2e4dcc4831699e"
  }
}

Save the PCRxx values above since they are needed later to update the AWS KMS policy associated with your AWS KMS key.

The PCRxx values can always be recomputed by running the describe-eif command:

$ anjuna-nitro-cli describe-eif --eif-path nitro-kms.eif