Deploy On-chain KMS Smart Contracts
Deploy theDstackKms smart contract to enforce that only authorized workloads can receive keys. This page covers the full contract deployment workflow, including the recommended Safe + Timelock governance setup for production.
Overview
| Component | Required | Description |
|---|---|---|
| DstackKms | Yes | Stores authorized workload measurements, admin roles, and KMS configuration |
| ERC1967Proxy | Yes | Proxy contract for upgradeable DstackKms (UUPS pattern) |
| TimelockController | Optional | Enforces a delay on governance actions |
| Safe (Multisig) | Optional | Multi-signature wallet for governance |
Note: Safe and Timelock are optional security enhancements, not part of dstack. They are recommended for production but not required for development.
Governance Models
Model A: Direct Admin (Simplest)
- Admin is a single EOA (externally owned account)
- No multisig, no timelock
- Governance actions execute immediately
- Suitable for development and testing
Model B: Timelock Only
- Admin is a TimelockController contract
- Governance actions require a delay before execution
- Anyone can execute after delay (or restricted to specific executors)
- Suitable for simple production setups
Model C: Safe + Timelock (Recommended for Production)
- Admin is a Safe multisig wallet
- Timelock enforces a delay
- Requires multi-party approval + delay period
- Maximum security and transparency
Prerequisites
- Foundry installed (
forge,cast) - A wallet with funds for deployment gas
- Testnet: Use a faucet (e.g., Base Sepolia faucet)
- Mainnet: Sufficient ETH for contract deployment
- RPC endpoint for the target network
Step 1: Set Up the Project
Step 2: Configure Environment
Create a.env file:
Security: Never commit your private key. Add.envto.gitignore.
Step 3: Deploy DstackKms (Basic, No Timelock)
For development/testing, you can deploy DstackKms with direct EOA admin:Why ERC1967Proxy? DstackKms uses UUPS upgradeable pattern. You must deploy a proxy to have a working upgradeable instance. The proxy is the actual application address.
Step 4: Deploy with Timelock (Recommended for Production)
Timelock Configuration
The timelock delay depends on your deployment environment:| Parameter | Testnet | Mainnet |
|---|---|---|
| Timelock delay | 1-4 hours | 24-72 hours |
| Safe signers | 2-3 addresses | 5-7 addresses (from multiple organizations) |
| Safe threshold | 2/3 | ≥ 2/3 |
| Executor role | Open or EOA | Safe only (strict control) |
| Admin role | EOA or 0x0 | 0x0 (self-managed by timelock) |
4.1 Prepare Timelock Configuration
4.2 Deploy All Contracts
4.3 Understanding TimelockController Roles
| Role | Description | Who Should Have It |
|---|---|---|
| Proposer | Can schedule operations | Safe multisig or trusted EOA |
| Executor | Can execute operations after delay | Safe, or address(0) for open execution |
| Admin | Can grant/revoke roles | Should be address(0) after setup (self-managed by timelock) |
Step 5: Configure Safe (Optional but Recommended)
For production, use a Safe multisig as the proposer/executor:5.1 Create a Safe
- Go to Safe web app
- Connect your wallet
- Create a new Safe on your target network
- Add signers (3-7 addresses recommended)
- Set threshold (≥ 2/3 of signers)
5.2 Use Safe Address in Deployment
When deploying the TimelockController, use your Safe address:5.3 Governance Flow with Safe + Timelock
- Draft transaction — Use Safe web interface to create a transaction
- Collect signatures — Required signers approve
- Schedule in timelock — Safe calls
timelock.schedule() - Wait for delay — Wait the configured delay period
- Execute — Anyone (or only executor) calls
timelock.execute()
Step 6: Verify Deployment
Verify on block explorer:DstackKmsowner is set to the TimelockController address- TimelockController has correct proposer/executor roles
How to Execute Governance Actions (With Timelock)
Once deployed, allonlyOwner operations must go through the timelock:
Schedule an Operation
Execute After Delay
All Governance-Protected Methods
Once ownership is transferred to timelock, these methods require timelock governance:| Method | Purpose |
|---|---|
setKmsInfo | Update KMS public key and attestation info |
setKmsQuote | Update KMS quote |
setKmsEventlog | Update KMS event log |
setGatewayAppId | Set gateway application ID |
setAppImplementation | Update app implementation address |
addKmsAggregatedMr | Authorize a KMS measurement |
removeKmsAggregatedMr | Revoke a KMS measurement |
addKmsDevice | Authorize a KMS device |
removeKmsDevice | Revoke a KMS device |
addOsImageHash | Authorize an OS image hash |
removeOsImageHash | Revoke an OS image hash |
Common Issues
| Issue | Solution |
|---|---|
| ”Insufficient funds” | Get testnet ETH from faucet, or ensure mainnet wallet has enough ETH |
| ”Ownable: caller is not the owner” | Ownership already transferred to timelock. Use timelock.schedule/execute |
| ”Timelock: operation is not ready” | Wait for the delay period to pass before executing |
| ”Timelock: operation already scheduled” | Use a different salt (unique operation ID) |
| Proxy verification fails | Use cast abi-encode to construct the constructor arguments |
Next Steps
- Register KMS Measurements — Register KMS measurements before bootstrap
- Register Workload Measurements — Authorize workloads to receive keys
- Manage Governance — How to create proposals and execute governance actions
- Concept: Governance — Understand the governance model

