Skip to content

Commit 10898e6

Browse files
committed
guest-agent: remove EmitEvent API
The RPC only meaningfully works on TDX (RTMR3 extension), is rarely used, and cannot be implemented faithfully in the simulator or across TEEs. Apps that need extra runtime measurements should use native TEE interfaces. Keep emit_runtime_event for guest boot measurements in dstack-util.
1 parent e5f138c commit 10898e6

19 files changed

Lines changed: 12 additions & 292 deletions

File tree

docs/native-tee-interfaces.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,4 @@ For configfs-tsm, permissions can be more provider-specific. If your main proces
144144

145145
On TDX, RTMR3 is an append-only runtime measurement register. It is useful when a launcher measures code or configuration first, then hands permission and execution to the measured code.
146146

147-
Use `/EmitEvent` through `/var/run/dstack.sock` when you want dstack's event log and verifier to replay an application runtime measurement. If your application extends RTMR3 directly through native interfaces, your application owns the event-log story for those extensions.
147+
dstack itself extends RTMR3 during guest boot (compose-hash, key-provider, instance-id, and related runtime events). Applications that need additional runtime measurements should extend RTMR3 through the native TDX / TSM measurement interfaces documented above and own the event-log story for those extensions.

docs/security/security-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ dstack replays an event log only for RTMR3. RTMR0-2 (and MRTD) are not replayed
166166

167167
This is also reflected at the source: the event log shipped alongside an attestation is stripped down to RTMR3 entries before it is embedded. `VersionedAttestation::into_stripped()` keeps only events with `imr == 3` (see `dstack-attest/src/attestation.rs`), and verification only ever replays those runtime events against `rt_mr3` (`verify_tdx_quote_with_events` / `decode_mr_tdx_from_quote`).
168168

169-
The reason boot-time event log entries (RTMR0-2) are dropped is that **nothing downstream consumes them**. Verification recomputes the OS-layer measurements directly from the signed `rt_mr0/1/2` values and compares them to independently reproduced expected measurements, so the corresponding boot event log would be redundant. Keeping it would only bloat the RA-TLS certificate and expose extra detail without adding any verification capability. RTMR3, by contrast, is runtime-extended (compose-hash, key-provider, instance-id, and application-emitted events), so its event log is the only one with a real consumer — the replay that proves what was extended into RTMR3.
169+
The reason boot-time event log entries (RTMR0-2) are dropped is that **nothing downstream consumes them**. Verification recomputes the OS-layer measurements directly from the signed `rt_mr0/1/2` values and compares them to independently reproduced expected measurements, so the corresponding boot event log would be redundant. Keeping it would only bloat the RA-TLS certificate and expose extra detail without adding any verification capability. RTMR3, by contrast, is runtime-extended (compose-hash, key-provider, instance-id, and other guest boot events), so its event log is the only one with a real consumer — the replay that proves what was extended into RTMR3.
170170

171171
### Why TDX lite mode does not validate ACPI table contents
172172

dstack-attest/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ mod v1;
2424
/// Appending to the event log and extending RTMR3 must happen atomically as a
2525
/// unit: the order of log entries has to match the order of RTMR extensions,
2626
/// otherwise the RTMR replay performed during quote verification will not
27-
/// reproduce the measured value. Concurrent callers (e.g. multiple
28-
/// `emit_event` RPCs hitting the guest-agent at once) would otherwise be able
27+
/// reproduce the measured value. Concurrent callers would otherwise be able
2928
/// to interleave their log writes and `extend_rtmr` calls.
3029
static EMIT_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
3130

guest-agent-simulator/src/main.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod simulator;
66

77
use std::sync::Arc;
88

