Develop your app
One of the advantages of using
mse to protect your application and your data in the cloud, is that you don’t need to adapt your own Python application. Indeed, you just need to pick your original code, design a standard Flask application without specific intructions, write a configuration TOML file and run the
In this section, we will list good practices or various considerations you need to know before developing or deploying your application inside an
The MSE node environment is running on
Ubuntu 20.04 with
Test your application locally¶
This method is well-suited to test the remote environment when deploying your app.
We recall that your application is deployed into a constraint environment under a specific architecture. This method emulates as close as possible the MSE node environment in production.
Before any deployment, it’s strongly recommended to test your application locally against the MSE Docker image specified into your
It enables you to verify that your application is compatible with the MSE environment and all required dependencies are installed.
Since you have installed
docker in the previous step on your own machine, you can run:
When you scaffold a new project, the configuration file contains a default Docker including minimal Flask packages. For many reasons, this Docker could be not enough to run your own application.
Let’s remind that any files written in
mse_src directory will be sent remotely to the MSE node.
mse_src directory contains a
requirements.txt, these packages will be installed when running the Docker.
It enables you to quickly setup and test your application in an MSE environment without generating a new Docker.
- There could be conflicts on underlying dependencies (ie: C dependencies) between installed packages and default environment ones
- It makes your installation not reproducible. Therefore, after a deployment, it’s strongly likely that your users won’t be able to verify the trustworthiness of your application
Then, we recommend to fork mse-docker-flask to build your own Docker by integrating all your dependencies.
You can test your application against your brand new Docker by editing the field
docker in your
mse.toml then run:
Refer to docker configuration for more details.
Using a third-party service with secrets¶
Before sending the Python code of your microservice, each file is encrypted but:
This code is supposed to be sharable, as your convenience, to any users in order to check the trustworthiness of your app. As a matter of fact, do not write any secret into your code. For example: passwords or keys to connect to a third-party service like a remote storage or a database.
For the same reason, do not store your SSL secret key or the configuration TOML file in the code directory.
If you need such secrets to run your code, you can write a
secrets.json file and specify this file into the
code.secrets field in the TOML configuration file. Please see the example below. This file will be sent to the enclave after the latter has been verified during the app deployment. Your application will then be able to read it to retrieve the secrets it needs.
Example of configuation file:
name="helloworld" project="default" hardware = "4g-eu-001" [code] location="./code" python_application="app:app" healthcheck_endpoint="/whoami" docker="ghcr.io/cosmian/mse-flask:20230228091325" secrets="./secrets.json" [ssl] domain_name="example.com" certificate="./cert.secret.pem" private_key="./key.secret.pem"
As you can see, the code directory (defined in
code.location field) does not contain the SSL private key (defined in
ssl.private_key field) nor the secrets file (defined in
Note that the configuration file does not contain any secrets values and can easily be commited into a code repository.
Example of a secret file:
Which is used by this application code example:
import os import json from pathlib import Path from flask import Flask app = Flask(__name__) @app.route('/whoami') def whoami(): """A simple example manipulating secrets.""" secrets = json.loads(Path(os.getenv("SECRETS_PATH")).read_text()) return secrets["login"]
Find below a small example using paths:
import os from http import HTTPStatus from pathlib import Path from datetime import datetime from flask import Flask, Response app = Flask(__name__) WORKFILE: Path = Path(os.getenv("HOME")) / "date.txt" @app.post('/') def write_date(): """A simple example of file writting.""" WORKFILE.write_text(str(datetime.now())) return Response(status=HTTPStatus.OK) @app.route('/') def read_date(): """A simple example of file reading.""" if not WORKFILE.exists(): return Response(response="You should write before read", status=HTTPStatus.NOT_FOUND) txt = WORKFILE.read_text() WORKFILE.unlink() return txt
You application owns a dedicated storage up to 10GB. The useful directories are the followings:
|Env||Path||Encrypted (1)||Persistent (2)||Comments|
||✅||❌||Could be used by third-party libraries (your application dependencies) to store caches or configuration files|
||✅||❌||The application secrets file you have sent as described in the previous section|
||✅||❌||A temporary folder|
||✅||❌||Containing the decrypted application code|
Please note that writting operations in
$HOME are about 2.5 times slower than in a
$TMP_PATH. However, the max file size you can allocate in
hardware_memory / 4 and the number of files has no limit since the sum of their size is lower than the size still available. Choose wisely the file location based on your own application constraints.
(1) Only the enclave containing this version of your code can decrypt this directory. Another enclave or even another version of your application won’t be able to read it
(2) The data will be removed when the application is stopped
You can edit a
.mseignore file in your code directory. This file is read by the cli when deploying an app and avoid sending some files remotely.
The syntax is the same as
.mseignore is generated by the
mse scaffold command.
When you declare the memory size through the field
hardware in the
mse.toml, you shall consider that a part of this memory is used by the system itself.
All the librairies needed to run your application will be loaded in that memory. Therefore, the effective memory size available for your application is about:
hardware_memory - librairies_size.
When calling the docker on your localhost, you can use the option
--memory to estimate your effective memory size. See our github for more details.
The MSE environment is running on
Ubuntu 20.04 with
Please find below limitations that you need to consider to be able to run your application in MSE:
- Do not fork processes
- Do not run subprocess (command execution)
Trying to use these system operations could make the app crash.