Autor: Aghiles Ait Messaoud, PhD, Research Software Engineer bei iExec.

Einführung

Teil 1 dieser Reihe legte das Fundament der Nox-Chain-of-Trust: die Verifizierung beim Systemstart, die verhindert, dass eine „Confidential Virtual Machine“ (CVM) ein Geheimnis erhält, sofern sie nicht in einem bekannten Betriebssystem-Image und einem bekannten Application-Stack gestartet wurde – auf attestierter Intel-TDX-Hardware. Diese Garantie wird jedoch intern von der Plattform zur Startzeit erzwungen; für sich allein gibt sie einem Endbenutzer oder einem externen Auditor zu einem späteren Zeitpunkt keine direkte Möglichkeit zu prüfen, dass ein laufender Nox-Dienst noch genau die Arbeitslast ist, die attestiert wurde.

Dieses Dokument ist der zweite Teil der Serie und schließt diese Lücke: Runtime Attestation, also die Möglichkeit für jede Partei, zu jedem Zeitpunkt im Lebenszyklus eines CVM zu verifizieren, dass eine bestimmte Nox-Komponente tatsächlich den erwarteten Code in einem echten Intel TDX Trust Domain (TD) ausführt. Wir beschreiben (i), wie eine frische TDX-Quote von einem laufenden CVM angefragt wird und was sie enthält; (ii) die um die TDX-Fleet herum bereitgestellten Komponenten, um die laufenden CVMs zu entdecken und ihre Quotes bereitzustellen; (iii) die Ende-zu-Ende-Sequenz und die benutzerseitige Oberfläche, über die diese Evidenz sichtbar wird; und (iv) das Schritt-für-Schritt-Protokoll, mit dem eine Quote verifiziert wird – von der Signatur bis zu dem tatsächlich ausgeführten docker-compose.

Es baut direkt auf der in Teil 1 beschriebenen TEE-Basis auf und beschränkt seinen Umfang bewusst auf Runtime Attestation, wie sie über die Runtime Attestation UI bereitgestellt wird. Die verbleibenden Verbindungen der Chain of Trust – Source-Code-Bindung und On-Chain-Governance der autorisierten Messungen – werden in späteren Teilen behandelt.

Der Rest dieses Dokuments ist wie folgt aufgebaut. Im Hintergrund erinnern wir daran, was Runtime Attestation ist, wie eine TDX-Quote strukturiert ist und die drei Quote-Felder, auf die Nox setzt. Im Abschnitt „Architectural deployment“ beschreiben wir die um die TDX-Server herum bereitgestellten Komponenten und welche Daten sie austauschen. In „Reference environment“ fixieren wir die Versionen der Komponenten, auf denen dieser Artikel basiert. Im „Sequence Diagram“ verfolgen wir den Ende-zu-Ende-Flow, mit dem die UI die laufenden CVMs entdeckt und sie attestiert. In „User Interface Presentation“ stellen wir die Oberfläche und ihre drei Attestierungsstufen vor. In „Attestation steps of a Nox component“ erläutern wir das Verifizierungsprotokoll, das auf eine einzelne CVM angewendet wird. Schließlich skizzieren wir in „Future Work“ die geplanten Verbesserungen: Image-Provenance, vom Nutzer bereitgestellte Challenges und zusätzliche Quote-Verifier.

Hintergrund

In diesem Abschnitt werfen wir einen Blick auf die Konzepte, auf denen dieses Dokument aufbaut: was Runtime Attestation ist, wie eine TDX-Quote strukturiert ist und die drei Quote-Felder, auf die Nox setzt, nämlich report_data, die RTMRs und deren zugehörige Event-Logs.

Runtime Attestation

Runtime Attestation ist der Mechanismus, der es jeder entfernten Partei ermöglicht, auf Abruf und zu jedem Zeitpunkt im Lebenszyklus einer CVM zu verifizieren, dass eine Nox-Komponente tatsächlich innerhalb eines echten Intel TDX Trust Domain (TD) mit dem erwarteten Code und der erwarteten Konfiguration läuft. Während die Attestierung zur Boot-Zeit (siehe Teil 1) die Chain of Trust von der Hardware bis zu dstack-OS herstellt, macht Runtime Attestation dieses Vertrauen für externe Verifier über ein einfaches Challenge-Response-Protokoll zugänglich.

TDX-Quote

