Volumes

In this section, you will learn how to leverage Kubernetes volumes in order to mount files and directories inside an AWS Nitro Enclave running as a Pod.

Using persistent storage in the context of enclaves might present a security risk to the enclave, as it creates shared storage between the AWS Nitro Enclave and the untrusted parent instance. Please refer to the Persistent storage security section before proceeding.

Before running any of the examples below, download the license from the Anjuna Resource Center. This license file will be mounted to your nginx Pod as a Kubernetes secret.

Run the following command to create a Kubernetes secret:

$ kubectl create secret generic anjuna-license --from-file=license.yaml=license.yaml

Mounting a ConfigMap

A common use case for volumes is mounting configuration files inside of Pods. In the example below, the Anjuna Nitro K8s Toolset will automatically create an Enclave Image File from the Pod spec. This includes correctly mapping the specified volumeMounts inside of the enclave so that the application running inside of the enclave can access the ConfigMap contents.

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-map-name
data:
  data.txt: "Welcome to Anjuna!"
---
apiVersion: v1
kind: Pod
metadata:
  name: nitro-busybox-pod
  labels:
    nitro.k8s.anjuna.io/managed: "yes"
spec:
  containers:
    - name: nitro-busybox-pod
      command:
        - "sh"
        - "-ec"
        - |
          cat /tmp/data/data.txt && echo
          sleep infinity
      image: busybox
      resources:
        limits:
          memory: "2048Mi"
          cpu: "2"
      volumeMounts:
        - name: config-volume
          mountPath: /tmp/data
  volumes:
    - name: config-volume
      configMap:
        name: config-map-name

After its startup, the enclave will display the contents of /tmp/data/data.txt and sleep indefinitely. You can create this Pod by saving the Pod spec above to example-configmap.yaml and then running:

$ kubectl create -f example-configmap.yaml

Check the Pod logs to confirm that the enclave can access the mounted file:

$ kubectl logs nitro-busybox-pod -f

The output will include many logs, including the steps the Anjuna Nitro K8s Toolset takes to create an Enclave Image File from your Pod spec. Then, the application (as specified in the command field) will run. You should see the following toward the end of the output:

ANJ-ENCLAVE: Service anjunafs started with original pid=465
ANJ-ENCLAVE: Mounting volume with mountPath '/tmp/data'
ANJ-ENCLAVE: Mounting volume with mountPath '/var/run/secrets/kubernetes.io/serviceaccount'
ANJ-ENCLAVE: Launched "/bin/sh" with pid=470
Welcome to Anjuna!

Using PersistentVolume and PersistentVolumeClaim

The other common use case for volumes is providing persistent storage to containers, which have ephemeral filesystems otherwise. Applications running inside enclaves can also benefit from the persistent volumes in Kubernetes. In the example below, you will mount /tmp/data, backed by a 1Gi PersistentVolume that is dynamically provisioned by the Storage Class gp2 (default for EKS). Note that manually provisioned volumes should work in the same way.

The application will write a file to the persisted directory (see the command field of the Pod spec).

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  storageClassName: gp2
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: nitro-busybox-pod
  labels:
    nitro.k8s.anjuna.io/managed: "yes"
spec:
  containers:
    - name: nitro-busybox-pod
      command:
        - "sh"
        - "-ec"
        - |
          echo "I am a persisted file" | tee /tmp/data/file.txt
          sleep infinity
      image: busybox
      resources:
        limits:
          memory: "2048Mi"
          cpu: "2"
      volumeMounts:
        - name: data
          mountPath: /tmp/data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc

To create this example, save the manifests above to example-pvc.yaml and run:

kubectl create -f example-pvc.yaml

Using volumes with pre-built EIFs

In the examples above, the Anjuna Nitro K8s Toolset automatically created an Enclave Image File (EIF) from your Pod spec. This will generate enclave configuration files dynamically, which will map the volume mounts inside the enclave. If you want to have full control over the enclave configuration file, you can rely on a pre-built EIF. By using a pre-built EIF, the Anjuna Nitro K8s Toolset will run your EIF instead of creating one on-the-fly.

To use pre-built EIFs, you must explicitly configure basic volume mounts in your enclave configuration file. Learn more about Persistent storage and Persistent storage mounts.

For instance, you could create or extend your existing enclave configuration file with a new basic mount for the data volume, as shown below:

version: 1.8
# ... other fields of your enclave config file ...
mounts:
  - type: basic
    name: data # must match the volume name in the Pod spec
    mountPath: /tmp/data

After building and pushing your new EIF, you can transform the previous Pod spec with a PersistentVolumeClaim to use a pre-built EIF saved to s3://<bucket>/busybox.eif by adding the nitro.k8s.anjuna.io/imageLocation annotation:

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
storageClassName: gp2
accessModes:
  - ReadWriteOnce
resources:
  requests:
    storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
name: nitro-busybox-pod
labels:
  nitro.k8s.anjuna.io/managed: "yes"
annotations:
  nitro.k8s.anjuna.io/imageLocation: "s3://<bucket>/busybox.eif"
spec:
  containers:
    - name: nitro-busybox-pod
      image: busybox
      resources:
        limits:
          memory: "2048Mi"
          cpu: "2"
      volumeMounts:
        - name: data
          mountPath: /tmp/data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc