본문으로 건너뛰기

Nautilus 사용하기

Nautilus는 Sui의 검증 가능한 오프체인 compute layer이다. 빌더는 민감하거나 리소스를 많이 사용하는 작업을 자체 관리 trusted execution environment (TEE) 또는 Marlin Oyster 같은 TEE marketplace에 위임하면서, smart contract 기반 검증을 통해 온체인 trust를 유지할 수 있다.

Nautilus repo는 재현 가능한 빌드, signature formatting, HTTPS traffic forwarding 같은 scaffolding을 제공한다. 따라서 enclave 내부의 오프체인 계산 로직 구현에 집중할 수 있다.

온체인 템플릿에는 Nautilus instance와 해당 public key를 등록하는 데 필요한 최소 smart contract code가 포함되어 있다.

important

Nautilus는 TEE에서 privacy-preserving 방식으로 code를 실행하는 것만을 의미하지 않는다. 전체 value proposition의 일부는 계산 무결성에 대한 on-chain verification이다.

  1. PCRs(enclave measurements)는 온체인에 등록되고 검증되어야 한다.
  2. 모든 계산 결과는 선택적으로 온체인에서 검증될 수 있다.

개발자 워크플로

앱에서 Nautilus를 사용하려면:

  1. 원하는 계산 로직으로 Rust에서 enclave를 구현한다.

  2. 예상 platform configuration registers (PCRs)를 저장하고 contract deployer가 이를 업데이트할 수 있게 하는 Move smart contract를 배포한다.

  3. AWS에 enclave instance를 배포하고 attestation document를 사용해 온체인에 등록한다.

  4. 등록된 enclave의 signed response를 업로드하고, 온체인에서 검증한 뒤 smart contract에서 결과를 사용한다.

이 가이드는 다음 단계를 안내한다.

  1. AWS Nitro Enclaves를 사용해 기본 Nautilus offchain instance를 작성하고 배포한다. 예제 instance는 특정 위치의 날씨 데이터를 가져오는 server를 실행한다.

  2. Attestation과 public key를 검증해 enclave를 등록한 뒤 Nautilus response(signature와 payload)를 온체인에서 검증하고 위치와 온도 데이터가 포함된 NFT를 민트하는 Move smart contract를 작성한다.

정보

Frontend code는 이 가이드에 포함되어 있지 않다.

###step AWS developer account 생성

AWS developer account를 설정하고 AWS CLI를 설치한다. 자세한 지침은 AWS Nitro Enclaves getting started guide를 참조한다.

###step AWS SSO 구성

AWS CLI version을 확인한다.

aws --version

출력은 2로 시작하는 version이어야 한다.

aws-cli/2.x.x

다음 command로 AWS CLI tool의 single sign on을 구성한다.

aws configure sso

프롬프트가 표시되면 다음 field를 입력한다.

  • SSO start URL: <your-sso-start-url>

  • SSO region: us-east-1

만료된 credential이 표시되면 다음 command로 재설정한다.

rm ~/.aws/credentials
rm ~/.aws/config

###step AWS SSO에 로그인

AWS SSO를 구성한 후 browser window를 통해 login하도록 redirect된다. account와 AdministratorAccess role을 선택한다. AWS는 AdministratorAccess-094557288217 같은 profile을 생성해야 한다.

###step 기존 EC2 SSH key pair 목록 확인

AWS account에 생성된 모든 key pair를 나열하려면 다음 command를 실행한다. 이 key pair는 EC2에 SSH로 접속할 때만 사용된다.

aws ec2 describe-key-pairs \
--region us-east-1 \
--profile AdministratorAccess-094557288217

####substep 새 EC2 SSH key pair 생성(optional)

사용할 key pair가 아직 없다면 다음 command로 새 EC2 SSH key pair를 생성한다.

aws ec2 create-key-pair \
--key-name <your-alias> \
--query 'KeyMaterial' \
--output text \
--region us-east-1 > ~/.ssh/<your-alias>.pem

SSH key의 permission을 구성한다.

chmod 400 ~/.ssh/<your-alias>.pem

###step 환경 변수 설정

KEY_PAIR 변수를 EC2 key pair 이름으로 설정한다.

export KEY_PAIR=<your-key-pair-name>

그런 다음 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN 환경 변수를 설정해야 한다. 이 값은 Nautilus provisioning script에 필요하다.

다음 command로 이 변수들의 값을 export한다.

aws configure export-credentials \
--profile AdministratorAccess-094557288217 \
--format env > ~/aws-temp-creds.sh