Eine TDX-Quote ist eine kryptografisch signierte Struktur, die von der Quoting Enclave der Plattform erzeugt wird. Sie enthält die Evidenz, die ein Verifier benötigt, um einem TD zu vertrauen, und sie ist mit einem von Intel bereitgestellten Attestation-Schlüssel signiert. Dadurch kann jeder ihre Echtheit validieren, indem die Zertifikatkette bis zur Intel-Root of Trust zurückverfolgt wird. Die drei Felder, auf die Nox für Runtime Attestation setzt (report_data, die RTMRs und deren zugehörige Event-Logs), werden unten detailliert beschrieben.

report_data

report_data ist ein 64-Byte-Feld, dessen Inhalt vollständig von der Workload ausgewählt wird. TDX kopiert es unverändert in die signierte Quote, wodurch eine Anwendung beliebige Daten an die Hardware-Attestation binden kann. Häufige Anwendungsfälle sind:

  • Frische / Challenge-Response: Ein von einem Verifier bereitgestellter Nonce wird eingebettet, wie es die Runtime Attestation UI tut, um nachzuweisen, dass die Quote bei Bedarf generiert wurde.

  • Identitätsbindung: Einbetten des Hashes eines öffentlichen Schlüssels oder TLS-Zertifikats (die Grundlage von RA-TLS, siehe Teil 1), sodass ein sicherer Kanal nachweislich innerhalb des TD beendet wird.

  • Andere Beweise, z. B. Blockchain-Wallet-Adressen oder Hashes des Anwendungszustands.

In Nox generiert die UI eine zufällige Challenge und erwartet, genau diesen Wert in der report_data der Quote zu finden.

RTMRs

Runtime Measurement Registers (RTMRs) sind das TDX-Pendant zu TPM-PCRs: Append-only-Register, die nicht direkt beschrieben werden können, sondern nur über eine Hash-Kette erweitert werden. Ein TD stellt davon vier bereit, und dstack weist jedem eine klar definierte Rolle zu:

  • RTMR0: die virtuelle Hardware-/Firmware-Umgebung.

  • RTMR1: der Linux-Kernel.

  • RTMR2: die Kernel-Kommandozeile und initrd.

  • RTMR3: anwendungspezifische Messungen: app-id, os_image_hash, compose-hash, instance-id und key-provider.

Der anfängliche Speicherinhalt und die Konfiguration des TD werden separat in MRTD erfasst. Während der Verifizierung attestieren RTMR0–RTMR2 (zusammen mit MRTD) die Integrität der Boot-Kette, während RTMR3 attestiert, dass der erwartete Anwendungs-Code und die erwartete Konfiguration laufen. In Nox konzentrieren wir uns auf RTMR3, da es die Quote an die konkrete Nox-Komponente und deren docker-compose bindet.

Event-Logs

Ein RTMR-Wert ist ein undurchsichtiger Hash: Er belegt, ob die erwarteten Messungen eingefaltet wurden, aber nicht, welche es waren. Das Event-Log ist der für Menschen lesbare Nachweis der einzelnen Messereignisse, die in ein RTMR erweitert wurden (in der Praxis RTMR3). Jedes Event ist eine Schlüssel-Wert-Messung wie app-id, compose-hash, instance-id oder key-provider, und jedes Event wird mit der Erweiterungsformel in das Register eingerechnet:

RTMR3_new = SHA384(RTMR3_old || SHA384(event_log))

Ein Verifier spielt das Event-Log über diese Formel zurück und vergleicht das neu berechnete Register mit dem rt_mr3-Wert in der signierten Quote. Wenn sie übereinstimmen, können die einzelnen Event-Werte, insbesondere os_image_hash und compose_hash, als getreue Repräsentationen des OS-Images und des tatsächlich von dem CVM ausgeführten docker-compose vertraut werden.

Architektonisches Deployment

In diesem Abschnitt beschreiben wir die Komponenten, die rund um die TDX-Server bereitgestellt werden, damit die Runtime Attestation UI funktioniert, und wir veranschaulichen die Struktur der Daten, die sie austauschen.

