1.0 Introduction
This article describes how to create a simple Dockerized Python server and deploy it within a Trusted Execution Environment (TEE) using Fortanix Enclave OS (operation system).
The following two options are provided to convert a Docker application to an Enclave OS application:
Using the Fortanix Confidential Computing Manager (CCM) user interface (UI)
Using REST API calls.
2.0 Create a Docker Application
2.1 Creating a Python Application
Create a simple Python server using Flask. Create a file named server.py with the following contents:
from flask import Flask
app = Flask("Hello Flask Server")
@app.route("/")
def hello():
return "Hello Flask"
if __name__ == '__main__':
app.run(host='0.0.0.0', port='9000')This application is a minimal Flask server that accepts requests on port 9000 and returns a greeting message.
2.2 Create a Docker Container
Create a Docker container containing the application and push it to a container registry.
Step 1: Create a Dockerfile
Create a file named Dockerfile with the following contents:
FROM python:3.7
EXPOSE 9000
RUN pip3 install flask
RUN mkdir /app
COPY server.py /app/
WORKDIR /app
ENTRYPOINT ["python3", "server.py"]Step 2: Build a Docker Image
Run the following command to build the Docker image:
docker build -t fortanix/python-flask:latest .NOTE
If you want to use your own container registry, replace
fortanixwith the name of your registry.
Run the Docker container using the following command:
docker run -p 9000:9000 fortanix/python-flask:latestFrom another terminal, run the following command to send an HTTP request to the deployed server:
curl localhost:9000Step 3: Push the Image to a Registry
To make the image publicly accessible, push it to a public registry using the following command:
docker push fortanix/python-flask:latestNOTE
The above command fails if you have not configured your own registry. You can skip this step because the image is already available in the Fortanix public registry: https://hub.docker.com/r/fortanix/python-flask.
3.0 Option 1: Build an Enclave OS Application Using the Fortanix CCM UI
This section describes how to convert a Docker application into an Enclave OS application that can run securely inside a Trusted Execution Environment using the Fortanix CCM UI.
3.1 Sign in to Fortanix Armor
Sign up and Log in to Fortanix Armor. For detailed instructions, refer to Getting Started with Fortanix Armor.
3.2 Select an Account
Create or select a Fortanix Armor account. For detailed instructions, refer to Getting Started with Fortanix Armor.
3.3 Create a Group
Create a group in the Fortanix Armor Identity and Access Management solution. For detailed instructions, refer to Fortanix Armor Identity and Access Management.
3.4 Create an Application
Perform the following steps to create an application using the Fortanix CCM UI:
In the CCM UI left navigation panel, navigate to Applications and then on the ACTIVE APPLICATION tab and click ADD APPLICATION.
In the Add application dialog box, select Enclave OS and click NEXT.
In the Add application form, enter the application details and click ADD APPLICATION.
For detailed instructions, refer to Add Application.
3.5 Create an Application Build
Perform the following steps to create a build using the Fortanix CCM UI:
In the application details page, go to BUILDS tab and click ADD BUILD.
In the Add Build form:
Enter the tag of the application input Docker image.
Enter the registry credentials for the output image. Registry credentials are used to access the private Docker registry where the image will be pushed. The input image does not require credentials because it is stored in a public registry.
Click ADD BUILD.
For detailed instructions, refer to Create Application Build.
3.6 Approve the Application Build
From the CCM UI left navigation panel, select Tasks. On the Tasks page, select the build task and click APPROVE.
4.0 Option 2: Build an Enclave OS Application Using REST API Calls
This section describes how to convert a Docker application into an Enclave OS application that can run securely inside a Trusted Execution Environment using the Fortanix CCM REST API.
4.1 Authenticate to Fortanix Armor
Before you can issue any requests, you must authenticate to Fortanix Armor using the following commands:
cpath=$(mktemp -p "/tmp" -t "fortanix_ccm_cookie.XXXXX")
curl -u <username>:<password> -c $cpath -X POST https://ccm.fortanix.com/v1/sys/authReplace <username> and <password> with the email address and password of your Fortanix Armor account.
NOTE
Authentication session tokens are short-lived. If you receive the response
{"message":"Forbidden","code":"FORBIDDEN"}, run the following command to refresh the session token:curl -b $cpath -c $cpath -H "X-CSRF-Header:true" -X POST https://ccm.fortanix.com/v1/sys/session/refresh
4.2 Select an Account Using an API Call
After authenticating to Fortanix Armor, select an account. Run the following command to list all available accounts:
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" https://ccm.fortanix.com/v1/accountsThis command returns a JSON response similar to the following:
{"name":"My account","acct_id":"26eaa328-5eb4-41c7-b09b-8a3e0a0f65c7", ...}, ...Copy the account ID of the account, in this example 26eaa328-5eb4-41c7-b09b-8a3e0a0f65c7, that you want to use and run the following command:
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" -X POST https://ccm.fortanix.com/v1/sys/session/select_account/<account_id>4.3 Create an Application Using an API Call
To create an application, create a file named app.json with the following contents. Replace output_image_name with your private registry.
{
"name":"Python Flask Server",
"description":"",
"input_image_name":"fortanix/python-flask",
"output_image_name":"fortanix-private/python-flask-nitro",
"default_build_settings": {
"sgx": {},
"nitro_enclaves": {
"cpu_count": 2,
"mem_size": 1024,
"enable_overlay_filesystem_persistence": true
}
},
"group_id": "a8e8395e-096d-4eb8-9017-2098f2ab8327",
"allowed_domains": [],
"advanced_settings": {
"entrypoint": [],
"manifestEnv": [],
"encryptedDirs": [],
"rw_dirs": [],
"certificate": {}
},
"custom_metadata": {
"app_type": "ENCLAVE_OS"
}
}Create the application using the following API call:
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" -H "Content-Type: application/json" -d @app.json -X POST https://ccm.fortanix.com/v1/appsThis command returns information about the newly created application, including the application ID:
{"name":"Python Flask Server","app_id":"cc386097-dcf7-4813-880a-ddacdafb48a2",...}4.4 Create a Build Using an API Call
After creating the application, create a file named build.json as shown below. Replace <app_id> with the ID of the newly created application. Replace <username> and <password> with the credentials of the registry where the converted build will be stored. This registry was specified earlier as output_image_name.
{
"app_id":"<app_id>",
"input_docker_version":"latest",
"output_docker_version":"latest",
"outputAuthConfig":{
"username":"<username>",
"password":"<password>"
}
}For more information about configuring registry credentials without including credentials in this file, refer to Fortanix CCM - Quickstart.
Create the build using the following command:
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" -H "Content-Type: application/json" -d @build.json -X POST https://ccm.fortanix.com/v1/builds/convert-appThis command returns information about the build, including the <task_id> . In this example, f0d815b6-9520-4ce4-b4f4-6a82a718bb7e .
{"build_name":"fortanix-private/python-flask-nitro:latest","pending_task_id":"f0d815b6-9520-4ce4-b4f4-6a82a718bb7e",...}Approve the image using the <task_id> and the following command:
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" -H "Content-Type: application/json" -d '{"status":"APPROVED"}' -X PATCH https://ccm.fortanix.com/v1/tasks/<task_id>5.0 Run the Application
Whether you created the application using the CCM UI or REST API, you should now have a converted and approved application build that can be run on a Nitro compute node.
Run the application using the following command:
docker run --privileged --volume /dev:/dev -v /var/run/aesmd/aesm.socket:/var/run/aesmd/aesm.socket -e NODE_AGENT=http://52.152.206.164:9092/v1/ fortanix-private/python-flask-nitro:latestWhere,
9092is the default port on which the Node Agent listens.52.152.206.164is the IP address of the compute node.fortanix-private/python-flask-nitro:latestis the converted application image.
NOTE
Replace the Node IP address, port, and converted image with your own values. The values shown above are examples.
Add the following flags to the command for additional details:
-e ENCLAVEOS_LOG_LEVEL=debugto enable debug logging.
-p 7622:80 -p 8038:443to map the application custom ports to ports80and443.