Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rust

mkSecureArtifact detects a Rust project by a Cargo.toml at the root of src. It builds the crate with rustPlatform.buildRustPackage from a vendored Cargo.lock and hands the result to mkHardenedImage.

The marker

The primary marker is Cargo.toml. A rust-toolchain.toml alongside it is read for the toolchain channel and recorded as the buildConfigFile.

Required and optional ecosystemArgs

  • cargoLock (required) — a vendored relative path to Cargo.lock, written exactly as ./Cargo.lock.
  • outputHashes (optional) — cargoLock.outputHashes for git dependencies. Git deps have no crates.io checksum, so they need an explicit "<crate>-<version>" -> sha256 entry. Omit it entirely when the lock has no git dependencies.

The vendored Cargo.lock / no-IFD rule

This one bites people, so it’s worth stating plainly: cargoLock must be a vendored relative path, never "${src}/Cargo.lock". Reading the lock out of the fetched source is an import-from-derivation — nix flake check --no-build can’t evaluate it, and the repo’s no-ifd-lockfile lint rejects it. The emitter even asserts against a /nix/store/ string sneaking in and throws with a pointer to this rule. Copy Cargo.lock into your repo and reference it relatively.

hb.mkSecureArtifact {
  name = "my-cli";
  version = "0.9.0";
  src = ./.;
  ecosystemArgs = {
    cargoLock = ./Cargo.lock; # vendored — NOT "${src}/Cargo.lock"
    # outputHashes = { "some-git-crate-1.2.3" = "sha256-…"; };
  };
  image.cmd = [ "/bin/my-cli" ];
}

Derivation-first alternative

If your crate needs build inputs, features, or flags the emitter doesn’t take, build it yourself and image it directly:

let
  myCli = pkgs.rustPlatform.buildRustPackage {
    pname = "my-cli";
    version = "0.9.0";
    src = ./.;
    cargoLock.lockFile = ./Cargo.lock; # still vendored, still relative
    buildInputs = [ pkgs.openssl ];
    nativeBuildInputs = [ pkgs.pkg-config ];
  };
in
hb.mkHardenedImage {
  name = "my-cli";
  version = "0.9.0";
  package = myCli;
  cmd = [ "/bin/my-cli" ];
}

FIPS composition (aws-lc-rs, ADR-0028)

Rust’s FIPS path is aws-lc-rs in FIPS mode (ADR-0028), not a flag you flip on an ordinary build. To ship a FIPS Rust artifact you build the crate under the FIPS package set — which composes the aws-lc-rs FIPS module — and only then pass fips = true so the image carries truthful FIPS labels. As everywhere, fips = true is a truthfulness contract: it labels; it does not convert a non-FIPS build. See FIPS.

SBOM

Rust crates are folded into the CycloneDX SBOM automatically — the SBOM builder reads the Cargo.lock inside the vendored cargoDeps on the finished derivation, so no extra configuration is needed. See SBOMs.