设备端个性化联合计算确定性 build

在设备端个性化 (ODP) 可信执行环境 (TEE) 中进行工作负载证明时,需要确定性 build,该环境在 Google Cloud 上以保密空间 (CS) 的形式公开提供。

工作负载映像必须生成确定性的映像哈希,供 CS 用于工作负载证明(使用 NIST 的 RFC 9334 远程证明程序 (RATS) 架构)。

本文档将介绍 odp-federatedcompute 代码库中确定性 build 的实现和支持。ODP 聚合器和模型更新器服务将在 Confidential Space 内运行。该代码库支持我们所有服务的确定性 build,而这对于生产用例是必需的。

确定性 build

确定性 build 包含两个主要组件:

  1. 必需二进制文件的编译。这包括 JAR、共享库和元数据。
  2. 基础映像和运行时依赖项。用于执行已编译二进制文件的运行时环境的基础映像。

目前,ODP Federated Compute 代码库支持以下类型的工作负载:

  • Java + Spring 工作负载
    • TaskAssignment、TaskManagement、Collector
  • Java + Spring 与 JNI tensorflow 工作负载
    • ModelUpdater、Aggregator
  • Python 工作负载
    • TaskBuilder

依赖项

以下是 ODP 为保持确定性和可用性而依赖的依赖项:

  • Bazel
  • GitHub
  • Maven
  • PyPi
  • Debian 快照
  • DockerHub 注册表
  • Google Container Registry (GCR)

确定性工作负载

所有工作负载都使用 Bazel 进行编译,并使用 rules_oci 构建特定于语言的工具链和容器映像。WORKSPACE 文件定义了所有依赖项及其对应的版本和哈希值。

Debian 快照

所有工作负载映像都应在提供的 Dockerfile 中构建,该文件基于 Debian 快照构建。Debian 快照提供了一个稳定的代码库快照,具有确定性:

Java Spring 工作负载

Bazel 的 remotejdk_17 用于提供用于编译的封闭式 Java。其他 Java 依赖项在 WORKSPACE 文件中进行管理和定义。

Java Spring 工作负载会编译为名为 <service>_application.jar 的 jar 文件。该 JAR 包含:

  • Java 类文件
  • META-INF/
    • Bazel 清单数据
  • build-data.properties
    • Bazel build-data
  • BOOT-INF/

图片层

Java Spring 工作负载映像包含两层:

映像配置

  • 入口点
    • java -jar <service>_application.jar

JNI TensorFlow 工作负载

JNI Tensorflow 工作负载基于 Java Spring 工作负载构建。使用 预构建的 Clang+LLVM 16 和 Debian 快照映像提供的 sysroot 来编译机器代码,从而提供 hermetic Clang+LLVM Bazel 工具链。

JNI 工作负载会编译为名为 libtensorflow.so 的共享库以及 <service>_application.jar

图片层

JNI TensorFlow 工作负载映像包含多个层:

  • 基础映像层
  • Debian 软件包依赖项层。这些层是使用从 debian-snapshot 下载并重新打包为映像层的 deb 归档生成的
    • libc++1-16_amd64.tar
    • libc++abi1-16_amd64.tar
    • libc6_amd64.tar
    • libunwind-16_amd64.tar
    • libgcc-s1_amd64.tar
    • gcc-13-base_amd64.tar
  • 工作负载层
    • binary_tar.tar
      • <service>_application.jar
      • libtensorflow-jni.so
      • libaggregation-jni.so

映像配置

  • 标签(仅适用于构建为在 TEE 中运行的映像)
    • "tee.launch_policy.allow_env_override": "FCP_OPTS"
      • 允许在保密空间中设置 FCP_OPTS 环境变量。 工作负载将在启动时消耗 FCP_OPTS 来配置必需的参数。
      • 为了保持构建确定性,FCP_OPTS 环境变量是在运行映像时(而不是在构建映像时)设置的。
    • "tee.launch_policy.log_redirect": "always"
    • "tee.launch_policy.monitoring_memory_allow": "always"
  • 入口点
    • java -Djava.library.path=. -jar <service>_application.jar

Python 工作负载

Bazel 的 rules_python 用于提供密封的 Python 3.10 工具链。锁定的 pip 需求文件用于确定性地提取 pip 依赖项。Debian 快照映像可确保根据平台兼容性提取确定性分发,并提供用于编译源分发的 C++ 工具链。

Python 工作负载将打包到一组下载的 pip 软件包、Python 3.10 分发版、ODP Python 源代码和一个 Python 启动脚本中。

  • <service>.runfiles/
    • Python 分发版存储在 python_x86_64-unknown-linux-gnu/
    • 源代码存储在 com_google_ondevicepersonalization_federatedcompute/
    • Pip 软件包存储在 pypi_<dependency_name>/
  • <service>.runfiles_manifest
    • <service>.runfiles/ 目录的清单文件
  • <service>
    • 使用 runfiles 运行 Python 工作负载的 Python 脚本

图片层

Python 工作负载映像包含四个层:

  • 基础映像层
  • 解释器层
    • interpreter_layer.jar
      • <service>/<service>.runfiles/python_x86_64-unknown-linux-gnu/**
  • 软件包层
    • packages_layer.jar
      • <service>/<service>.runfiles/**/site-packages/**
  • 工作负载层
    • app_tar_manifest.tar
      • 包含源代码、启动脚本和清单。
        • <service>/<service>.runfiles_manifest
        • <service>/<service>
        • <service>/<service>.runfiles/com_google_ondevicepersonalization_federatedcompute/**

映像配置

  • 入口点
    • /<service>/<service>

构建映像

选择工作负载后,您就可以构建并发布映像了。

前提条件

过程

映像应在由提供的 Dockerfile 构建的 Docker 容器内构建。 我们提供了两个脚本,可帮助您构建最终的确定性映像。

  • docker_run.sh
    • docker_run.sh 将根据 Dockerfile 构建 Docker 映像,装载工作目录,装载宿主 Docker 守护进程,并使用提供的 Bash 命令运行 Docker。在 bash 命令之前传递的任何变量都将被视为 docker run 标志。
  • build_images.sh
    • build_images.sh 将针对所有映像运行 bazel build,并输出每个已构建映像的生成映像哈希。

构建所有映像

./scripts/docker/docker_run.sh "./scripts/build_images.sh"

您可以在 odp-federatedcompute GitHub 版本下找到每个版本的预期映像哈希。

发布图片

发布是使用 oci_push Bazel 规则配置的。对于每项服务,目标代码库应配置为:

  • 聚合信息网站
  • 收集器
  • model_updater
  • task_assignment
  • task_management
  • task_scheduler
  • task_builder

发布单张图片

如需发布单张图片,请执行以下操作:

./scripts/docker/docker_run.sh "bazel run //shuffler/services/<servicename_no_underscore>:<servicename_with_underscore>_image_publish"

已构建的映像

所有构建的映像都需要由创建者存储和托管,例如在 GCP Artifact Registry 中。