Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Keep Enclave Deployment

Deploy Keep on AWS Nitro Enclaves for hardware-isolated signing.

Architecture

┌─────────────────────────────────────────────────────────┐
│                    AWS Nitro Enclave                    │
│  ┌───────────────────────────────────────────────────┐  │
│  │              keep-enclave binary                   │  │
│  │  • Private keys (memory only)                     │  │
│  │  • Policy engine (amount limits, rate limits)     │  │
│  │  • FROST threshold signing                        │  │
│  │  • PSBT sighash computation                       │  │
│  └───────────────────────────────────────────────────┘  │
│                          ▲                              │
│                          │ vsock                        │
│                          ▼                              │
│  ┌───────────────────────────────────────────────────┐  │
│  │                   Host (EC2)                       │  │
│  │  • Routes requests to enclave                     │  │
│  │  • Verifies attestation                           │  │
│  │  • Never sees private keys                        │  │
│  └───────────────────────────────────────────────────┘  │
│                          │                              │
│                          ▼                              │
│  ┌───────────────────────────────────────────────────┐  │
│  │                    AWS KMS                         │  │
│  │  Key Policy: Decrypt only if PCR0/1/2 match       │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

Keys live only in enclave memory. KMS decrypts only if PCRs match.

Prerequisites

Deployment Options

MethodBest forComplexity
EnclaverQuick setup, simpler operationsLow
CDK (automated)Production with full AWS integrationMedium
ManualLearning, debugging, custom setupsHigher

Using Enclaver

Enclaver simplifies enclave builds:

curl -sL https://github.com/edgebitio/enclaver/releases/latest/download/enclaver-linux-x86_64.tar.gz | tar xz
sudo mv enclaver /usr/local/bin/

docker build -f keep-enclave/build/Dockerfile.local -t keep-enclave:local .
enclaver build -f keep-enclave/enclaver.yaml

Deploy to EC2 (use CDK or Manual to provision an instance first):

docker save keep-enclave:enclave | gzip > keep-enclave.tar.gz
scp -i ~/.ssh/keep-enclave.pem keep-enclave.tar.gz ec2-user@<IP>:~/

# On EC2
docker load < keep-enclave.tar.gz
enclaver run keep-enclave:enclave

Still need KMS setup for key persistence.


Automated Deployment (CDK)

Create ECR repository and push enclave image first:

aws ecr create-repository --repository-name keep-enclave
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <account>.dkr.ecr.us-east-1.amazonaws.com
docker build -f keep-enclave/build/Dockerfile.enclave -t keep-enclave:v1.0.0 .
docker tag keep-enclave:v1.0.0 <account>.dkr.ecr.us-east-1.amazonaws.com/keep-enclave:v1.0.0
docker push <account>.dkr.ecr.us-east-1.amazonaws.com/keep-enclave:v1.0.0

Deploy infrastructure:

cd deploy/cdk
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
CDK_DEPLOY_ACCOUNT=<account> CDK_DEPLOY_REGION=us-east-1 cdk deploy -c image_tag=v1.0.0

Provisions VPC, ASG, NLB, KMS. Update KMS policy with PCRs after build.

Manual Deployment

IAM Role

aws iam create-role --role-name keep-enclave-role \
  --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam create-instance-profile --instance-profile-name keep-enclave-profile
aws iam add-role-to-instance-profile --instance-profile-name keep-enclave-profile --role-name keep-enclave-role
export EC2_ROLE_ARN=$(aws iam get-role --role-name keep-enclave-role --query 'Role.Arn' --output text)

SSH Key

aws ec2 create-key-pair --key-name keep-enclave --query 'KeyMaterial' --output text > ~/.ssh/keep-enclave.pem
chmod 400 ~/.ssh/keep-enclave.pem

Launch EC2

aws ec2 run-instances \
  --image-id ami-0c02fb55956c7d316 \
  --count 1 \
  --instance-type m5.xlarge \
  --enclave-options 'Enabled=true' \
  --key-name keep-enclave \
  --iam-instance-profile Name=keep-enclave-profile \
  --block-device-mappings '[{"DeviceName":"/dev/xvda","Ebs":{"VolumeSize":20}}]' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=keep-enclave}]'

Note: AMI ami-0c02fb55956c7d316 is for us-east-1. Find your region’s Amazon Linux 2 AMI via aws ssm get-parameter --name /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 --query 'Parameter.Value' --output text.