그런 다음 credential을 load한다.

source ~/aws-temp-creds.sh

정상적으로 설정되었는지 확인한다.

env | grep AWS_

다음 command로 AWS identity도 확인할 수 있다.

aws sts get-caller-identity

예상 출력:

{
"UserId": "AROARMBANW4MXIS7SZ7S6:george.melas@mystenlabs.com",
"Account": "094557288217",
"Arn": "arn:aws:sts::094557288217:assumed-role/AWSReservedSSO_AdministratorAccess_bb69586677f0373c/george.melas@mystenlabs.com"
}

이 command가 동작하면 AWS environment는 Nautilus와 함께 사용할 준비가 된 것이다.

###step Nautilus repository 구조 확인

다운로드하거나 clone한 Nautilus repository의 내용을 확인한다.

/move
/enclave # enclave config와 public key registration을 위한 utility functions
/weather-example # enclave functions를 사용하는 예제 onchain logic
/twitter-example # 대체 예제 onchain logic

/src
/aws # AWS boilerplate; 수정할 필요가 없다.
/init # AWS boilerplate; 수정할 필요가 없다.
/system # AWS boilerplate; 수정할 필요가 없다.
/nautilus-server # enclave 내부에서 실행되는 Nautilus server.
/src
/apps
/weather-example # 예제 directory. 필요에 따라 자체 application logic으로 교체한다.
mod.rs # process_data endpoint와 관련 logic을 정의한다. 오프체인 계산 logic으로 교체한다.
allowed_endpoints.yaml # enclave가 접근할 수 있는 모든 endpoint를 나열한다. 기본적으로 enclave는 internet access가 없다. 구성 중 이 파일은 traffic forwarding을 위한 code를 생성한다.
/twitter-example # 유사한 구조의 또 다른 예제 directory.
run.sh # enclave 내부에서 Rust server를 실행한다. 수정하지 않는다.
common.rs # attestation을 가져오는 common code. 수정하지 않는다.

핵심 구현 파일:

  • allowed_endpoints.yaml: external API access permission을 정의한다.

  • mod.rs: application-specific computation logic을 포함한다.

  • run.sh: server startup과 configuration을 처리한다.

  • common.rs: attestation 가져오기를 관리한다.

자체 Nautilus app을 만들려면:

  • Move module용 directory를 move/my_app 아래에 추가한다.

  • Rust server logic용 directory를 src/nautilus-server/src/apps/my_app 아래에 추가한다.

  • 기존 app directory를 reference로 사용한다.

  • 배포된 Move contract 및 enclave-hosted Rust server와 상호작용할 frontend logic을 빌드한다.

템플릿 대부분은 수정하지 않아도 되므로 개발을 간소화하면서 app-specific logic을 완전히 제어할 수 있다.

###step Nautilus provisioning script 실행

Nautilus directory root에서 실행한다.

cd /nautilus
sh configure_enclave.sh weather-example

setup script는 다음 작업을 수행한다.

  • 사전 구성된 EC2 instance를 시작하고 Nitro Enclave를 할당한다.

  • Rust 기반 template application을 enclave image format (EIF) binary로 빌드하고 enclave 내부에서 실행한다.

  • enclave 자체에는 internet access가 없으므로 parent EC2 instance를 통해 external API에 접근할 수 있도록 필요한 HTTP domain을 구성한다.

  • client-side에서 enclave와 통신할 수 있도록 endpoint 3개를 노출한다.

enclave가 시작되면 새 key pair를 생성하고 다음 endpoint를 노출한다.

  • health_check: enclave 내부에서 허용된 domain을 점검한다. 이 logic은 template에 내장되어 있으며 수정할 필요가 없다.

  • get_attestation: enclave public key에 대한 signed attestation document를 반환한다. onchain registration 중 사용한다. 이 logic은 template에 내장되어 있으며 수정할 필요가 없다.

  • process_data: external API에서 날씨 데이터를 가져오고 enclave key로 서명한 뒤 결과를 반환한다. 이 customizable logic은 직접 구현해야 한다.

추가 지침은 sh configure_enclave.sh -h를 실행해 확인한다. AWS account가 us-east-1에 없다면 region별 REGIONAMI_ID 값을 구성해야 할 수 있다. 적합한 Amazon Linux image ID를 찾으려면 이 guide를 참조한다.

$ export REGION=<your-region>
$ export AMI_ID=<find-an-amazon-linux-ami-for-your-region>

public subnet이 있는 VPC를 생성해야 할 수 있다. 지침은 이 AWS guide를 참조한다.

