ADR-0001

Stack backend : Rust + Axum

source : docs/adr/0001-backend-stack.md · versionné · MADR-lite

ADR-0001 — Stack backend : Rust + Axum

  • Statut : Accepted
  • Date : 2026-04-24
  • Décideurs : Core team OmbrysWeb
  • Issue GitHub : #1
  • Références cahier des charges : § 5.2

Contexte

OmbrysWeb doit exposer plusieurs micro-services (auth, blog, messaging, storage, audit, vault-proxy, admin) manipulant :

  • du trafic non authentifié à fort volume (blog public),
  • de la cryptographie sensible (WebAuthn, dérivations, liboqs),
  • des données utilisateur jamais lisibles en clair par le serveur (§ 5.3 Zero-Knowledge),
  • une communication interne mTLS/gRPC avec rotation de certificats courts.

Le modèle de menace (§ 1.3) liste explicitement comme vecteurs critiques :

  • corruption mémoire (buffer overflow, UAF, double-free) → classe de CVE historique dominante,
  • défaut d'isolation entre workloads ou entre requêtes,
  • chaîne d'approvisionnement (supply chain) compromise.

Le choix du langage backend et de son framework web structure toute la suite (CI, observabilité, format binaire, empreinte mémoire des conteneurs distroless § 5.7).

Options considérées

Option A — Rust + Axum (retenue)

  • Langage memory-safe par design (sauf unsafe explicite, interdit sauf bindings FFI documentés).
  • Écosystème async mature via Tokio (dont Axum est issu).
  • Axum : framework maintenu par le core Tokio, API fondée sur tower (middlewares composables), intégration native hyper / rustls.
  • Bindings FFI clairs pour liboqs (Kyber/Dilithium) et ring / RustCrypto.
  • Binaires statiques compatibles scratch / distroless (< 30 MB typique).
  • Outillage : cargo-audit, cargo-deny, cargo-fuzz, miri (UB detection), cargo-llvm-cov.

Option B — Go + Chi / Echo

  • Memory-safe (GC), concurrence goroutines simple, compile-time rapide.
  • Écosystème crypto solide (crypto/*, golang.org/x/crypto).
  • Bindings CGO pour liboqs fonctionnels mais augmentent la surface d'attaque (CGO désactive certaines protections du runtime Go, et complique les builds reproductibles statiques).
  • Perf très correctes mais overhead GC mesurable sur charges crypto lourdes et latences tail.
  • Moins de garanties statiques (typage moins strict, absence d'ADT/sum types ergonomique).

Option C — Node.js / TypeScript (Fastify, Hono)

  • Partage de code potentiel avec le frontend TS.
  • Not memory-safe pour les natifs (fuites courantes via modules C++).
  • Performances et empreinte mémoire défavorables sur un parc de 7 services.
  • Écosystème npm = surface supply chain extrêmement large → incompatible avec le durcissement visé (§ 5.5).
  • Rejeté pour tout code backend. Reste acceptable côté frontend uniquement (via Next.js, § 5.1).

Option D — Zig / C / C++

  • Performances maximales possibles.
  • Non memory-safe → incompatible avec l'objectif d'élimination de la classe CWE-119 et apparentées.
  • Rejeté.

Option E — Rust + Actix-web

  • Même socle langage que l'option A.
  • Actix-web historiquement plus performant sur benchmarks synthétiques, mais :
  • base actor (actix) non indispensable,
  • historique de unsafe mieux maîtrisé désormais mais plus dense qu'Axum,
  • ergonomie middleware et extraction un cran en dessous de tower.
  • Conservé en plan B si un service a des besoins spécifiques (ex : WebSocket très haute charge).

Décision

Rust stable comme langage backend unique pour tous les micro-services (auth-svc, blog-svc, messaging-svc, storage-svc, audit-svc, vault-svc, admin-svc).

Axum (dernière stable, piste axum = "0.7" ou supérieure selon l'état à M1) comme framework HTTP par défaut. Tonic pour gRPC interne (mTLS, même écosystème Tokio).

Contraintes :

  • #![forbid(unsafe_code)] au niveau crate pour tout code applicatif.
  • unsafe autorisé uniquement dans des crates dédiées FFI clairement nommées (ombrys-liboqs-sys, etc.), revues ligne à ligne.
  • Rust stable pin (ex : rust-toolchain.toml versionné) ; bump manuel après validation CI.
  • cargo-deny configuré (licences autorisées, bans, advisories RustSec bloquantes).
  • cargo-audit en CI bloquant sur critical et high.
  • cargo-fuzz sur parsers et handlers sensibles (WebAuthn, désérialisation, gRPC).
  • Builds reproductibles : --locked, SOURCE_DATE_EPOCH fixé, toolchain pinnée (§ 5.7.1).

Conséquences

Positives

  • Élimine par construction la classe dominante de CVE (§ 1.3, ~70 % des CVE mémoire éliminées).
  • Binaires statiques compatibles distroless/scratch → images < 50 MB par service (objectif § 5.7.1 atteint).
  • Outillage sécurité (fuzz, audit, deny, miri) natif et mûr.
  • Axum/Tonic/hyper = même runtime Tokio sur tous les services → cohérence opérationnelle et modèle mental unique.
  • Compatible objectif SLSA niveau 3 (§ 5.5) et builds reproductibles.

Négatives

  • Courbe d'apprentissage Rust plus raide que Go ou TS → onboarding contributeurs rallongé. Mitigation : pairing, revues appuyées en M1-M2, templates de micro-service.
  • Temps de compilation plus long. Mitigation : sccache, cache mount Docker, workspace partagé.
  • Écosystème crypto post-quantique (liboqs) encore jeune côté bindings Rust. Mitigation : crate FFI interne auditée, pas de dépendance directe sur un wrapper tiers non maintenu.
  • Certains intégrateurs (SSO, SDK tiers) peuvent n'avoir de SDK qu'en Go ou Node. Mitigation : wrappers HTTP/gRPC isolés si nécessaire, jamais dans le chemin critique d'auth ou de crypto.

Neutres

  • Observabilité : tracing + opentelemetry-rust couvrent les besoins, alignés sur Loki/Grafana (§ 5.5).
  • Testing : cargo test + insta (snapshots) + criterion (bench) + proptest couvrent le besoin.

Suivi

  • Les ADR qui en dépendent directement : ADR-0002 (crypto, usage des crates RustCrypto), ADR-0003 (ZK, modèle de stockage), et toute ADR future concernant runtime, DB driver, observability.
  • Une ADR de révision pourra être produite si :
  • un service a un besoin où Axum est démontré insuffisant → option Actix-web locale avec justification ;
  • l'état de l'écosystème PQ évolue (ex : Dilithium/Kyber inclus dans ring upstream) → simplification possible des FFI.

Changelog

  • 2026-04-24 : rédaction initiale, statut Accepted.