---
title: "Using Fortanix Confidential Computing Manager to Build an Enclave OS Application from Scratch"
slug: "using-fortanix-ccm-to-build-an-enclave-os-application-from-scratch"
updated: 2026-07-23T06:36:11Z
published: 2026-07-23T06:36:11Z
canonical: "support.fortanix.com/using-fortanix-ccm-to-build-an-enclave-os-application-from-scratch"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://support.fortanix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Using Fortanix Confidential Computing Manager to Build an Enclave OS Application from Scratch

## 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:

```python
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:

```dockerfile
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:

```bash
docker build -t fortanix/python-flask:latest .
```

> [!NOTE]
> NOTE
> 
> If you want to use your own container registry, replace `fortanix` with the name of your registry.

Run the Docker container using the following command:

```bash
docker run -p 9000:9000 fortanix/python-flask:latest
```

From another terminal, run the following command to send an HTTP request to the deployed server:

```bash
curl localhost:9000
```

#### Step 3: Push the Image to a Registry

To make the image publicly accessible, push it to a public registry using the following command:

```bash
docker push fortanix/python-flask:latest
```

> [!NOTE]
> NOTE
> 
> 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](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](https://ccm.fortanix.com).

### 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*](/v1/docs/fortanix-armor-getting-started#20-sign-up-on-fortanix-armor-platform-new-users).

### 3.2 Select an Account

Create or select a Fortanix Armor account. *For detailed instructions, refer to* [*Getting Started with Fortanix Armor*](/v1/docs/fortanix-armor-getting-started#40-create-an-account).

### 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*](/v1/docs/fortanix-armor-identity-and-access-management-iam#43-create-a-group).

### 3.4 Create an Application

Perform the following steps to create an application using the Fortanix CCM UI:

1. In the CCM UI left navigation panel, navigate to **Applications** and then on the **ACTIVE APPLICATION** tab and click **ADD APPLICATION**.
2. In the **Add application** dialog box, select **Enclave OS** and click **NEXT**.
3. In the **Add application** form, enter the application details and click **ADD APPLICATION**.

*For detailed instructions, refer to* [*Add Application*](/v1/docs/fortanix-ccm-add-and-edit-an-application)*.*

### 3.5 Create an Application Build

Perform the following steps to create a build using the Fortanix CCM UI:

1. In the application details page, go to **BUILDS** tab and click **ADD BUILD**.
2. In the **Add Build** form:
  1. Enter the tag of the application input Docker image.
  2. 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.
3. Click **ADD BUILD**.

*For detailed instructions, refer to* [*Create Application Build*](/v1/docs/fortanix-ccm-create-a-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](https://fortanix.com/api/ccm/).

### 4.1 Authenticate to Fortanix Armor

Before you can issue any requests, you must authenticate to Fortanix Armor using the following commands:

```bash
cpath=$(mktemp -p "/tmp" -t "fortanix_ccm_cookie.XXXXX")
curl -u <username>:<password> -c $cpath -X POST https://ccm.fortanix.com/v1/sys/auth
```

Replace `&lt;username&gt;` and `&lt;password&gt;` with the email address and password of your Fortanix Armor account.

> [!NOTE]
> 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:
> 
> ```bash
> 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:

```bash
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" https://ccm.fortanix.com/v1/accounts
```

This command returns a JSON response similar to the following:

```bash
{"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:

```bash
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.

```json
{
    "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:

```bash
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/apps
```

This command returns information about the newly created application, including the application ID:

```bash
{"name":"Python Flask Server","app_id":"cc386097-dcf7-4813-880a-ddacdafb48a2",...}
```

### 4.4 Create an Application Build Using an API Call

After creating the application, create a file named `build.json` as shown below. Replace `&lt;app_id&gt;` with the ID of the newly created application. Replace `&lt;username&gt;` and `&lt;password&gt;` with the credentials of the registry where the converted build will be stored. This registry was specified earlier as `output_image_name`.

```json
{
  "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*](/v1/docs/quickstart-guide-1)*.*

Create the build using the following command:

```bash
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-app
```

This command returns information about the build, including the `&lt;task_id&gt;` . In this example, `f0d815b6-9520-4ce4-b4f4-6a82a718bb7e` .

```bash
{"build_name":"fortanix-private/python-flask-nitro:latest","pending_task_id":"f0d815b6-9520-4ce4-b4f4-6a82a718bb7e",...}
```

Approve the image using the `&lt;task_id&gt;` and the following command:

```bash
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:

```bash
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:latest
```

Where,

- `9092` is the default port on which the Node Agent listens.
- `52.152.206.164` is the IP address of the compute node.
- `fortanix-private/python-flask-nitro:latest` is the converted application image.

> [!NOTE]
> 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=debug` to enable debug logging.
>   - `-p 7622:80 -p 8038:443` to map the application custom ports to ports `80` and `443`.

## Related

- [Fortanix CCM - Quickstart](/fortanix-ccm-quickstart-guide.md)
- [How does the attestation process guarantee code integrity?](/how-does-the-attestation-process-guarantee-code-integrity.md)
- [Bringing EDP Rust Apps to Confidential Computing Manager](/bringing-edp-rust-apps-to-fortanix-ccm.md)
