Persistent storage
The Anjuna Nitro Runtime provides a seamless experience for running AWS Nitro Enclaves with persistent storage. This section describes the persistent storage options that the Anjuna Nitro Runtime supports and describes setting up AWS Nitro Enclaves with persistent storage.
Block mounts & basic mounts
The Anjuna Nitro Runtime provides two methods to store persistent data: block mounts and basic mounts. Both options look the same from within the enclave and provide a persistent mount point.
Block mounts allow persisting data inside an enclave, and they are more performant than basic
mounts.
Block
mounts are created and managed by the Anjuna Nitro Runtime.
Block
mounts are persistent, and the data is saved on the parent instance.
However, only one enclave can access the contents of the block
mount,
and neither the parent instance nor another enclave can mount that volume when it is in use by an
enclave.
You can create multiple block
mounts with different sizes.
A single enclave can mount a maximum of one volume at a time.
Basic mounts allow binding a file or a directory and its contents from the parent instance into
an enclave.
It is less performant compared to block
mounts but does not require creating a dedicated volume.
As opposed to block mounts, basic mounts can be shared between enclaves on the same host.
Persistent storage security
Persistent volume mounts provide shared storage between the AWS Nitro Enclave and the
untrusted parent instance.
This is a convenient way to externally configure an enclave application,
provide input data, obtain results from an enclave,
or share data between enclaves on the same host.
However, if used incorrectly,
this feature can open up vulnerabilities that could compromise the security of the enclave,
either by exposing sensitive data or by allowing an attacker to modify the operation of the
enclave application.
Therefore, it is important that the end user analyze the potential implications of opening access
to an untrusted mount directory (the mountPath
) and ensure that the enclave application does not
trust any data within the file tree of a volume mount or access it by a method that could
compromise security.
Some examples of potential security issues created by shared storage:
-
The enclave application reads configuration files from a volume mount, but allows for configuration options that are critical to the operation of the enclave and could be used to modify execution or obtain sensitive information.
-
The enclave application reads configuration files from a volume mount, does not allow critical options to be specified in the config, but due to a security bug (such as a buffer overflow in the config parser) allows an attacker to gain control of the enclave application.
-
The enclave application uses a volume mount for config files, but may also store sensitive data such as log files, which are exposed to the untrusted parent instance.
-
The enclave application provides a way to customize functionality through external scripts or executables that are within a volume mount. These executables would be under the control of the parent instance and could therefore be used to take control of the enclave application or modify its execution.
-
The enclave application accesses shared libraries on a volume mount, which allows an attacker to execute arbitrary code.
There are additional security implications of the forceMount
option. This option provides a convenient
way to mount over existing content in a docker image. This is useful when the docker image is distributed
by a third party or is not easily changed. However, if used incorrectly it can expose the enclave application
data or introduce additional vulnerabilities. The most secure option is to remove the conflicting resource
from the docker image, when creating the EIF file. However, if this is not practical, then the forceMount
option can be used to overwrite the target mountPath
.
In order to limit the scope of the override,
this option uses individual flags to specify the type of resources that will be overwritten.
These flags should be limited to the expected type of conflicting resources.
If, for example,
a docker image has an empty directory for configuration files that the user wants to configure
externally from the parent instance,
the forceMount
option could be set to empty
, as shown below:
mounts:
- type: basic
name: example-volume
mountPath: /etc/app
forceMount: empty
If instead of empty
, the all
option was used, an update to the docker image by the third party,
with a new unexpected feature that has an executable script or shared library executed by the
application now in the volume mountPath
,
would expose the application to an attack when a new EIF image is built.
With the more restrictive option, a newly built EIF image would fail to start,
recognizing that there are now files where an empty directory was expected.
The full
option can be used in cases where a directory contains content that the persistent
storage should be mounted over.
However, there are no checks in this case on what the content of the directory is and whether it
might change something critical in the docker image.
This flag should be considered the least secure flag with the forceMount
option.