9-
use anyhow::{bail, Context, Result};
9+
use anyhow::{Context, Result};
1010
use clap::Parser;
1111
use dstack_guest_agent::{
1212
backend::PlatformBackend,
@@ -89,10 +89,6 @@ impl PlatformBackend for SimulatorPlatform {
8989
fn attest_response(&self, report_data: [u8; 64]) -> Result<AttestResponse> {
9090
simulator::simulated_attest_response(&self.attestation, report_data, self.patch_report_data)
9191
}
92-
93-
fn emit_event(&self, event: &str, _payload: &[u8]) -> Result<()> {
94-
bail!("runtime event emission is unavailable in simulator mode: {event}")
95-
}
9692
}
9793

9894
#[rocket::main]
@@ -145,13 +141,6 @@ mod tests {
145141
SimulatorPlatform::new(fixture, true)
146142
}
147143

148-
#[test]
149-
fn simulator_rejects_runtime_event_emission() {
150-
let platform = load_fixture_platform();
151-
let err = platform.emit_event("test.event", b"payload").unwrap_err();
152-
assert!(err.to_string().contains("unavailable in simulator mode"));
153-
}
154-
155144
#[test]
156145
fn simulator_provides_certificate_attestation() {
157146
let platform = load_fixture_platform();

guest-agent/rpc/proto/agent_rpc.proto

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ service DstackGuest {
5050
// Returns a dstack-defined attestation format that supports different attestation modes across platforms.
5151
rpc Attest(RawQuoteArgs) returns (AttestResponse) {}
5252

53-
// Emit an event. This extends the event to RTMR3 on TDX platform.
54-
rpc EmitEvent(EmitEventArgs) returns (google.protobuf.Empty) {}
55-
5653
// Get app info
5754
rpc Info(google.protobuf.Empty) returns (AppInfo) {}
5855

@@ -205,13 +202,6 @@ message GetQuoteResponse {
205202
bytes attestation = 5;
206203
}
207204

208-
message EmitEventArgs {
209-
// The event name
210-
string event = 1;
211-
// The event data
212-
bytes payload = 2;
213-
}
214-
215205
// The request to derive a key
216206
message AppInfo {
217207
// App ID

guest-agent/src/backend.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: Apache-2.0
44

55
use anyhow::{Context, Result};
6-
use dstack_attest::emit_runtime_event;
76
use dstack_guest_agent_rpc::{AttestResponse, GetQuoteResponse};
87
use ra_tls::attestation::Attestation;
98
use ra_tls::attestation::{QuoteContentType, VersionedAttestation};
@@ -13,7 +12,6 @@ pub trait PlatformBackend: Send + Sync {
1312
fn certificate_attestation(&self, pubkey: &[u8]) -> Result<VersionedAttestation>;
1413
fn quote_response(&self, report_data: [u8; 64], vm_config: &str) -> Result<GetQuoteResponse>;
1514
fn attest_response(&self, report_data: [u8; 64]) -> Result<AttestResponse>;
16-
fn emit_event(&self, event: &str, payload: &[u8]) -> Result<()>;
1715
}
1816

1917
#[derive(Debug, Default)]
@@ -62,8 +60,4 @@ impl PlatformBackend for RealPlatform {
6260
attestation: attestation.into_versioned().to_bytes()?,
6361
})
6462
}
65-
66-
fn emit_event(&self, event: &str, payload: &[u8]) -> Result<()> {
67-
emit_runtime_event(event, payload)
68-
}
6963
}

guest-agent/src/rpc_service.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ use dstack_guest_agent_rpc::{
1111
dstack_guest_server::{DstackGuestRpc, DstackGuestServer},
1212
tappd_server::{TappdRpc, TappdServer},
1313
worker_server::{WorkerRpc, WorkerServer},
14-
AppInfo, AttestResponse, DeriveK256KeyResponse, DeriveKeyArgs, EmitEventArgs,
15-
GetAttestationForAppKeyRequest, GetKeyArgs, GetKeyResponse, GetQuoteResponse, GetTlsKeyArgs,
16-
GetTlsKeyResponse, RawQuoteArgs, SignRequest, SignResponse, TdxQuoteArgs, TdxQuoteResponse,
17-
VerifyRequest, VerifyResponse, WorkerVersion,
14+
AppInfo, AttestResponse, DeriveK256KeyResponse, DeriveKeyArgs, GetAttestationForAppKeyRequest,
15+
GetKeyArgs, GetKeyResponse, GetQuoteResponse, GetTlsKeyArgs, GetTlsKeyResponse, RawQuoteArgs,
16+
SignRequest, SignResponse, TdxQuoteArgs, TdxQuoteResponse, VerifyRequest, VerifyResponse,
17+
WorkerVersion,
1818
};
1919
use dstack_types::{AppKeys, SysConfig};
2020
use ed25519_dalek::ed25519::signature::hazmat::{PrehashSigner, PrehashVerifier};
@@ -179,10 +179,6 @@ impl AppState {
179179
fn attest_response(&self, report_data: [u8; 64]) -> Result<AttestResponse> {
180180
self.inner.platform.attest_response(report_data)
181181
}
182-
183-
fn emit_event(&self, event: &str, payload: &[u8]) -> Result<()> {
184-
self.inner.platform.emit_event(event, payload)
185-
}
186182
}
187183

188184
pub struct InternalRpcHandler {
@@ -328,10 +324,6 @@ impl DstackGuestRpc for InternalRpcHandler {
328324
self.state.quote_response(report_data)
329325
}
330326

331-
async fn emit_event(self, request: EmitEventArgs) -> Result<()> {
332-
self.state.emit_event(&request.event, &request.payload)
333-
}
334-
335327
async fn info(self) -> Result<AppInfo> {
336328
get_info(&self.state, false).await
337329
}
@@ -858,10 +850,6 @@ pNs85uhOZE8z2jr8Pg==
858850
attestation: VersionedAttestation::V1 { attestation }.to_bytes()?,
859851
})
860852
}
861-
862-
fn emit_event(&self, _event: &str, _payload: &[u8]) -> Result<()> {
863-
Ok(())
864-
}
865853
}
866854

