Developing with Marlin TEEs: Local simulation made easy

When building applications for Marlin TEEs (reference), secure execution and attestation are crucial — but fast iteration is just as important. Recompiling, pushing to Docker Hub, and testing inside real enclaves slows down early-stage development.

To solve this, we’ve introduced a local development setup that closely mirrors Oyster CVM enclaves (reference) — no enclave hardware required. It allows developers to test applications, validate service integrations like attestation (reference) and KMS (reference), and simulate enclave behavior using Docker, Rust, and the Oyster CLI.

:test_tube: Why Simulate Enclaves Locally?

While production deployment requires secure enclaves (TEEs) and real attestation, developers often need to:

  • Test key generation workflows (x25519, secp256k1) (reference)
  • Debug integration with services like KMS derive and attestation
  • Ensure init parameters (reference) and app config behave as expected

A local simulation environment saves significant time by removing the friction from build–test cycles.

:hammer_and_wrench: Prerequisites

Before you get started, make sure you have:

Simulated Services Overview

Here’s how the key enclave-related services are replicated locally:

|Service | Purpose | Local Simulation|

|— | — | —|
|Keygen | Generate cryptographic keys | Standalone local services|
|Attestation | Prove enclave identity | Mock server with hardcoded certs|
|KMS Derive | Derive keys/secrets | Mock or seeded derive server|
|Init Params | Injected values into app | Passed directly via CLI args|

Architecture Overview

Everything runs inside a Docker-in-Docker (DinD) container. Docker is chosen to simulate the enclave isolation locally. The base image is based on alpine to minimize the size of the docker image used for development environment and to remove unnecessary bloat since all services run within docker inside the local development environment container. Docker images used within the docker-compose file are pulled from the local machine rather than registry to reduce time to simulate and bandwidth requirements.

±------------------------------------------------------------------------------------------------------------------------------------+

Local Development Container
- Keygen Server generates key which are available at ‘/app/id.pub’ , ‘/app/id.sec’ , ‘/app/ecdsa.pub’ ,
‘/app/ecdsa.sec’
- Mock Attestation is available at 1300 & 1301
- Mock KMS Derive is available at 1100 (not exposed outside the container)
- Your App via Docker
±------------------------------------------------------------------------------------------------------------------------------------+

This approach ensures full simulation while letting you mount your own docker-compose.yml just like you’d do in production.

Image available on Docker Hub:

:arrow_forward: Running Your App Locally

Step 1: Build the Oyster CLI

  • Open the terminal for Oyster Monorepo directory and go to the relevant commit: git checkout 5d106c2558382d1fd5f4bd9e11bb052d4346ae7a
  • Navigate to the CLI: cd cli/oyster-cvm
  • Build the CLI binary using Rust: cargo build --release
  • Copy the binary to your working directory: cp target/release/oyster-cvm ./

Step 2: Write a Docker Compose File

Create your docker-compose file in the working directory like:

# docker-compose.yml
services:
  redis:
    image: redis:latest
    command: ["redis-server"]
    network_mode: "host"

  redis-cli:
    image: redis:latest
    command: ["sh", "-c", "while true; do redis-cli -h localhost ping; sleep 5; done"]
    network_mode: "host"

You can replace this with your own services — just ensure network_mode: host is used.

Step 3: Simulate

./oyster-cvm simulate \
  --arch amd64 \
  --base-image ayushkyadav/local_dev_image_amd64:latest \
  --docker-compose ./docker-compose.yml \
  --init-params secret:1:0:utf8:hello \
  --expose-ports 6379

This launches:

  • Your app containers (from docker-compose.yml) in the local development environment
  • Simulated enclave services (KMS, attestation, keygen)
  • Injected init parameters like real enclaves

You can now interact with your app on the specified ports and also access the attestation servers on 1300 and 1301.
Note: Unlike the actual Oyster deployment, the simulation allows you to use your local docker images as well which have not yet been pushed to the hub.
For more info: CLI Readme

:white_check_mark: Summary

The Oyster local development environment gives you:

  • Fast iteration with Docker Compose
  • Simulated KMS, attestation, and keygen services
  • CLI tooling to abstract container bootstrapping

By staying close to the real deployment model while remaining lightweight, this simulation workflow helps developers debug faster and ship with confidence.