###step 예제 실행

weather example을 그대로 실행하려면 allowed_endpoints.yaml을 수정할 필요가 없다. 이미 api.weatherapi.com이 포함되어 있기 때문이다. 프롬프트에 따라 필요한 값을 입력한다. 이 단계는 AWS Secrets Manager를 사용해 secret(API key)을 저장하는 방법을 보여주므로 public application code에 secret을 포함하지 않아도 된다.

Enter EC2 instance base name: weather # 원하는 이름
Do you want to use a secret? (y/n): y
Do you want to create a new secret or use an existing secret ARN? (new/existing): new
Enter secret name: weather-api-key # 원하는 이름
Enter secret value: 045a27812dbe456392913223221306 # 예시 api key이며, weatherapi.com에서 본인 key를 받을 수 있다

출력에는 다음 항목이 포함된다.

  • Instance ID

  • Public IP

  • Security group

  • 생성된 IAM role

다음과 같은 public IP를 저장한다.

Instance launched with ID: i-0728fc72a13834bc8
Public IP: 18.208.226.122

EC2 initialization을 위해 2-3분 기다린다.

###step Nautilus repo를 EC2로 복사

script가 성공적으로 완료되면 /src/nautilus-server/run.shexpose_enclave.sh에 변경 사항이 생성된다. enclave image를 빌드할 때 필요하므로 이 변경 사항을 EC2로 복사해야 한다.

rsync -avz -e "ssh -i ~/.ssh/<your-alias>.pem" \
/Users/<you>/suistack/nautilus/ \
ec2-user@<public-ip>:~/nautilus/

# example: rsync -avz -e "ssh -i ~/.ssh/melas-se-3.pem" \
# /Users/geomel/suistack/nautilus/ \
# ec2-user@18.208.226.122:~/nautilus/
정보

enclave가 추가 external domain에 접근하도록 허용하려면 allowed_endpoints.yaml에 추가한다. 이 파일을 업데이트하면 endpoint list가 enclave build에 compile되므로 새 instance를 생성하기 위해 configure_enclave.sh를 다시 실행해야 한다.

codebase에 포함하고 싶지 않은 민감한 값을 저장하려면 secret을 선택적으로 생성할 수 있다. secret은 environment variable로 enclave에 전달된다. 새로 생성된 secret을 검증하거나 기존 ARN을 찾으려면 AWS Secrets Manager console을 확인한다.

###step EC2에 SSH 접속

ssh -i ~/.ssh/<your-alias>.pem ec2-user@<public-ip>

# example: ssh -i ~/.ssh/melas-se-3.pem ec2-user@18.208.226.122

이제 이전 단계의 committed file changes가 포함된 server code directory 안에 있다. 다음으로 enclave image를 빌드하고 실행한 뒤 port 3000에서 HTTP endpoint를 노출한다.

$ cd nautilus/
$ make ENCLAVE_APP=<APP> && make run # this builds the enclave and runs it, ex. `make ENCLAVE_APP=weather-example`
$ sh expose_enclave.sh # this exposes port 3000 to the Internet for traffic

enclave를 debug mode에서 실행하려면 make run 대신 make run-debug를 사용한다. 이는 production build와 달리 모든 log를 출력한다. debug mode에서는 PCR 값이 모두 0이며 production 용도로 유효하지 않다.

이제 외부에서 enclave와 상호작용할 수 있다. PUBLIC_IP는 AWS console에서 확인할 수 있다.

# Run a health check:
$ curl -H 'Content-Type: application/json' -X GET http://<PUBLIC_IP>:3000/health_check

# View the attestation document:
$ curl -H 'Content-Type: application/json' -X GET http://<PUBLIC_IP>:3000/get_attestation

# Get weather data for a location:
$ curl -H 'Content-Type: application/json' -d '{"payload": { "location": "San Francisco"}}' -X POST http://<PUBLIC_IP>:3000/process_data

선택적으로, EC2 instance에 AWS Certificate Manager (ACM)의 SSL/TLS certificate를 사용하는 application load balancer (ALB)를 설정하고 Amazon Route 53으로 DNS routing을 구성할 수 있다. 자세한 내용은 ACM User GuideALB Guide를 참조한다.

###step enclave를 온체인에 등록

Rust code를 최종 확정한 후 app administrator는 해당 PCRs와 public key로 enclave를 등록할 수 있다.

# Optionally
$ sui client switch --env testnet # or appropriate network
$ sui client faucet
$ sui client gas
# deploy the enclave package
$ cd move/enclave
$ sui move build
$ sui client publish

