Für die Arbeitslastattestierung in der Trusted Execution Environment (TEE) von On Device Personalization (ODP), die öffentlich in Google Cloud als Confidential Space (CS) verfügbar ist, sind deterministische Builds erforderlich.
Die Arbeitslast-Images müssen einen deterministischen Image-Hash generieren, der von Confidential Space für die Arbeitslast-Attestierung verwendet werden kann. Dabei wird die RATS-Architektur (Remote ATtestation procedureS) von NIST gemäß RFC 9334 verwendet.
In diesem Dokument werden die Implementierung und Unterstützung von deterministischen Builds im Repository odp-federatedcompute beschrieben. Die Dienste „ODP Aggregator“ und „Model Updater“ werden in Confidential Space ausgeführt. Das Repository unterstützt deterministische Builds für alle unsere Dienste, die für Produktionsanwendungsfälle erforderlich sind.
Deterministische Builds
Deterministische Builds bestehen aus zwei Hauptkomponenten:
- Die Kompilierung der erforderlichen Binärdateien. Dazu gehören JAR-Dateien, freigegebene Bibliotheken und Metadaten.
- Das Basis-Image und die Laufzeitabhängigkeiten. Das Basis-Image der Laufzeitumgebung, das zum Ausführen der kompilierten Binärdateien verwendet wird.
Derzeit unterstützt das ODP Federated Compute-Repository die folgenden Arten von Arbeitslasten:
- Java- und Spring-Arbeitslasten
- TaskAssignment, TaskManagement, Collector
- Java + Spring mit JNI-TensorFlow-Arbeitslasten
- ModelUpdater, Aggregator
- Python-Arbeitslasten
- TaskBuilder
Abhängigkeiten
In der folgenden Liste sind die Abhängigkeiten aufgeführt, auf die ODP angewiesen ist, um Determinismus und Verfügbarkeit aufrechtzuerhalten:
- Bazel
- GitHub
- Maven
- PyPi
- Debian-Snapshots
- DockerHub-Registry
- Google Container Registry (GCR)
Deterministische Arbeitslasten
Alle Arbeitslasten werden mit Bazel mit sprachspezifischen Toolchains und Container-Images kompiliert, die mit rules_oci erstellt wurden. In der WORKSPACE-Datei werden alle Abhängigkeiten mit den entsprechenden Versionen und Hashes definiert.
Debian-Snapshots
Alle Arbeitslast-Images sollten innerhalb des bereitgestellten dockerfile erstellt werden, das auf einem Debian-Snapshot basiert. Debian-Snapshots bieten einen stabilen Repository-Snapshot mit deterministischen:
- Systemheader und ‑bibliotheken
- Systemarchitektur
- linux_x86_64
- Debian
- C++-Compiler
Java Spring-Arbeitslasten
remotejdk_17 von Bazel wird verwendet, um eine hermetische Java-Umgebung für die Kompilierung bereitzustellen. Andere Java-Abhängigkeiten werden in der WORKSPACE-Datei verwaltet und definiert.
Die Java Spring-Arbeitslasten werden in einer JAR-Datei mit dem Namen <service>_application.jar kompiliert. Die JAR-Datei enthält:
- Java-Klassendateien
META-INF/- Bazel-Manifestdaten
build-data.properties- Bazel-Build-Daten
BOOT-INF/- Verpackte JAR-Abhängigkeiten, die von rules_spring generiert werden.
Bildebenen
Das Java Spring-Arbeitslast-Image besteht aus zwei Ebenen:
- Basisebene des Images
- Java-Basis-Image:
gcr.io/distroless/java17-debian11
- Java-Basis-Image:
- Arbeitslastschicht
binary_tar.tar<service>_application.jar
Image-Konfiguration
- Einstiegspunkt
java -jar <service>_application.jar
JNI-TensorFlow-Arbeitslasten
JNI-TensorFlow-Arbeitslasten basieren auf Java Spring-Arbeitslasten. Eine hermetische Clang+LLVM-Bazel-Toolchain wird mit vorgefertigtem Clang+LLVM 16 mit einem Sysroot bereitgestellt, das vom Debian-Snapshot-Image zum Kompilieren von Maschinencode bereitgestellt wird.
Die JNI-Arbeitslasten werden in einer gemeinsam genutzten Bibliothek mit dem Namen libtensorflow.so zusammen mit der <service>_application.jar kompiliert.
Bildebenen
Das JNI-TensorFlow-Arbeitslast-Image besteht aus mehreren Ebenen:
- Basisebene des Images
- Java-Basis-Image:
gcr.io/distroless/java17-debian11
- Java-Basis-Image:
- Debian-Paketabhängigkeitsebenen. Die Ebenen werden mithilfe von DEB-Archiven generiert, die von debian-snapshot heruntergeladen und als Image-Ebenen neu verpackt werden.
libc++1-16_amd64.tarlibc++abi1-16_amd64.tarlibc6_amd64.tarlibunwind-16_amd64.tarlibgcc-s1_amd64.targcc-13-base_amd64.tar
- Arbeitslastschicht
binary_tar.tar<service>_application.jarlibtensorflow-jni.solibaggregation-jni.so
Image-Konfiguration
- Labels (nur für Bilder, die für die Ausführung in der TEE erstellt wurden)
"tee.launch_policy.allow_env_override": "FCP_OPTS"- Ermöglicht das Festlegen der Umgebungsvariable
FCP_OPTSim vertraulichen Bereich. Die Arbeitslast verbraucht beim StartFCP_OPTS, um die erforderlichen Parameter zu konfigurieren. - Die Umgebungsvariable
FCP_OPTSwird beim Ausführen des Images (nicht beim Erstellen) festgelegt, um die Deterministik des Builds beizubehalten.
- Ermöglicht das Festlegen der Umgebungsvariable
"tee.launch_policy.log_redirect": "always""tee.launch_policy.monitoring_memory_allow": "always"
- Einstiegspunkt
java -Djava.library.path=. -jar <service>_application.jar
Python-Arbeitslasten
Die rules_python von Bazel werden verwendet, um eine hermetische Python 3.10-Toolchain bereitzustellen. Eine gesperrte pip-Anforderungsdatei wird für das deterministische Abrufen von pip-Abhängigkeiten verwendet. Das Debian-Snapshot-Image sorgt dafür, dass deterministische Distributionen basierend auf der Plattformkompatibilität abgerufen werden, und bietet eine C++-Toolchain zum Kompilieren von Quelldistributionen.
Die Python-Arbeitslasten werden in einer Reihe heruntergeladener Pip-Pakete, einer Python 3.10-Distribution, dem ODP-Python-Quellcode und einem Python-Startskript verpackt.
<service>.runfiles/- Die Python-Distribution wird unter
python_x86_64-unknown-linux-gnu/gespeichert. - Der Quellcode wird unter
com_google_ondevicepersonalization_federatedcompute/gespeichert. - Pip-Pakete werden unter
pypi_<dependency_name>/gespeichert.
- Die Python-Distribution wird unter
<service>.runfiles_manifest- Manifestdatei für das Verzeichnis
<service>.runfiles/
- Manifestdatei für das Verzeichnis
<service>- Python-Skript zum Ausführen des Python-Arbeitslast mit den Runfiles
Bildebenen
Das Python-Arbeitslast-Image besteht aus vier Ebenen:
- Basisebene des Images
- Python-Basis-Image python:slim
- Dolmetscherebene
interpreter_layer.jar<service>/<service>.runfiles/python_x86_64-unknown-linux-gnu/**
- Ebene „Pakete“
packages_layer.jar<service>/<service>.runfiles/**/site-packages/**
- Arbeitslastschicht
app_tar_manifest.tar- Enthält Quellcode, Startskript und Manifest.
<service>/<service>.runfiles_manifest<service>/<service><service>/<service>.runfiles/com_google_ondevicepersonalization_federatedcompute/**
- Enthält Quellcode, Startskript und Manifest.
Image-Konfiguration
- Einstiegspunkt
/<service>/<service>
Bilder erstellen
Nachdem Sie Ihre Arbeitslasten ausgewählt haben, können Sie Ihre Images erstellen und veröffentlichen.
Vorbereitung
Vorgehensweise
Bilder sollten im Docker-Container erstellt werden, der durch das bereitgestellte Dockerfile erstellt wurde. Es gibt zwei Skripts, die beim Erstellen der endgültigen deterministischen Bilder helfen.
- docker_run.sh
- Mit
docker_run.shwird das Docker-Image aus dem Dockerfile erstellt, das Arbeitsverzeichnis und der Docker-Daemon des Hosts werden bereitgestellt und Docker wird mit dem angegebenen Bash-Befehl ausgeführt. Alle Variablen, die vor dem Bash-Befehl übergeben werden, werden als „docker run“-Flags behandelt.
- Mit
- build_images.sh
- Mit
build_images.shwirdbazel buildfür alle Bilder ausgeführt und die generierten Bild-Hashes für jedes erstellte Bild ausgegeben.
- Mit
Alle Bilder erstellen
./scripts/docker/docker_run.sh "./scripts/build_images.sh"
Die erwarteten Image-Hashes für die einzelnen Releases finden Sie unter odp-federatedcompute GitHub-Releases.
Bilder veröffentlichen
Die Veröffentlichung wird mit oci_push-Bazel-Regeln konfiguriert. Das Ziel-Repository sollte für jeden Dienst für Folgendes konfiguriert sein:
- Aggregator
- Datensammler
- model_updater
- task_assignment
- task_management
- task_scheduler
- task_builder
Einzelnes Bild veröffentlichen
So veröffentlichen Sie ein einzelnes Bild:
./scripts/docker/docker_run.sh "bazel run //shuffler/services/<servicename_no_underscore>:<servicename_with_underscore>_image_publish"
Erstellte Bilder
Alle erstellten Bilder müssen vom Ersteller gespeichert und gehostet werden, z. B. in einer GCP Artifact Registry.