Skip to content

Commit 69d3f0b

Browse files
committed
feat(kms): enhance onboard page with site name, chain info, and k256 pubkey
- Add configurable site_name to core config, displayed as page title and heading on the onboard page for operator visibility. - Read eth_rpc_url and kms_contract_address from auth-api instead of duplicating in onboard config. Display chain info in a separate card. - Return k256_pubkey in OnboardResponse so it can be compared with the on-chain kmsInfo.k256Pubkey after onboarding.
1 parent dec6ee3 commit 69d3f0b

7 files changed

Lines changed: 74 additions & 3 deletions

File tree

kms/auth-eth/src/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export async function build(): Promise<FastifyInstance> {
5959
return {
6060
status: 'ok',
6161
kmsContractAddr: kmsContractAddr,
62+
ethRpcUrl: rpcUrl,
6263
gatewayAppId: batch[0],
6364
chainId: batch[1],
6465
appAuthImplementation: batch[2], // NOTE: for backward compatibility

kms/kms.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mandatory = false
2626
cert_dir = "/etc/kms/certs"
2727
subject_postfix = ".dstack"
2828
admin_token_hash = ""
29+
site_name = ""
2930

3031
[core.image]
3132
verify = true

kms/rpc/proto/kms_rpc.proto

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ message OnboardRequest {
131131
}
132132

133133
message OnboardResponse {
134+
// k256 public key (secp256k1) inherited from source KMS
135+
bytes k256_pubkey = 1;
134136
}
135137

136138
// Attestation info needed for on-chain KMS authorization.
@@ -143,6 +145,12 @@ message AttestationInfoResponse {
143145
bytes os_image_hash = 3;
144146
// Attestation mode (e.g. "dstack-tdx", "dstack-gcp-tdx")
145147
string attestation_mode = 4;
148+
// Custom site name for display
149+
string site_name = 5;
150+
// Ethereum RPC URL from auth API
151+
string eth_rpc_url = 6;
152+
// KMS contract address from auth API
153+
string kms_contract_address = 7;
146154
}
147155

148156
// The Onboard RPC service.

kms/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub(crate) struct KmsConfig {
4040
pub image: ImageConfig,
4141
#[serde(with = "serde_human_bytes")]
4242
pub admin_token_hash: Vec<u8>,
43+
#[serde(default)]
44+
pub site_name: String,
4345
}
4446

4547
impl KmsConfig {

kms/src/main_service/upgrade_authority.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ pub(crate) struct BootResponse {
9999
pub(crate) struct AuthApiInfoResponse {
100100
pub status: String,
101101
pub kms_contract_addr: String,
102+
#[serde(default)]
103+
pub eth_rpc_url: String,
102104
pub gateway_app_id: String,
103105
pub chain_id: u64,
104106
pub app_implementation: String,
@@ -110,6 +112,7 @@ pub(crate) struct GetInfoResponse {
110112
pub is_dev: bool,
111113
pub gateway_app_id: Option<String>,
112114
pub kms_contract_address: Option<String>,
115+
pub eth_rpc_url: Option<String>,
113116
pub chain_id: Option<u64>,
114117
pub app_implementation: Option<String>,
115118
}
@@ -161,15 +164,22 @@ impl AuthApi {
161164
AuthApi::Dev { dev } => Ok(GetInfoResponse {
162165
is_dev: true,
163166
kms_contract_address: None,
167+
eth_rpc_url: None,
164168
gateway_app_id: Some(dev.gateway_app_id.clone()),
165169
chain_id: None,
166170
app_implementation: None,
167171
}),
168172
AuthApi::Webhook { webhook } => {
169173
let info: AuthApiInfoResponse = http_get(&webhook.url).await?;
174+
let eth_rpc_url = if info.eth_rpc_url.is_empty() {
175+
None
176+
} else {
177+
Some(info.eth_rpc_url.clone())
178+
};
170179
Ok(GetInfoResponse {
171180
is_dev: false,
172181
kms_contract_address: Some(info.kms_contract_addr.clone()),
182+
eth_rpc_url,
173183
chain_id: Some(info.chain_id),
174184
gateway_app_id: Some(info.gateway_app_id.clone()),
175185
app_implementation: Some(info.app_implementation.clone()),

kms/src/onboard_service.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,10 @@ impl OnboardRpc for OnboardHandler {
9898
)
9999
.await
100100
.context("Failed to onboard")?;
101+
let k256_pubkey = keys.k256_key.verifying_key().to_sec1_bytes().to_vec();
101102
keys.store(&self.state.config)
102103
.context("Failed to store keys")?;
103-
Ok(OnboardResponse {})
104+
Ok(OnboardResponse { k256_pubkey })
104105
}
105106

106107
async fn get_attestation_info(self) -> Result<AttestationInfoResponse> {
@@ -136,11 +137,26 @@ impl OnboardRpc for OnboardHandler {
136137
.decode_app_info_ex(false, &info.vm_config)
137138
.context("Failed to decode app info")?;
138139

140+
let (eth_rpc_url, kms_contract_address) = match self.state.config.auth_api.get_info().await
141+
{
142+
Ok(info) => (
143+
info.eth_rpc_url.unwrap_or_default(),
144+
info.kms_contract_address.unwrap_or_default(),
145+
),
146+
Err(err) => {
147+
tracing::warn!("failed to get auth api info: {err}");
148+
(String::new(), String::new())
149+
}
150+
};
151+
139152
Ok(AttestationInfoResponse {
140153
device_id: app_info.device_id,
141154
mr_aggregated: app_info.mr_aggregated.to_vec(),
142155
os_image_hash: app_info.os_image_hash,
143156
attestation_mode,
157+
site_name: self.state.config.site_name.clone(),
158+
eth_rpc_url,
159+
kms_contract_address,
144160
})
145161
}
146162

kms/src/www/onboard.html

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@
145145
color: #333;
146146
}
147147

148+
.chain-info {
149+
background-color: #f8f4e8;
150+
border: 1px solid #ddc;
151+
border-radius: 4px;
152+
padding: 15px;
153+
margin-bottom: 20px;
154+
}
155+
156+
.chain-info h3 {
157+
margin-top: 0;
158+
color: #444;
159+
}
160+
148161
.loading {
149162
color: #888;
150163
font-style: italic;
@@ -154,7 +167,7 @@
154167

155168
<body>
156169
<div id="app" class="container">
157-
<h1>dstack KMS Setup</h1>
170+
<h1>{{ siteName || 'dstack KMS Setup' }}</h1>
158171

159172
<div v-if="attestationLoading" class="loading">Loading attestation info...</div>
160173
<div v-else-if="attestationError" class="error">Attestation info: {{ attestationError }}</div>
@@ -178,6 +191,18 @@ <h3>Attestation Info (for on-chain registration)</h3>
178191
</div>
179192
</div>
180193

194+
<div v-if="attestationInfo && (attestationInfo.eth_rpc_url || attestationInfo.kms_contract_address)" class="chain-info">
195+
<h3>Chain Info</h3>
196+
<div v-if="attestationInfo.eth_rpc_url" class="info-row">
197+
<span class="info-label">ETH RPC URL:</span>
198+
<span class="info-value">{{ attestationInfo.eth_rpc_url }}</span>
199+
</div>
200+
<div v-if="attestationInfo.kms_contract_address" class="info-row">
201+
<span class="info-label">KMS Contract:</span>
202+
<span class="info-value">{{ attestationInfo.kms_contract_address }}</span>
203+
</div>
204+
</div>
205+
181206
<div v-if="!setupFinished">
182207
<div v-if="!selectedOption" class="initial-buttons">
183208
<button @click="selectedOption = 'bootstrap'">Bootstrap</button>
@@ -261,7 +286,8 @@ <h2>Onboard from an Existing KMS Instance</h2>
261286
setupFinished: false,
262287
attestationInfo: null,
263288
attestationLoading: true,
264-
attestationError: ''
289+
attestationError: '',
290+
siteName: ''
265291
}
266292
},
267293
async mounted() {
@@ -271,6 +297,10 @@ <h2>Onboard from an Existing KMS Instance</h2>
271297
this.attestationError = data.error;
272298
} else {
273299
this.attestationInfo = data;
300+
if (data.site_name) {
301+
this.siteName = data.site_name;
302+
document.title = data.site_name;
303+
}
274304
}
275305
} catch (err) {
276306
this.attestationError = err.message;
@@ -310,6 +340,9 @@ <h2>Onboard from an Existing KMS Instance</h2>
310340
if (data.error) throw new Error(data.error);
311341

312342
this.success = 'Onboarding successful!';
343+
this.result = JSON.stringify({
344+
k256Pubkey: '0x' + data.k256_pubkey,
345+
}, null, 2);
313346
this.error = '';
314347
} catch (err) {
315348
this.error = err.message;

0 commit comments

Comments
 (0)