# Record ENCLAVE_PACKAGE_ID as env var from publish output
$ ENCLAVE_PACKAGE_ID=0x3b009f952e11f0fa0612d0a8e07461fb69edc355d732e5d6e39267b1b4fd7138

# Deploy your app logic
$ cd ../<APP>
$ sui move build
$ sui client publish

# Record CAP_OBJECT_ID (owned object of type Cap), ENCLAVE_CONFIG_OBJECT_ID (shared object), APP_PACKAGE_ID (package containing weather module) as env var from publish output

$ CAP_OBJECT_ID=0xb232d20245ba2d624d1c1628c4fc062bd1d3249601385476d9736fc60c897d2b
$ ENCLAVE_CONFIG_OBJECT_ID=0x9a50017ab37090ef4b5704eb24201c88b2e4bbad2aad1d4e69ecf1bdfbae9ccb
$ APP_PACKAGE_ID=0x097b551dec72f0c47e32e5f8114d0d12a98ab31762d21adff295f6d95d353154

# Record the deployed enclave url, for example http://<PUBLIC_IP>:3000
$ ENCLAVE_URL=<DEPLOYED_URL>

# The module name and otw name used to create the app, defined in your Move code `fun init`
$ MODULE_NAME=weather
$ OTW_NAME=WEATHER

# Make sure all env vars are populated
$ echo $APP_PACKAGE_ID
$ echo $ENCLAVE_PACKAGE_ID
$ echo $CAP_OBJECT_ID
$ echo $ENCLAVE_CONFIG_OBJECT_ID
$ echo 0x$PCR0
$ echo 0x$PCR1
$ echo 0x$PCR2
$ echo $MODULE_NAME
$ echo $OTW_NAME
$ echo $ENCLAVE_URL

# =======
# The two steps that follow (update pcrs, register enclave) can be reused if enclave server is updated
# =======

# This calls the update_pcrs onchain with the enclave cap and built PCRs, this can be reused to update PCRs if Rust server code is updated
$ sui client call --function update_pcrs --module enclave --package $ENCLAVE_PACKAGE_ID --type-args "$APP_PACKAGE_ID::$MODULE_NAME::$OTW_NAME" --args $ENCLAVE_CONFIG_OBJECT_ID $CAP_OBJECT_ID 0x$PCR0 0x$PCR1 0x$PCR2

# Optional, give it a name you like
$ sui client call --function update_name --module enclave --package $ENCLAVE_PACKAGE_ID --type-args "$APP_PACKAGE_ID::$MODULE_NAME::$OTW_NAME" --args $ENCLAVE_CONFIG_OBJECT_ID $CAP_OBJECT_ID "weather enclave, updated 2025-05-13"

# This script calls the get_attestation endpoint from your enclave url and uses it to call register_enclave onchain to register the public key, resulting in the created enclave object
$ sh ../../register_enclave.sh $ENCLAVE_PACKAGE_ID $APP_PACKAGE_ID $ENCLAVE_CONFIG_OBJECT_ID $ENCLAVE_URL $MODULE_NAME $OTW_NAME

# Record the created shared object ENCLAVE_OBJECT_ID as env var from register output
$ ENCLAVE_OBJECT_ID=0x1c9ccfc0f391f5e679e1f9f7d53c7fa455bf977e0f6dc71222990401f359c42a

PCR 값을 포함하는 example enclave config object를 SuiScan에서 확인할 수 있다. 또한 등록된 enclave public key가 포함된 example enclave object도 확인한다.

###step EC2 instance 중지

작업을 마치면 EC2 instance를 중지하는 것이 중요하다. 그렇지 않으면 AWS가 시간당 $0.19를 청구한다.

aws ec2 stop-instances --instance-ids <instance-id>

나중에 instance를 시작하려면:

aws ec2 start-instances --instance-ids <instance-id>

instance에 다시 연결하려면:

ssh -i ~/.ssh/<your-alias>.pem ec2-user@<public-ip>
cd nautilus
make ENCLAVE_APP=weather-example
make run
sh expose_enclave.sh

Twitter 예제 artifacts

다른 예제인 apps/twitter-example을 시험해 보려면 다음 artifacts를 사용한다.

