---
title: "Using Fortanix Confidential Computing Manager to Build an Enclave OS Application that Talks Over TLS from Within an Enclave"
slug: "using-fortanix-ccm-to-build-an-enclave-os-application-that-talks-over-tls-from-within-an-enclave"
updated: 2026-07-23T06:37:31Z
published: 2026-07-23T06:37:31Z
canonical: "support.fortanix.com/using-fortanix-ccm-to-build-an-enclave-os-application-that-talks-over-tls-from-within-an-enclave"
---

> ## 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 that Talks Over TLS from Within an Enclave

## 1.0 Introduction

This example describes how to create two Python Flask applications that run securely within an Amazon Web Service (AWS) Nitro enclave and communicate over a TLS connection. Each application receives a TLS certificate signed by Fortanix Confidential Computing Manager (CCM). The corresponding private key is generated within the enclave and is never exposed outside the enclave.

![](https://cdn.us.document360.io/c3bd85d2-4ad8-4d85-9f60-f1c168a3aad9/Images/Documentation/image(91).png)

## 2.0 Create the Client and Server Applications

### 2.1 Create a Python Server Application

Create a file named `server.py` with the following contents:

```python
import ssl
import uuid
from flask import jsonify, Flask
from flask_api import status

app = Flask("Python Flask TLS Server")

@app.route('/random')
def get_random_token():
    random_token = uuid.uuid4().hex[:6]
    return jsonify({
        "token": random_token
    }), status.HTTP_200_OK

if __name__ == "__main__":
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_verify_locations("/app/cert/ca.crt")
    context.load_cert_chain("/app/cert/server.crt", "/app/cert/server.key")
    app.run(host="0.0.0.0", port=2222, use_reloader=False, threaded=True, ssl_context=context)
```

This server listens on port `2222`, accepts GET requests on the `/random` endpoint, and returns a random token.

The server is configured to use HTTPS with the certificate located at `/app/cert/server.crt` and the corresponding private key located at `/app/cert/server.key`. The Certificate Authority (CA) certificate that signed the `server.crt` certificate is located at `/app/cert/ca.crt`.

The line `context.verify_mode = ssl.CERT_REQUIRED` indicates that the sender of requests, in this case the client, must be verified using its certificate, establishing a mutual TLS connection.

When this application is deployed using Enclave OS, Enclave OS generates the certificate key and stores it at `/app/cert/server.key` within the enclave. It then submits a Certificate Signing Request (CSR) to Fortanix CCM and receives a signed certificate, which is stored at `/app/cert/server.crt`.

### 2.2 Create a Docker Container for the Server Application

Create a file named `dockerfile.server` with the following contents:

```dockerfile
FROM python:3.7
RUN mkdir /app
RUN mkdir /app/cert
COPY server.py /app/
RUN pip3 install flask Flask-API
WORKDIR /app
ENTRYPOINT ["python3", "server.py"]
```

Build the container and push it to a registry using the following commands:

```bash
docker build -t fortanix/python-tls-server -f dockerfile.server .
docker push fortanix/python-tls-server
```

In the above commands, you can modify the tag to point to your own container registry or skip this step because the container is already available in the Fortanix public registry: [https://hub.docker.com/r/fortanix/python-tls-server](https://hub.docker.com/r/fortanix/python-tls-server).

### 2.3 Create a Python Client Application

Similar to the server application, the client application receives a signed certificate from Fortanix CCM.

When the client application receives a request from a user, it uses this certificate to establish a mutual TLS connection with the server and submit a request. The server response, which is a random token in this example, is returned to the user.

Create a file named `client.py` with the following contents:

```python
import os
import requests
import ssl
from flask import Flask

SERVER_DOMAIN = "flask-server.domain"
ENDPOINT = "https://" + SERVER_DOMAIN + ":2222"
app = Flask("Python Flask TLS Client")

@app.route("/submit")
def submit_request():
    path = ENDPOINT + "/random"
    req = requests.get(url=path, verify='/app/cert/ca.crt', cert=("/app/cert/client.crt", "/app/cert/client.key"))
    return req.content

if __name__ == '__main__':
    os.system("echo '0.0.0.0 " + SERVER_DOMAIN + "' >> /etc/hosts")
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.load_verify_locations("/app/cert/ca.crt")
    context.load_cert_chain("/app/cert/client.crt", "/app/cert/client.key")
    app.run(host="0.0.0.0", port=3333, use_reloader=False, threaded=True, ssl_context=context)
```

### 2.4 Create a Docker Container for the Client Application

Create a file named `dockerfile.client` with the following contents:

```dockerfile
FROM python:3.7
RUN mkdir /app
RUN mkdir /app/cert
COPY client.py /app/
RUN pip3 install flask Requests
WORKDIR /app
ENTRYPOINT ["python3", "client.py"]
```

Build the container and push it to a registry using the following commands:

```bash
docker build -t fortanix/python-tls-client -f dockerfile.client .
docker push fortanix/python-tls-client
```

The client container is already available in the Fortanix public registry: [https://hub.docker.com/r/fortanix/python-tls-client](https://hub.docker.com/r/fortanix/python-tls-client)

## 3.0 Create Fortanix CCM Applications

After pushing both application containers to a registry, create Fortanix CCM applications for the server and client applications to convert the containers into applications that run within enclaves using Fortanix Enclave OS.

Follow the steps described in the referenced example to:

- Authenticate to Fortanix Armor.
- Select an account.

Session tokens are short-lived. If you receive the following response, refresh the session token: `{"message": "Forbidden", "code": "FORBIDDEN"}` .

When creating a Fortanix CCM application, use the following `server.json` file with the API request. Replace `output_image_name` with your private registry.

```bash
curl -b $cpath -c $cpath -H "X-CSRF-Header:true" -H "Content-Type: application/json" -d @server.json -X POST https://ccm.fortanix.com/v1/apps
```

```json
{
    "name": "Python TLS Server",
    "description": "A python server using Flask and a CCM certificate",
    "input_image_name": "fortanix/python-tls-server",
    "output_image_name": "fortanix-private/python-tls-server-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": [
        "flask-server.domain"
    ],
    "advanced_settings": {
        "entrypoint": [],
        "manifestEnv": [],
        "encryptedDirs": [],
        "certificate": {
            "issuer": "MANAGER_CA",
            "subject": "flask-server.domain",
            "keyType": "RSA",
            "keyParam": {
                "size": 2048
            },
            "keyPath": "/app/cert/server.key",
            "certPath": "/app/cert/server.crt"
        },
        "caCertificate": {
            "caPath": "/app/cert/ca.crt",
            "system": "false"
        },
        "rw_dirs": [
            "/app/cert"
        ]
    },
 "custom_metadata": {
        "app_type": "ENCLAVE_OS"
    }
}
```

Note the `&lt;app_id&gt;` and `pending_task_id` values in the response. These values are required for subsequent requests.

```json
{
    "name":"Python TLS Server",
    "app_id":"1ef7d352-28b6-4560-a714-a503435455bc",
    "pending_task_id":"d5550480-697e-4782-9bc5-58aaaa97e712",
    "domains_added":["flask-server.domain"],
    ...
}
```

Approve the application domain using 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>
```

Follow the steps in the [referenced example](/v1/docs/using-fortanix-confidential-computing-manager-to-build-an-enclave-os-application-from-scratch#44-create-an-image-using-an-api-call) to create and approve a build. You will need the `&lt;app_id&gt;` as part of the build creation process.

Follow the same procedure to create a Fortanix CCM application for the client application and create and approve a build. Use the following `client.json` file when creating the client application:

```json
{
    "name": "Python TLS Client",
    "description": "A python client using Flask and a CCM certificate",
    "input_image_name": "fortanix/python-tls-client",
    "output_image_name": "fortanix-private/python-tls-client-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": [
        "flask-client.domain"
    ],
    "advanced_settings": {
        "entrypoint": [],
        "manifestEnv": [],
        "encryptedDirs": [],
        "certificate": {
            "issuer": "MANAGER_CA",
            "subject": "flask-client.domain",
            "keyType": "RSA",
            "keyParam": {
                "size": 2048
            },
            "keyPath": "/app/cert/client.key",
            "certPath": "/app/cert/client.crt"
        },
        "caCertificate": {
            "caPath": "/app/cert/ca.crt",
            "system": "false"
        },
        "rw_dirs": [
            "/app/cert"
        ]
    },
 "custom_metadata": {
        "app_type": "ENCLAVE_OS"
    }
}
```

## 4.0 Run the Converted Applications

After creating and approving both application builds, deploy and test the applications on a compute node enrolled in CCM.

Run the server application using the following command. Replace `&lt;ip_addr&gt;` with the IP address of the compute node and use the build name from your private registry.

```bash
docker run --privileged --volume /dev:/dev -v /run/nitro_enclaves:/run/nitro_enclaves -e NODE_AGENT=http://<ip_addr>:9092/v1 -p 2222:2222 fortanix-private/python-tls-server-nitro:latest
```

On the same compute node, run the client application in a separate terminal window using the following command:

```bash
docker run --privileged --volume /dev:/dev -v /run/nitro_enclaves:/run/nitro_enclaves -e NODE_AGENT=http://:9092/v1 -p 3333:3333 --network host fortanix-private/python-tls-client-nitro:latest
```

After both applications are running, submit a request using the following command:

```bash
curl -k --cacert ca.pem https://localhost:3333/submit
```

`ca.pem` is the certificate of the Certificate Authority (CA) that signed the `server.crt` and `client.crt` certificates delivered to the applications.

The `ca.pem` file is also referred to as the Zone Certificate and is specific to your Fortanix Armor account. All applications within the same account receive certificates signed by the same Zone Certificate.

To retrieve the CA certificate, use the attached `fetch_ca.sh` script.

## 5.0 Conclusion

In this example, you created two applications that run securely within an enclave. Both applications receive TLS certificates from Fortanix Confidential Computing Manager and use these certificates to establish secure communication channels with each other and with external users.

## Related

- [Using Fortanix Confidential Computing Manager to Build an Enclave OS Application from Scratch](/using-fortanix-ccm-to-build-an-enclave-os-application-from-scratch.md)
- [Using Fortanix Confidential Computing Manager for Easy Deployment of Elasticsearch on AWS Nitro](/using-fortanix-ccm-for-easy-deployment-of-elasticsearch-on-aws-nitro.md)