Um die Runtime Attestation UI funktionsfähig zu machen, arbeiten fünf zentrale Komponenten zusammen:

  • Portal für die Runtime Attestation UI: Die Oberfläche, die der Nutzer aufruft, um den Runtime-Attestation-Prozess zu visualisieren. Sie ist bereits auf der iExec-Seite unter https://trust.noxprotocol.io bereitgestellt, kann aber auch mit Hilfe ihres Quellcodes (https://github.com/iExec-Nox/nox-attestation-portal) neu gebaut und auf persönlichen Computern bereitgestellt werden. Die UI fordert nox-cvms-exporter-aggregator auf, die Liste aktiver CVMs abzurufen – zusammen mit der jeweils frisch abgerufenen Quote und dem docker-compose. Der Aggregator selbst kontaktiert jeden CVM dstack-quote-service, sodass die UI nie direkt mit den CVMs spricht.

  • nox-cvms-exporter: ein Host-Service, der sich mit dem dstack-Hypervisor (dstack-vmm) verbindet, um die Liste der aktiven CVMs (deren dstack-quote-service-URL) auf der lokalen TDX-Maschine einzusammeln und an den nox-cvms-exporter-aggregator zu senden.

  • nox-cvms-exporter-aggregator: ein auf Azure Kubernetes Service bereitgestellter Dienst, der die Liste der aktiven CVMs aggregiert, die von jedem einzelnen nox-cvms-exporter empfangen wurden. Für jede aufgelistete CVM kontaktiert er anschließend den CVM dstack-quote-service, um dessen frische Quote (an die UI-Challenge gebunden) und sein docker-compose abzurufen, und gibt die angereicherte Liste an das Portal der Runtime Attestation UI zurück.

  • Proof of Cloud Trust Server: iExec-Server für Proof of Cloud (http://github.com/proofofcloud/trust-server), um zu prüfen, ob eine Quote von einer whitelisted TDX-Maschine ausgegeben wurde und nicht widerrufen ist. Details zum Whitelisting-Prozess von Proof of Cloud sind in Teil I unserer Artikelserie dokumentiert.

  • Phala PCCS: lokaler Phala-Cache zum Speichern von Collaterals (TCB Infos, Intel-PCK-Zertifikate und Zertifikat-Revocation-Lists), um eine Quote zu verifizieren.

Referenzumgebung

In diesem Abschnitt legen wir die exakten Versionen der Komponenten fest, die in der Runtime Attestation UI beteiligt sind. So kann das Verhalten, das im Rest dieses Artikels beschrieben wird, reproduziert werden und – während sich diese Komponenten weiterentwickeln – gegen eine bekannte Basislinie verglichen werden.

Sequenzdiagramm

In diesem Abschnitt verfolgen wir die Ende-zu-Ende-Sequenz, mit der die Runtime Attestation UI die laufenden CVMs entdeckt und sie attestiert – vom Öffnen des Portals bis zur Anzeige des Ergebnisses.

Dieses Diagramm beschreibt, wie die Runtime Attestation UI die Confidential VMs (CVMs) auf der TDX-Fleet entdeckt und sie attestiert.

  1. Portal öffnen: Der Nutzer öffnet das Portal entweder direkt über die iExec-gehostete Instanz https://trust.noxprotocol.io oder indem er das Quell-Repository selbst baut und ausführt (https://githu b.com/iExec-Nox/nox-attestation-portal ). Beim Laden generiert die UI eine einzelne zufällige Challenge (32 Bytes), die erwartungsgemäß an die gesammelten Quotes gebunden ist.

  2. Discovery-Anfrage: Die UI ruft den Aggregator GET /cvms auf und übergibt seine Challenge als Query-Parameter (?challenge=...). Dieser Parameter ist zwingend, da die Challenge an die CVMs weitergeleitet werden muss, um die zurückgegebenen Quotes zu binden.

  3. Fan-out zu Exportern: Für jede TDX-Maschine in ihrer konfigurierten Exporter-Liste ruft der Aggregator GET {base_url}/cvms parallel. Die Challenge wird in dieser Phase nicht weitergeleitet; sie wird erst später verwendet, wenn die Quotes abgefragt werden.

  4. Lokale CVM-Aufzählung: Jeder Exporter fragt sein lokales dstack-vmm (POST /prpc/Status?json) ab, um die auf dieser Maschine laufenden VMs aufzulisten.

  5. VMM-Antwort: dstack-vmm gibt die rohe VM-Liste zurück. Der Exporter filtert VMs heraus, deren Status gestoppt/entfernt ist, und schließt die kms- und dstack-gateway-System-CVMs aus.

  6. Exporter-Antwort: Der Exporter erstellt für jede CVM den Quote-Service-Base-URL und gibt die CVMs gruppiert nach app_id zurück, wobei jede Instanz { instance_id, url, machine_id } mitführt.

  7. Quote-Anfrage (Anreicherung): Der Aggregator bereichert jede Instanz mit ihrer frischen Quote: Für jede Instanz ruft der Aggregator den CVM-Quote-Service GET {url}/quote?data={challenge} auf und leitet dabei die UI-Challenge weiter, sodass die zurückgegebene Quote an sie gebunden ist.

  8. Quote-Antwort: Der Quote-Service gibt { quote, event_log } zurück, da die UI die Quote für den Signatur-Check und das Event-Log für das RTMR3-Replay benötigt.

  9. Manifest-Anfrage: Zeitgleich mit der Quote-Anfrage ruft der Aggregator denselben CVM-Quote-Service GET {url}/info auf, um das Deployment-Manifest abzurufen.

  10. Manifest-Antwort: Der Quote-Service gibt seine /info-Payload zurück; daraus extrahiert der Aggregator das docker-compose-Manifest (tcb_info.app_compose).

  11. Zusammenführen & antworten: Der Aggregator gruppiert die angereicherten Instanzen nach app_id und gibt die zusammengeführte Liste an die UI zurück. Jede Instanz trägt nun { instance_id, machine_id, quote: { quote, event_log }, app_compose }. Das Feld url wird intern im Aggregator behalten und niemals der UI offengelegt, sodass der Browser die CVMs nicht direkt erreichen kann. Die JSON-Datei unten zeigt ein Beispiel für einen aggregierten Eintrag, den der nox-cvms-exporter-aggregator an die Attestation-UI sendet.

{

"app_id": "a1b2c3...",

"name": "nox-component-cvm",

"instances": [

{

"instance_id": "i-0abc123",

"machine_id": "Node 1",

"quote": {

"quote": "0x0400...", # TDX-Quote (Hex)

"event_log": [ ... ] # RTMR3-Event-Log

},

"app_compose": "..." # docker-compose (YAML)-Manifest

},

{

"instance_id": "i-0def456",

"machine_id": "Node 2",

"quote": {

"quote": "0x0400...",

"event_log": [ ... ]

},

"app_compose": "..."

}

]

}

Verifizieren & anzeigen: Für jede zurückgegebene CVM prüft die UI die Attestierung lokal und zeigt die CVMs zusammen mit dem Ergebnis an. Dieses Verifizierungsprotokoll wird in den Attestation steps of a Nox component beschrieben.

Darstellung der Benutzeroberfläche

In diesem Abschnitt stellen wir die Runtime Attestation UI und die drei Attestierungsstufen vor, die sie dem Nutzer bereitstellt.

Runtime Attestation UI wie angezeigt in NOX · Chain of Trust https://trust.noxprotocol.io

Der Screenshot oben zeigt die Runtime Attestation UI. Beim Laden listet das linke Bedienfeld die Nox-Komponenten auf, die auf den Testnet-TDX-Maschinen laufen; jede Komponente ist mit ihrer Anzahl von Replikas annotiert (z. B. 6 für nox-kms). Die Oberfläche bietet drei Attestierungsstufen für Nox-Komponenten:

  1. Vollständige Verifizierung: Sobald auf die Schaltfläche „Verify all“ geklickt wird, werden alle CVM-Instanzen aller Nox-Komponenten verifiziert
    .

  2. Verifizierung auf Komponentenebene: Diese Stufe wird verfügbar, sobald eine Nox-Komponente im linken Bedienfeld ausgewählt wurde. Sobald auf „Verify all“ geklickt wird, werden alle CVM-Instanzen der ausgewählten Nox-Komponente verifiziert – unabhängig von der zugrunde liegenden Maschine.

  3. Verifizierung auf Instanzebene: Diese Stufe wird ebenfalls verfügbar, sobald eine Nox-Komponente im linken Bedienfeld ausgewählt wurde. Sobald auf „Verify“ geklickt wird, wird nur die konkrete Instanz der ausgewählten Nox-Komponente verifiziert.

Attestierungsschritte einer Nox-Komponente

In diesem Abschnitt beschreiben wir das Schritt-für-Schritt-Verifizierungsprotokoll, das auf eine einzelne Nox-Komponenten-CVM angewendet wird, und erklären, was die UI anzeigt, sobald jede Prüfung erfolgreich war.

Runtime-Attestation-Workflow für eine Nox-Komponente

Das auf eine Nox-Komponente CVM angewendete Verifizierungsprotokoll läuft wie folgt ab:

  1. Holen Sie sich ein frisches Angebot: Die UI generiert eine zufällige Challenge und erhält über den Aggregator ein frisches, an diese Challenge gebundenes Angebot (siehe Sequenzdiagramm ). Die Challenge soll in den report_data des Angebots eingebettet sein.

  2. Überprüfen der Signatur und Zertifikatkette des Angebots: die Signatur des Angebots und ihre Zertifikatkette bis hin zu Intel werden von einem DCAP-Verifier validiert. In der aktuellen Implementierung läuft dies lokal im Browser über eine eingebettete Phala dcap-qvl (Quote Verification Library: githubl). Die qvl ruft die Verifizierungs-Assets ab (die TCB-Informationen und die Intel-rooted Zertifikatkette) von der dstack PCCS (Phala-gehosteter Provisioning Certificate Caching Service) und führt den Check selbst durch. Parallel dazu wird die Quote an den Proof of Cloud Trust Server übermittelt, der meldet, ob die attestierte Maschine zu einem whitelisted (zertifizierten) Cloud-Fleet gehört. Dieses Proof-of-Cloud-Ergebnis ist informativ und nicht blockierend: Falls der Trust-Server nicht verfügbar ist oder ein Timeout auftritt, läuft die Attestierung dennoch weiter.

  3. Überprüfen der Quote-Frische: die Frische der Quote wird bestätigt, indem überprüft wird, dass die zufällige, von der UI erzeugte Challenge in den report_data der Quote eingebettet ist.

  4. RTMR-Werte anzeigen: ein informativer Schritt, der die RTMR-Werte der Quote extrahiert und anzeigt.

  5. RTMR3 wiedergeben: die zusammen mit der Quote zurückgegebenen Event-Logs (in der Aggregator-Antwort) werden verwendet, um RTMR3 gemäß der Intel-Formel nachzubilden: RTMR3_new = SHA384(RTMR3_old || SHA384(event_log)). Wenn das nachgebildete RTMR3 mit dem attestierten übereinstimmt (in der Quote), können die Event-Log-Werte os_image_hash und compose_hash als repräsentativ für das ausgeführte Betriebssystem und das docker-compose vertraut werden.

  6. OS-Image prüfen: das os_image_hash RTMR3-Event-Log wird extrahiert, und ein Download-Link wird bereitgestellt, damit das Image und sein Hash bei Bedarf manuell überprüft werden können. Bei iExec ist dieses Image dstackOS.

  7. Compose-Hash prüfen: das docker-compose (app_compose, das in der Aggregator-Antwort bereitgestellt wird) wird gehasht, und das Ergebnis wird mit dem eingebetteten compose_hash verglichen, das als RTMR3-Event-Log gespeichert ist.

Sobald diese Verifizierungsschritte durchgeführt wurden, wird das docker-compose angezeigt, das dem compose-hash des attestierten CVM entspricht, wie im Bild unten dargestellt.

Teil von nox-kms docker-compose

Das docker-compose der CVM umfasst drei Services:

  • nox-component: der im CVM ausgeführte Business-Service (z. B. nox-kms)

  • quote-service: der Service, der die Quote und die Event-Logs beschafft, die benötigt werden, um das CVM zu attestieren

  • fluent-bit: iExec-Log-Exporter-Service für interne Beobachtbarkeit

Zukünftige Arbeiten

In diesem Abschnitt skizzieren wir die geplanten Verbesserungen für den Attestation-Flow: Image-Provenance, vom Nutzer bereitgestellte Challenges und zusätzliche Quote-Verifier.

Image-Provenance

Aktuell endet die Attestierung, sobald wir das docker compose anzeigen, das die in dem attestierten CVM ausgeführten Images auflistet. Als nächster Schritt kann man die Sigstore-Infrastruktur nutzen, um den GitHub-Actions-Workflow, der jedes Image erzeugt, während des Builds zu signieren und dann die SLSA (Supply-chain Levels for Software Artifacts)-Attestation zu veröffentlichen, die durch die sha256-Checksumme des Images (subject-name) in GitHub und dem Docker-Registry des Images identifiziert wird. Ein Rekor-Eintrag wird ebenfalls auf natürliche Weise gepusht. Dadurch können wir die in diesem Artikel genannten Verifizierungsschritte erweitern, indem wir die Herkunft (Provenance) jedes Nox-Images attestieren (d. h. Build-Workflow und GitHub-Repo-Commit).

Vom Nutzer eingegebene Challenge

Aktuell testen wir die Frische einer Quote mit einer automatisch erzeugten Challenge, die von der UI als Query-Parameter an den Aggregator übermittelt wird; dieser leitet sie dann an jeden Quote-Service weiter. Wir werden diesen Prozess stärken, indem wir UI-Nutzern erlauben, ihre eigene Challenge einzugeben, um eine zusätzliche Vertrauensebene in die Frische der Quote zu erhalten.

Mehrere Verifier

Aktuell verwenden wir Phala qvl als die einzige Verifizierungsmethode, um die Intel-Signatur und Zertifikatkette einer Quote zu prüfen. Wir werden zusätzliche Verifizierungsmethoden ergänzen, entweder als Backups oder als obligatorische Checks, falls verfügbar, um das Vertrauen in das Verifizierungsergebnis zu verbessern. Die potenziellen Verifier, die wir hinzufügen könnten, sind iExec-gehostete dstack-verifier und Intel Trust Authority.