$ cd nautilus/
$ make ENCLAVE_APP=twitter-example
$ cat out/nitro.pcrs
Click to open
Output
968f1266150cf8c4d62c9692b9f9b8fd6889d9331019d323f67a6ae6ab88b9378ad23f49f58c349526b9fdd5865da879 PCR0
968f1266150cf8c4d62c9692b9f9b8fd6889d9331019d323f67a6ae6ab88b9378ad23f49f58c349526b9fdd5865da879 PCR1
21b9efbc184807662e966d34f390821309eeac6802309798826296bf3e8bec7c10edb30948c90ba67310f7b964fc500a PCR2
# Add environment variables to use later when registering the enclave.
$ PCR0=968f1266150cf8c4d62c9692b9f9b8fd6889d9331019d323f67a6ae6ab88b9378ad23f49f58c349526b9fdd5865da879
$ PCR1=968f1266150cf8c4d62c9692b9f9b8fd6889d9331019d323f67a6ae6ab88b9378ad23f49f58c349526b9fdd5865da879
$ PCR2=21b9efbc184807662e966d34f390821309eeac6802309798826296bf3e8bec7c10edb30948c90ba67310f7b964fc500a

$ MODULE_NAME=twitter
$ OTW_NAME=TWITTER

# replace with your registered enclave
$ ENCLAVE_PACKAGE_ID=0xcca410b231d0acfa92c7709d490ab2f15fb5619be719ee0786099ffc3f6c9ab8
$ APP_PACKAGE_ID=0x652875162b566bb04187c76f93215e56c28aa05487393056279e331598ba4978
$ CAP_OBJECT_ID=0x44f3b57aa3870762ad334424cccb7f4c785cac007baab7e987c6d6a43c6aa100
$ ENCLAVE_CONFIG_OBJECT_ID=0xe33641a2dae5eb4acad3859e603ec4e25641af05f837c85058645c7d8d9d831a
$ ENCLAVE_OBJECT_ID=0x53db077721140910697668f9b2ee80fbecd104ac076d60fc1fb49ae57cd96c0d

# replace with your own enclave IP
$ ENCLAVE_URL=http://<PUBLIC_IP>:3000

PCR 값이 포함된 example enclave config object를 확인할 수 있다. 또한 등록된 enclave public key가 포함된 example enclave object도 확인할 수 있다.

Twitter example의 frontend code는 이 repository에서 확인할 수 있다.

개발 모드

non-production development에서는 enclave 내부에서 private key를 생성하는 대신 private key를 주입하고, 어느 곳에서나 debug mode로 enclave를 실행할 수 있다.

  1. enclave에 deterministic private key를 주입하도록 code를 수정한다. 이렇게 하면 AWS Nitro instance 없이도 동일한 private key로 server를 어디서나 실행할 수 있다.
  2. make run 대신 make run-debug를 사용한다. Debug mode는 all-zero PCR 값을 생성한다. 이 all-zero PCR로 enclave를 온체인에 한 번 등록하고 개발 중 PCR을 온체인에서 업데이트하지 않고 재사용할 수 있다.
위험

개발 전용이다. all-zero PCR은 attestation guarantee를 제공하지 않고 injected key는 TEE security model을 훼손하므로 production에서 절대 사용하지 않는다.

문제 해결

  • Traffic forwarder error: 대상 domain이 모두 allowed_endpoints.yaml에 나열되어 있는지 확인한다. 다음 command를 사용해 모든 domain에 대한 enclave connection을 테스트한다.
$ curl -H 'Content-Type: application/json' -X GET http://<PUBLIC_IP>:3000/health_check
Click to open
Output
{
"pk":"f343dae1df7f2c4676612368e40bf42878e522349e4135c2caa52bc79f0fc6e2",
"endpoints_status":
{
"api.weatherapi.com":true
}
}
  • Docker is not running: EC2 instance가 아직 시작 중일 수 있다. 잠시 기다린 뒤 다시 시도한다.

  • Cannot connect to enclave: VSOCK communication issue 때문일 수 있다. enclave가 실행 중이고 sh expose_enclave.sh로 올바르게 노출되었는지 확인한다.

  • SSO expired: 이 error는 다음 command로 수정할 수 있다.

aws sso login --profile AdministratorAccess-094557288217
aws configure export-credentials --profile AdministratorAccess-094557288217 --format env > ~/aws-temp-creds.sh
source ~/aws-temp-creds.sh
  • PEM “invalid format”: file이 비어 있거나 손상되었다. keypair를 다시 생성한다.

  • rsync permission denied: permission을 수정한다: chmod 700 ~/.ssh\chmod 400 ~/.ssh/<your-alias>.pem

  • Enclave endpoint unreachable: expose_enclave.sh가 실행 중인지, instance가 실행 중인지, 올바른 public IP를 사용 중인지 확인한다.