Software-Lieferkette unter Kontrolle: The Rust Way

Software-Lieferkette unter Kontrolle: The Rust Way
By Matthias Petermann / on 26.10.2025

Einführung

Digitale Souveränität ist kein politischer Slogan, sondern eine technische Notwendigkeit. Wer Software entwickelt, hängt an einer langen Kette von Abhängigkeiten – Compiler, Bibliotheken, Build-Tools, Cloud-Services, Artefakt-Repos. Die Lieferkette (Software Supply Chain) ist das Rückgrat moderner Entwicklung – und zugleich ihr größter Unsicherheitsfaktor.

Warum Lieferkettenkontrolle wichtig ist

Jede Abhängigkeit ist ein potenzieller Einfallspunkt. Ein kompromittiertes Paket, ein fehlerhafter Mirror oder ein proprietärer Build-Schritt kann unbemerkt das Fundament ganzer Systeme verändern. Wer nicht weiß, woher sein Code stammt und wie er gebaut wurde, hat keine echte Kontrolle über das eigene Produkt.

Wenn die Lieferkette fremdbestimmt ist

Fehlt Transparenz, übernehmen andere die Kontrolle:

  • Der Build bricht, wenn das CI-System offline ist.
  • Eine Dependency verschwindet aus dem Registry-Index.
  • Lizenzbedingungen ändern sich, ohne dass man es merkt.
  • Cloud-Dienste diktieren Update-Zyklen und Build-Pfade.

So entsteht ein Netz aus Unsicherheiten – technisch, rechtlich, organisatorisch.

Risiken und ihre Folgen

Für Anwenderinnen und Anwender bedeutet das:

  • Verlust von Vertrauen: Kann ich diesem Update trauen?
  • Abhängigkeit von Dritten: Wer kontrolliert meine Werkzeuge?
  • Sicherheitslücken in der Lieferkette: Exploits in Upstream-Paketen.

Kurz: Ohne souveräne Lieferkette gibt es keine souveräne Software.


Exkurs: Warum Rust?

In den letzten Jahren habe ich mit verschiedenen Toolchains gearbeitet – von CMake und Maven bis Go und Rust. Gerade im Vergleich fällt auf, dass Rust das Thema Unabhängigkeit auf einer sehr praktischen Ebene ernst nimmt.

  • Offene Struktur statt Konzernbindung: Die Rust Foundation ist gemeinnützig organisiert. Niemand kann die Sprache oder ihre Werkzeuge monopolisieren – ein wichtiger Punkt, wenn es um Vertrauen und langfristige Stabilität geht.

  • Konsistente, ausgereifte Toolchain: Vom Compiler über den Paketmanager (Cargo) bis hin zu Test-, Linter- und Dokumentationswerkzeugen kommt alles aus einer Hand und ist offen nachvollziehbar. Dadurch entfällt die übliche Fragmentierung, die man aus vielen anderen Ökosystemen kennt.

  • Reproduzierbare Builds als Prinzip: Cargo kompiliert alle Abhängigkeiten aus Quelltexten, kann sie lokal spiegeln und vollständig offline bauen. Diese Architektur lädt förmlich dazu ein, reproduzierbare, auditierbare Build-Prozesse zu gestalten – ohne auf zentrale Dienste angewiesen zu sein.

  • Breite Plattformunterstützung: Ob Linux, macOS, Windows, Embedded oder WebAssembly – die Toolchain verhält sich auf allen Plattformen gleich und lässt sich sauber versionieren.

Rust steht damit weniger für eine bestimmte Programmiersprache als für ein ökosystemisches Design, das Unabhängigkeit technisch ermöglicht und organisatorisch unterstützt. Es zeigt, dass „digitale Souveränität“ kein abstrakter Begriff ist, sondern im Werkzeugkasten beginnt.


Beispiel: Eine minimale REST-API mit Rust

Software-Souveränität zeigt sich nicht in Schlagworten, sondern in der technischen Umsetzung. Ein einfaches Beispiel ist eine kleine REST-API, die zeigt, wie Rust Abhängigkeiten strukturiert, baut und überprüfbar hält.

Projektdatei: Cargo.toml

[package]
name = "tiny-rest"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
axum = "0.7"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

Programmdatei: src/main.rs

use axum::{routing::post, extract::Json, response::Json as JsonResponse, Router};
use serde::{Deserialize, Serialize};
use tokio::net::TcpListener;

#[derive(Deserialize, Serialize)]
struct Message { text: String }

#[tokio::main]
async fn main() {
    let app = Router::new().route("/echo", post(echo));
    let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
    println!("Listening on http://localhost:3000");
    axum::serve(listener, app).await.unwrap();
}

async fn echo(Json(payload): Json<Message>) -> JsonResponse<Message> {
    JsonResponse(payload)
}