Supported: m5.xlarge, m6i.xlarge, c5.xlarge, r5.xlarge (and 2xlarge variants).

Instance Setup

ssh -i ~/.ssh/keep-enclave.pem ec2-user@<INSTANCE_IP>

sudo amazon-linux-extras install aws-nitro-enclaves-cli -y
sudo yum install aws-nitro-enclaves-cli-devel docker -y
sudo usermod -aG ne,docker ec2-user
sudo tee /etc/nitro_enclaves/allocator.yaml <<< $'memory_mib: 512\ncpu_count: 2'
sudo systemctl enable --now nitro-enclaves-allocator docker
exit  # Re-login to apply groups

Build Enclave

See keep-enclave/build/README.md. Produces keep-enclave.eif and pcrs.json.

PCRs (Platform Configuration Registers) are hashes of the enclave code. They change on rebuild. KMS uses them to restrict decryption to your exact code.

scp -i ~/.ssh/keep-enclave.pem keep-enclave/build/keep-enclave.eif ec2-user@<IP>:~/

KMS Setup

aws kms create-key --description "Keep Enclave" --tags TagKey=Project,TagValue=keep
export KMS_KEY_ID=<key-id-from-output>
aws kms create-alias --alias-name alias/keep-enclave --target-key-id $KMS_KEY_ID

Edit keep-enclave/build/kms-policy.json, replace all placeholders:

  • <EC2_INSTANCE_ROLE_ARN>: Role ARN from IAM setup (use echo $EC2_ROLE_ARN)
  • <KMS_ADMIN_ROLE_ARN>: Your IAM user/role ARN for key administration
  • <REGION>: AWS region (e.g., us-east-1)
  • <ACCOUNT_ID>: Your AWS account ID
  • <KMS_KEY_ID>: Key ID from above
  • <PCR0_VALUE>, <PCR1_VALUE>, <PCR2_VALUE>: From pcrs.json after build
aws kms put-key-policy --key-id $KMS_KEY_ID --policy-name default \
  --policy file://keep-enclave/build/kms-policy.json

Run Enclave

nitro-cli run-enclave --eif-path ~/keep-enclave.eif --memory 512 --cpu-count 2
nitro-cli describe-enclaves  # Note EnclaveCID (usually 16)

Debug mode (PCR0 = zeros, insecure):

nitro-cli run-enclave --eif-path ~/keep-enclave.eif --memory 512 --cpu-count 2 --debug-mode
nitro-cli console --enclave-id <id>  # View logs

Stop: nitro-cli terminate-enclave --all

CLI Commands

keep enclave verify --cid 16                                    # Verify attestation
keep enclave generate-key --name mykey --cid 16                 # Generate key in enclave
keep enclave import-key --name enclavekey --from-vault vaultkey --cid 16
keep enclave sign --key mykey --message <hex> --cid 16
keep enclave sign-psbt --key mykey --psbt tx.psbt --network testnet --cid 16

Policy example (enforced inside enclave):

#![allow(unused)]
fn main() {
PolicyRule::MaxAmountSats(1_000_000)  // 0.01 BTC limit
PolicyRule::MaxPerHour(10)            // Rate limit
}

Local Development

Mock mode (no security, dev only):

keep enclave generate-key --name test --local
keep enclave sign --key test --message <hex> --local

QEMU emulation (vsock testing, no real attestation):

qemu-system-x86_64 -M nitro-enclave,vsock=parent -kernel keep-enclave.eif -m 512 -nographic --enable-kvm

Troubleshooting

ErrorFix
Enclave boot failedIncrease --memory
No enclave supportUse Nitro-capable instance
Resource busynitro-cli terminate-enclave --all
AccessDeniedExceptionPCR mismatch: rebuild, update KMS policy
Vsock failedCheck nitro-cli describe-enclaves, verify CID

Debug mode KMS: set PCR0 to 96 zeros in policy.

Security Notes

  • PCRs change on rebuild; update KMS policy each time
  • Debug mode sets PCR0=0; bypasses attestation; never in prod
  • Keys lost on restart unless persisted via KMS envelope encryption
  • Host can’t decrypt; KMS policy restricts to enclave with matching PCRs
  • No network in enclave; host proxies KMS

Checklist

  • Runs without --debug-mode
  • Attestation passes
  • KMS works with real PCRs
  • Signing works
  • Policy enforced
  • Keys survive restart
  • Wrong PCRs fail decrypt