Skip to main content

Customizing, Testing, and Management

The directory src/nautilus-server contains the Nautilus server logic. To customize the application, refer to the Using Nautilus guide as a template. The commands on this page use the weather example from that guide; it is an example, not a required use case, and your application defines its own process_data logic.

info

These customization, testing, and management steps are for self-managed trusted execution environments (TEEs). Alternatively, you can use the Marlin Oyster marketplace for Docker-based simplicity that removes testing and management overhead.

Create custom server logic​

You can customize the Nautilus server to define allowed endpoints and specify any external domains your application needs to access. You can create mod.rs to define your process_data logic and register any additional endpoints.

The following files typically do not require modification:

  • common.rs handles the get_attestation endpoint.

  • main.rs initializes the ephemeral key pair and sets up the HTTP server.

Test locally​

You can test most functionality by running the server locally. However, the get_attestation endpoint doesn't work locally because it requires access to the Nitro Secure Module (NSM) driver, which is only available when running the code inside the configured EC2 instance. This endpoint functions correctly when the server runs within the enclave as described in the setup steps.

To test the process_data endpoint locally, run the following commands. The API_KEY value in the second command is an example. Replace it with your own key for the weather API that the example calls.

$ cd src/nautilus-server/
$ RUST_LOG=debug API_KEY=045a27812dbe456392913223221306 cargo run --features=weather-example --bin nautilus-server
$ curl -H 'Content-Type: application/json' -d '{"payload": { "location": "San Francisco"}}' -X POST http://localhost:3000/process_data
Click to open
Output
{
"response":
{
"intent":0,
"timestamp_ms":1744041600000,
"data":
{
"location":"San Francisco",
"temperature":13
}
},
"signature":"b75d2d44c4a6b3c676fe087465c0e85206b101e21be6cda4c9ab2fd4ba5c0d8c623bf0166e274c5491a66001d254ce4c8c345b78411fdee7225111960cff250a"
}

Check reproducibility​

Every enclave built from the same source code (everything in /src) can produce identical Platform Configuration Registers (PCRs) through reproducible builds. This includes any traffic forwarding changes made in run.sh (see branch example-configuration).

$ cd nautilus/
$ make ENCLAVE_APP=weather-example
$ cat out/nitro.pcrs
Click to open
Output
911c87d0abc8c9840a0810d57dfb718865f35dc42010a2d5b30e7840b03edeea83a26aad51593ade1e47ab6cced4653e PCR0
911c87d0abc8c9840a0810d57dfb718865f35dc42010a2d5b30e7840b03edeea83a26aad51593ade1e47ab6cced4653e PCR1
21b9efbc184807662e966d34f390821309eeac6802309798826296bf3e8bec7c10edb30948c90ba67310f7b964fc500a PCR2
# Add env var that will be used later when registering the enclave.
$ PCR0=911c87d0abc8c9840a0810d57dfb718865f35dc42010a2d5b30e7840b03edeea83a26aad51593ade1e47ab6cced4653e
$ PCR1=911c87d0abc8c9840a0810d57dfb718865f35dc42010a2d5b30e7840b03edeea83a26aad51593ade1e47ab6cced4653e
$ PCR2=21b9efbc184807662e966d34f390821309eeac6802309798826296bf3e8bec7c10edb30948c90ba67310f7b964fc500a

Manage enclaves​

The template allows the admin to register multiple Enclave objects associated with one EnclaveConfig that defines PCRs. Each Enclave object represents a specific enclave instance with a unique public key, while the EnclaveConfig tracks the PCR values and their associated version. You can register all new Enclave instances with the latest config_version to ensure consistency.

This design allows the admin to run multiple instances of the same enclave with different public keys, where each new Enclave object gets the latest version as its config_version. The admin can register or destroy their Enclave objects.

Update PCRs​

The deployer of the smart contract holds the EnclaveCap, which allows for updating the PCRs and enclave public key if you modify the Nautilus server code. You can retrieve the new PCRs using make ENCLAVE_APP=<APP> && cat out/nitro.pcrs. To update the PCRs or register the enclave again, reuse the steps outlined in the previous section.

Use verified computation in Move​

Write frontend code to interact with the enclave for computation, and then send the resulting data to the Move contract for use. For the weather example, you can request the enclave to retrieve weather data for a specific location. Replace <PUBLIC_IP> with the public IP address of the EC2 instance running the enclave:

$ curl -H 'Content-Type: application/json' -d '{"payload": { "location": "San Francisco"}}' -X POST http://<PUBLIC_IP>:3000/process_data
Click to open
Output
{
"response":
{
"intent":0,
"timestamp_ms":1744683300000,
"data":
{
"location":"San Francisco",
"temperature":13
}
},
"signature":"77b6d8be225440d00f3d6eb52e91076a8927cebfb520e58c19daf31ecf06b3798ec3d3ce9630a9eceee46d24f057794a60dd781657cb06d952269cfc5ae19500"
}

Then use the values from the enclave response, signature, timestamp, location, and temperature, to call update_weather in the Move contract. This example demonstrates the call using a script, but you should integrate it into your app frontend. The script takes the following positional arguments, in order: the app package ID, the module name, the One-Time Witness (OTW) name, the enclave object ID, the signature, the timestamp in milliseconds, the location, and the temperature.

$ sh ../../update_weather.sh \
$APP_PACKAGE_ID \
$MODULE_NAME \
$OTW_NAME \
$ENCLAVE_OBJECT_ID \
"77b6d8be225440d00f3d6eb52e91076a8927cebfb520e58c19daf31ecf06b3798ec3d3ce9630a9eceee46d24f057794a60dd781657cb06d952269cfc5ae19500" \
1744683300000 \
"San Francisco" \
13

An example of a created weather NFT is available on network scanners.

Sign the payload​

You construct signing payloads in Move using Binary Canonical Serialization (BCS). These must match the structure specified in the enclave Rust code when generating the signature. Otherwise, signature verification in enclave.move might fail.

Write unit tests in both Move and Rust to ensure consistency. See test_serde() in src/nautilus-server/src/app.rs and the examples in move/enclave/enclave.move.

FAQs​

The following sections answer some questions the community often asks.

Why did Sui choose AWS Nitro Enclaves initially?​

  • There are many TEE providers available, but initial support for AWS Nitro Enclaves is due to their maturity and support for reproducible builds. Sui might consider support for additional TEE providers in the future.

For questions about Nautilus, use case discussions, or integration support, contact the Nautilus team on Sui Discord.

Where is the root of trust of AWS?​

  • The Sui framework stores it and uses it to verify AWS attestation documents. You can verify its hash by following the steps outlined on AWS.
$ curl https://raw.githubusercontent.com/MystenLabs/sui/refs/heads/main/crates/sui-types/src/nitro_root_certificate.pem -o cert_sui.pem
$ sha256sum cert_sui.pem

6eb9688305e4bbca67f44b59c29a0661ae930f09b5945b5d1d9ae01125c8d6c0

$ curl https://aws-nitro-enclaves.amazonaws.com/AWS_NitroEnclaves_Root-G1.zip -o cert_aws.zip
$ unzip cert_aws.zip
$ sha256sum root.pem

6eb9688305e4bbca67f44b59c29a0661ae930f09b5945b5d1d9ae01125c8d6c0 # check it matches from the one downloaded from the Sui repo