Interessant ist dabei weniger der Code selbst, sondern der Build-Prozess: Rust kompiliert immer aus Quelltexten – jede Abhängigkeit wird durch das Build-Tool cargo lokal gebaut, mit demselben Compiler, unter denselben Bedingungen. Damit bleibt der Prozess transparent und nachvollziehbar:

cargo build

Allerdings: Solange Cargo seine Abhängigkeiten direkt aus dem Internet lädt, ist der Build noch nicht vollständig deterministisch. Netzwerkverfügbarkeit, Upstream-Änderungen oder entfernte Pakete können das Ergebnis verändern.

Erst durch Vendoring und das Einfrieren der Abhängigkeiten wird der Build wirklich reproduzierbar und offline nachvollziehbar.


Von Online-Builds zur echten Unabhängigkeit

Beim ersten cargo build lädt Cargo alle externen Abhängigkeiten aus crates.io, der öffentlichen Rust-Paketquelle. Das ist bequem – aber genau hier liegt eine kritische Abhängigkeit.

Solange der Buildprozess auf Netzwerkzugriff und externe Quellen angewiesen ist, bleibt die Lieferkette verwundbar:

  • Wenn crates.io offline ist, steht der Build.
  • Wenn ein Maintainer ein Paket ändert oder entfernt, ändert sich das Ergebnis.
  • In abgeschotteten Umgebungen (z. B. Behörden oder Industrieanlagen) kann der Build gar nicht mehr laufen.

Mit Vendoring – also dem lokalen Spiegeln aller Dependencies – wird der Prozess dagegen selbsttragend, reproduzierbar und auditierbar. Damit entsteht eine Form von digitaler Souveränität: nachvollziehbar, wiederholbar, unabhängig.


Kontrolle über die Lieferkette: Vendoring

Die Stärke von Rust zeigt sich, wenn man die gesamte Lieferkette lokalisiert. Mit cargo vendor lassen sich alle Abhängigkeiten in einen lokalen Ordner (vendor/) spiegeln:

cargo vendor

Danach reicht eine kleine Konfiguration:

# .cargo/config.toml
[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"

Ab dann bezieht Cargo alle Dependencies ausschließlich lokal. Der Build funktioniert sogar komplett offline:

cargo build --offline

Kein externer Zugriff, keine unbemerkten Änderungen, keine Build-Instabilitäten.


Vergleich: Rust vs. Java (Maven & Gradle)

Im Java-Ökosystem mit Maven oder Gradle sieht es auf den ersten Blick ähnlich aus – Dependencies werden aus zentralen Repositories geladen. Der Unterschied liegt in der Art der Artefakte:

  • Maven & Gradle laden fertig kompilierte JARs.
  • Cargo lädt Quellcode und baut ihn lokal neu.

Dadurch steht Rust auf einer anderen Vertrauensebene. Ein Rust-Projekt kann seine gesamte Toolchain, alle Crates und Abhängigkeiten aus Quelltexten reproduzieren. Jede Build-Entscheidung bleibt nachvollziehbar.

Bei Maven bleibt vieles eine Blackbox:

  • JARs sind vorkompiliert und oft nicht deterministisch.
  • Metadaten lassen sich prüfen, aber nicht vollständig reproduzieren.
  • Unterschiedliche JVMs und Plugins führen leicht zu abweichenden Ergebnissen.

Rusts Philosophie – „Vendor Everything“ – dreht das Prinzip um:

Statt Binärartefakte herunterzuladen, entsteht ein überprüfbarer Build aus lokalem Quellcode.

Das macht den Prozess nicht nur technisch sauberer, sondern auch auditierbar.

Kurz: 👉 Java lädt fertige Pakete. 👉 Rust baut alles selbst.


Weiterführende Gedanken

Vendor-Sources versionieren

Wer langfristige Nachvollziehbarkeit möchte, kann das vendor/-Verzeichnis mitsamt Checksums im Git-Repo mitführen. So lässt sich der exakte Zustand des Ökosystems einfrieren und später reproduzieren.

Lizenz-Transparenz im Offline-Modus

Tools wie cargo-license oder cargo-about listen auch offline alle Lizenzen der Abhängigkeiten auf – eine überprüfbare Software Bill of Materials (SBOM) inklusive Lizenzlage.

Archivieren für Langzeitstabilität

Für sicherheitskritische oder industrielle Umgebungen kann der komplette Build-Stack archiviert werden – inklusive Compiler-Version, Toolchain und Cargo-Index. Damit wird Software nicht nur reproduzierbar, sondern auch auditierbar.


Fazit: Das Rust-Ökosystem zeigt, wie sich offene Infrastruktur, integriertes Tooling, formale Sicherheit und praktische Kontrolle verbinden lassen.


Bildnachweis: Das Rust-Logo ist eine eingetragene Marke der Rust Foundation. Verwendung im Rahmen redaktioneller Berichterstattung gemäß den Markenrichtlinien der Rust Foundation.