867855
let inner = AppStateInner {

sdk/curl/api.md

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -174,34 +174,7 @@ curl --unix-socket /var/run/dstack.sock http://dstack/Info
174174
}
175175
```
176176

177-
### 5. Emit Event
178-
179-
Emit an event to be extended to RTMR3 on TDX platform. This API requires dstack OS 0.5.0 or later.
180-
181-
**Endpoint:** `/EmitEvent`
182-
183-
**Request Parameters:**
184-
185-
| Field | Type | Description | Example |
186-
|-------|------|-------------|----------|
187-
| `event` | string | The event name | `"custom-event"` |
188-
| `payload` | string | Hex-encoded payload data | `"deadbeef"` |
189-
190-
**Example:**
191-
```bash
192-
curl --unix-socket /var/run/dstack.sock -X POST \
193-
http://dstack/EmitEvent \
194-
-H 'Content-Type: application/json' \
195-
-d '{
196-
"event": "custom-event",
197-
"payload": "deadbeef"
198-
}'
199-
```
200-
201-
**Response:**
202-
Empty response with HTTP 200 status code on success.
203-
204-
### 6. Sign (not yet released)
177+
### 5. Sign (not yet released)
205178

206179
Signs a payload.
207180

@@ -238,7 +211,7 @@ curl --unix-socket /var/run/dstack.sock -X POST \
238211
}
239212
```
240213

241-
### 7. Verify (not yet released)
214+
### 6. Verify (not yet released)
242215

243216
Verifies a signature.
244217

@@ -273,7 +246,7 @@ curl --unix-socket /var/run/dstack.sock -X POST \
273246
}
274247
```
275248

276-
### 8. Attest
249+
### 7. Attest
277250

278251
Generates a versioned attestation with the given report data. Returns a dstack-defined attestation format that supports different attestation modes across platforms.
279252
You can submit the returned `attestation` directly to the verifier `/verify` endpoint.

sdk/go/README.md

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -168,37 +168,6 @@ tlsKey2, _ := client.GetTlsKey(ctx, dstack.TlsKeyOptions{})
168168
// tlsKey1.Key != tlsKey2.Key (always different!)
169169
```
170170

171-
### Event Logging
172-
173-
> [!NOTE]
174-
> This feature isn't available in the simulator. We recommend sticking with `report_data` for most cases since it's simpler and safer to use. If you're not super familiar with SGX/TDX attestation quotes, it's best to avoid adding data directly into quotes as it could cause verification issues.
175-
176-
Extend RTMR3 with custom events for audit trails:
177-
178-
```go
179-
// Emit custom events (requires dstack OS 0.5.0+)
180-
eventData := map[string]interface{}{
181-
"action": "transfer",
182-
"amount": 1000,
183-
"timestamp": time.Now().Unix(),
184-
}
185-
eventPayload, _ := json.Marshal(eventData)
186-
187-
err := client.EmitEvent(ctx, "user-action", eventPayload)
188-
if err != nil {
189-
log.Fatal(err)
190-
}
191-
192-
// Events are automatically included in subsequent quotes
193-
quote, err := client.GetQuote(ctx, []byte("audit-data"))
194-
if err != nil {
195-
log.Fatal(err)
196-
}
197-
198-
var events []interface{}
199-
json.Unmarshal([]byte(quote.EventLog), &events)
200-
```
201-
202171
## Optional blockchain helpers (build tags)
203172

204173
By default, the Go SDK builds a **core profile** (attestation, key derivation, info, signing, env encryption).
@@ -655,18 +624,6 @@ cert2, _ := client.GetTlsKey(ctx, dstack.TlsKeyOptions{})
655624
// cert1.Key != cert2.Key (always different)
656625
```
657626

658-
##### `EmitEvent(ctx context.Context, event string, payload []byte) error`
659-
660-
Extends RTMR3 with a custom event for audit logging.
661-
662-
**Parameters:**
663-
- `event`: Event identifier string
664-
- `payload`: Event data
665-
666-
**Requirements:**
667-
- dstack OS version 0.5.0 or later
668-
- Events are permanently recorded in TEE measurements
669-
670627
##### `IsReachable(ctx context.Context) bool`
671628

672629
Tests connectivity to the dstack service.

sdk/go/dstack/client.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -697,21 +697,6 @@ func (c *DstackClient) IsReachable(ctx context.Context) bool {
697697
return err == nil
698698
}
699699

700-
// EmitEvent sends an event to be extended to RTMR3 on TDX platform.
701-
// The event will be extended to RTMR3 with the provided name and payload.
702-
//
703-
// Requires dstack OS 0.5.0 or later.
704-
func (c *DstackClient) EmitEvent(ctx context.Context, event string, payload []byte) error {
705-
if event == "" {
706-
return fmt.Errorf("event name cannot be empty")
707-
}
708-
_, err := c.sendRPCRequest(ctx, "/EmitEvent", map[string]interface{}{
709-
"event": event,
710-
"payload": hex.EncodeToString(payload),
711-
})
712-
return err
713-
}
714-
715700
// Legacy methods for backward compatibility with warnings
716701

717702
// DeriveKey is deprecated. Use GetKey instead.

0 commit comments

Comments
 (0)