Providing an Enclave Image File for the Pod’s Enclave
Confidential Pods launch the workload by running the EIF (Enclave Image File) for the Pod inside an enclave. This EIF can be provided by using one of the following methods:
-
Built on the fly, based on the container image provided
-
Fetched from S3 buckets
-
Taken from the local filesystem of the Pod
Built on-the-fly EIFs
EIFs may be built on the fly, based on the Pod configuration provided, such as the container image, container ports, and any volume mounts it may use. In this case, the Pod configuration is converted into an enclave configuration. This configuration, combined with the container image, are transformed into an EIF by the launcher Pod. While convenient, this option is not recommended for production use cases, because of the following reasons:
-
It extends the launch time of the Pod, as the EIF is built during Pod launch.
-
It is less secure, since it is not possible to enable the remote attestation in this case.
Pre-built EIFs
This is the recommended option for most production use cases. It allows a faster start of the Confidential Pod, as well being much more secure, since it enables leveraging remote attestation with KMS and the Anjuna Encrypted Configuration. For more details, see the Anjuna Nitro Enclave configuration and anjuna-nitro-cli build-enclave.
Getting the pre-built EIF from an S3 Bucket
The Anjuna Kubernetes Toolset for AWS EKS tools has built-in support for S3 storage. This allows you to upload your pre-built EIF to an S3 bucket, and point the launcher Pod to fetch them from there. For an example, see Using pre-built EIFs.
Getting the pre-built EIF from source other than S3
Sometimes, using S3 storage is not the preferred approach. When not using S3 storage, you can load the EIF to the launcher Pod’s filesystem, and indicate from where to fetch the EIF. All standard K8s methods of loading the EIF to the filesystem are supported, including through the use of Volume Mounts. These Volume Mounts may be populated in any way, including the following:
-
Through a Secret/ConfigMap (though this may not be suitable, since EIF files can be large)
-
Init Containers populating shared volumes
-
Persistent Volume Claims
Use the following annotation to specify the absolute path of the EIF on the filesystem. (This annotation can be applied with any method that was used to make the file visible to the launcher Pod.):
nitro.k8s.anjuna.io/imageLocation
Example for getting the pre-built EIF from source other than S3
In this example you will:
-
Create a MinIO server that will hold an EIF.
-
Add a shared EmptyDir volume to the Pod.
-
Add an init container to the Pod specification that will download the EIF from the MinIO server.
-
Tell the launcher Pod where the EIF is located (where the volume mount is mounted, and the filename of the EIF inside of it).
First steps
Define the environment variables that will be used throughout this example (change the values to match your environment):
$ export EIF_PATH=nginx.eif
$ export NAMESPACE=default
$ export MINIO_SERVER_NAME=minio-server
$ export MINIO_USER=admin
$ export MINIO_PASSWORD=miniopassword
$ export MINIO_BUCKET_NAME=eifs
$ export MINIO_SERVICE_PORT=9000
Next, build an EIF for a simple Nginx container:
$ anjuna-nitro-cli build-enclave --docker-uri nginx:latest --output-file ${EIF_PATH}
Creating a MinIO Server and uploading the EIF to it
Launch a MinIO server Pod:
$ kubectl run --image minio/minio:RELEASE.2025-04-08T15-41-24Z --port 9000 \
--env "MINIO_ROOT_USER=${MINIO_USER}" \
--env "MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}" \
-n ${NAMESPACE} \
${MINIO_SERVER_NAME} server /data
Create a service that exposes the MinIO server to the cluster:
$ kubectl expose pod ${MINIO_SERVER_NAME} --port=${MINIO_SERVICE_PORT} \
--target-port=9000 --name=${MINIO_SERVER_NAME} --type=ClusterIP \
-n ${NAMESPACE}
Using a MinIO client to upload the EIF to the MinIO server
Forward the MinIO Server port using kubectl port-forward
,
launch a MinIO client container, and upload the EIF to the MinIO server:
$ kubectl port-forward pod/minio-server 9000:9000 &
# Wait for port-forward to take affect
$ sleep 3
$ docker run -i --rm --entrypoint bash -v $(realpath ${EIF_PATH}):/${EIF_PATH} --net=host minio/mc:RELEASE.2025-04-08T15-39-49Z <<EOF
mc alias set minioserver "http://localhost:9000" ${MINIO_USER} ${MINIO_PASSWORD}
mc mb minioserver/${MINIO_BUCKET_NAME}
mc cp /${EIF_PATH} minioserver/${MINIO_BUCKET_NAME}/${EIF_PATH}
EOF
$ kill %1
Preparing a Pod specification
Create a Pod specification for the Nginx Pod, which will include a shared volume mount, and an init container. This init container will download the EIF from the MinIO server, and will load it into the shared volume.
$ cat > pod_spec.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: confidential-nginx-pod
labels:
nitro.k8s.anjuna.io/managed: "yes"
annotations:
nitro.k8s.anjuna.io/imageLocation: "/anjuna/files/eifs/${EIF_PATH}"
spec:
initContainers:
- name: anjuna-eif-downloader
image: minio/mc:RELEASE.2025-04-08T15-39-49Z
command:
- /bin/sh
- -c
- |
mc alias set minioserver http://minio-server.default.svc.cluster.local:${MINIO_SERVICE_PORT} ${MINIO_USER} ${MINIO_PASSWORD} &&
mc cp minioserver/${MINIO_BUCKET_NAME}/${EIF_PATH} /anjuna/files/eifs/${EIF_PATH}
volumeMounts:
- name: anjuna-system-eifs
mountPath: "/anjuna/files/eifs"
containers:
- name: confidential-nginx
image: DOES-NOT-MATTER
imagePullPolicy: Always
resources:
limits:
memory: "2048Mi"
cpu: "2"
volumeMounts:
- name: anjuna-system-eifs
mountPath: "/anjuna/files/eifs"
volumes:
- name: anjuna-system-eifs
emptyDir: {}
EOF
The |
The volume used to pass the EIF to the enclave has a name that starts with |
Launching the Pod and validating it
First, launch the Pod:
$ kubectl apply -f pod_spec.yaml -n ${NAMESPACE}
Then, make sure that the Pod started correctly (this may take a few seconds):
$ kubectl logs -n ${NAMESPACE} -f confidential-nginx-pod
The output should be of the following form:
2025/04/23 23:40:01 [notice] 471#471: using the "epoll" event method
2025/04/23 23:40:01 [notice] 471#471: nginx/1.27.3
2025/04/23 23:40:01 [notice] 471#471: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/04/23 23:40:01 [notice] 471#471: OS: Linux 5.10.223
2025/04/23 23:40:01 [notice] 471#471: getrlimit(RLIMIT_NOFILE): 1024:4096
2025/04/23 23:40:01 [notice] 471#471: start worker processes
2025/04/23 23:40:01 [notice] 471#471: start worker process 495
2025/04/23 23:40:01 [notice] 471#471: start worker process 496