Skip to content

key-provider-build: pin transitive deps for reproducible mr_enclave#672

Open
barakeinav1 wants to merge 1 commit intoDstack-TEE:masterfrom
barakeinav1:reproducible-key-provider-build
Open

key-provider-build: pin transitive deps for reproducible mr_enclave#672
barakeinav1 wants to merge 1 commit intoDstack-TEE:masterfrom
barakeinav1:reproducible-key-provider-build

Conversation

@barakeinav1
Copy link
Copy Markdown
Contributor

@barakeinav1 barakeinav1 commented May 10, 2026

Why

Two independent builds of Dockerfile.key-provider from the same commit weeks apart produced different mr_enclave values, traced to an unpinned libcurl3-gnutls apt update. The current Dockerfile pins gramine, git, build-essential, Rust major-minor, and the upstream source commit, but transitive apt deps, the Rust patch version, and the rustup-init script can all drift between builds.

What

Parameterize and pin three drift channels via build-args, plumbed through docker-compose.yaml so they're overridable as env vars (no file edits needed):

Build-arg / env Default Status
APT_SNAPSHOT 20260423T000000Z Empirical — observed libcurl3-gnutls shifting …ubuntu1.23 → …ubuntu1.24 produced a different mr_enclave
RUST_TOOLCHAIN 1.85.1 Defensive1.85 resolves to whatever 1.85.x is current at install time
RUSTUP_VERSION + RUSTUP_INIT_SHA256 1.28.2 / 20a06e64… Defensive — replaces live curl https://sh.rustup.rs | sh

Only APT_SNAPSHOT has demonstrated drift today; the other two are forward-looking pins (universally correct, no per-consumer choice baked in).

To override any of these at build time, set the env var(s) before invoking ./run.sh, e.g. APT_SNAPSHOT=20260501T000000Z RUST_TOOLCHAIN=1.86.0 ./run.sh.

The defaults reproduce a known-canonical build but are intentionally unopinionated — feel free to bump them. Each downstream consumer that pins to a specific mr_enclave overrides via env vars at build time.

Verified

  • Two clean builds with the same args produce byte-identical enclaves (deterministic).
  • The docker-compose build path with an env-var override works end-to-end:
    APT_SNAPSHOT=20260423T000000Z ./run.sh
    
  • For one example downstream consumer (NEAR's MPC TDX deployment), the default APT_SNAPSHOT reproduces their pinned mr_enclave = 6b5ed02e…. Other consumers with different canonical dates can override.

Notes for maintainers

  • Three values can be bumped trivially. They're ARG lines at the top of each Dockerfile section, also overridable via env vars or --build-arg.
  • If you bump RUSTUP_VERSION, the matching RUSTUP_INIT_SHA256 is published at:
    https://static.rust-lang.org/rustup/archive/<VERSION>/x86_64-unknown-linux-gnu/rustup-init.sha256
    
  • Builds now require snapshot.ubuntu.com to be reachable. If that's a problem for any consumer's network, they fork and override APT_SNAPSHOT to point at a private mirror via the same env-var mechanism.

Out of scope

  • Adding a key-provider-build/README.md documenting the env-var knobs (no README exists today; happy to add as a follow-up if useful).
  • Pinning MoeMahhouk/gramine-sealing-key-provider to a maintainer-controlled mirror (e.g. under Dstack-TEE/, Phala-Network/, or a fork) so a future force-push or repo deletion can't break builds. Currently git clone of an upstream commit hash.

@barakeinav1 barakeinav1 force-pushed the reproducible-key-provider-build branch 2 times, most recently from 64012c6 to 34aa8ac Compare May 10, 2026 16:01
The upstream Dockerfile pins gramine (by digest), git, build-essential,
Rust major-minor, and the upstream key-provider source commit. It does
not pin transitive apt deps, the Rust patch version, or the rustup-init
installer script. Each is a drift channel that silently changes the
bytes hashed into the Gramine manifest's trusted_files list, which
changes mr_enclave — breaking any attestation flow that pins to a
specific expected value.

In practice, builds done weeks apart on the same Dockerfile already
diverge today: a rebuild produced 98f735d1… instead of the expected
6b5ed02e… because Ubuntu shipped a libcurl3-gnutls security update
between the two build dates (7.81.0-1ubuntu1.23 → 1ubuntu1.24).

This change parameterizes and pins all three drift channels:

1. APT_SNAPSHOT build-arg routes apt at https://snapshot.ubuntu.com/
   so all transitive deps resolve to whatever Ubuntu had on the named
   date. Default = 20260423T000000Z. Each consumer overrides to match
   their expected mr_enclave:

       docker build --build-arg APT_SNAPSHOT=YYYYMMDDT000000Z ...

2. RUST_TOOLCHAIN build-arg with default 1.85.1 (was --default-toolchain
   1.85, which resolves to whatever 1.85.x is current at install time).

3. RUSTUP_VERSION + RUSTUP_INIT_SHA256 build-args replace the live
   `curl https://sh.rustup.rs | sh` invocation with a pinned download
   from static.rust-lang.org's archive, verified against a sha256.

Verified: with APT_SNAPSHOT=20260423T000000Z, the build reproduces the
canonical mr_enclave 6b5ed02e549a1c30aaa8e3171a045f1f449b0017353ef595e78e39c348c98d01
that consumers (e.g. NEAR's MPC TDX nodes) currently expect.
@barakeinav1 barakeinav1 force-pushed the reproducible-key-provider-build branch from 34aa8ac to 864a988 Compare May 10, 2026 16:15
@barakeinav1 barakeinav1 marked this pull request as ready for review May 10, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant