Aller au contenu

Fondamentaux des miroirs de paquets

Les ecosystemes de paquets

Chaque langage, chaque OS, chaque plateforme possède son propre système de distribution de paquets. Un miroir interne doit supporter les ecosystemes utilises dans l'entreprise.

Paquets système

Ecosysteme Format Registre public Outils clients
Debian .deb archive.ubuntu.com apt, dpkg
RHEL .rpm mirrorlist.centos.org yum, dnf, rpm
Alpine .apk dl-cdn.alpinelinux.org apk

Les dépôts système sont composes de fichiers binaires et de metadonnees (Packages.gz pour apt, repodata/repomd.xml pour yum). Un miroir doit repliquer ces metadonnees pour que les clients retrouvent la même arborescence qu'en amont.

Paquets applicatifs

Ecosysteme Format Registre public Outils clients
npm tarball .tgz registry.npmjs.org npm, yarn, pnpm
PyPI wheel, sdist pypi.org pip, poetry, uv
Maven .jar, .pom repo.maven.apache.org mvn, gradle
Go module zip + info proxy.golang.org go mod
NuGet .nupkg api.nuget.org dotnet, nuget
RubyGems .gem rubygems.org gem, bundle

Artefacts d'infrastructure

Ecosysteme Format Registre public Outils clients
Docker/OCI Layers OCI, manifests registry-1.docker.io docker, podman
Helm .tgz (chart archive) artifacthub.io helm
Terraform Provider binaires registry.terraform.io terraform, tofu

Modèles de dépôts

Un gestionnaire de dépôts organise les artefacts en trois types fondamentaux : proxy, hosted et group.

Dépôt proxy (cache-through)

Le dépôt proxy fait office de cache transparent devant un registre distant. Lorsqu'un client demande un paquet :

graph LR
    Client -->|requete| Proxy["Depot Proxy"]
    Proxy -->|cache miss| Public["Registre public"]
    Proxy --> Check{"cache hit ?"}
    Check -->|oui| Local["reponse locale"]
    Check -->|non| Download["telechargement,<br/>stockage, reponse"]

Comportement :

  1. Le client interroge le proxy comme s'il etait le registre officiel
  2. Si le paquet est en cache local, réponse immédiate
  3. Sinon, le proxy telecharge depuis l'upstream, le stocke, puis répond au client
  4. Les requêtes suivantes sont servies depuis le cache

Avantages : aucune configuration prealable des paquets a cacher, disponibilité en cas de panne upstream (pour les paquets déjà caches), deduplication des telechargements.

Dépôt hosted (paquets internes)

Le dépôt hosted stocke les artefacts produits en interne : bibliotheques privées, images Docker applicatives, packages npm internes. Aucun upstream n'est configuré.

graph LR
    CICD["CI/CD Pipeline"] -->|push| Hosted["Depot Hosted"]
    Autre["Autre projet"] -->|pull| Hosted

Cas d'usage :

  • Bibliotheques internes partagees entre équipes
  • Artefacts de build (.jar, .whl, images Docker)
  • Packages forks de projets open source avec correctifs internes

Dépôt group (agregation)

Le dépôt group expose un point d'entree unique qui agrege plusieurs dépôts (proxy et hosted) :

graph TD
    Client -->|requete| Group["Depot Group"]
    Group --> Hosted["Depot Hosted<br/>(interne)"]
    Group --> Proxy1["Depot Proxy 1<br/>(registre A)"]
    Group --> Proxy2["Depot Proxy 2<br/>(registre B)"]

Le group résout les paquets dans l'ordre de priorité defini :

  1. Chercher dans le dépôt hosted (paquets internes d'abord)
  2. Chercher dans le premier proxy
  3. Chercher dans le deuxieme proxy

Priorité au hosted pour prevenir la dependency confusion

Toujours placer le dépôt hosted en premier dans l'ordre de résolution du group. Cela empeche un paquet malveillant public de même nom qu'un paquet interne de prendre le dessus.


Stratégies de caching

Cache complet vs cache a la demande

Stratégie Description Stockage requis Cas d'usage
Cache a la demande Seuls les paquets demandes sont telecharges Faible Approche par defaut (proxy)
Miroir complet Réplication integrale du registre upstream Tres eleve Environnement air-gapped
Prefetch selectif Telechargement anticipe des paquets critiques Moyen Garantir la disponibilité offline

Politique d'expiration

Les caches doivent gérer la fraicheur des metadonnees et des artefacts :

# Exemple de politique de cache Nexus
proxy:
  remote_url: https://registry.npmjs.org
  content_max_age: 1440      # Artefacts : verifier toutes les 24h
  metadata_max_age: 1440     # Metadonnees : verifier toutes les 24h
  negative_cache:
    enabled: true
    ttl: 15                  # Paquets introuvables : re-essayer apres 15 min

Negative cache

Le negative cache evite de bombarder l'upstream pour des paquets inexistants, mais il peut retarder la disponibilité d'un paquet nouvellement publie. Un TTL de 15 minutes est un bon compromis.


SBOM et provenance

Software Bill of Materials

Un SBOM est un inventaire complet des composants logiciels d'un projet. Les miroirs internes facilitent la génération de SBOM car ils centralisent l'ensemble des paquets consommes.

Format SBOM Standard Outils de génération
SPDX ISO 5962 syft, trivy, scancode
CycloneDX OWASP cdxgen, trivy, syft

Provenance et attestation

Les ecosystemes modernes ajoutent des mécanismes de provenance :

Ecosysteme Mécanisme de provenance Vérification
npm Provenance statements (Sigstore) npm audit signatures
PyPI Attestations PEP 740 Vérification via Sigstore
Docker Cosign signatures, SLSA provenance cosign verify, slsa-verifier
Go go.sum (hash de chaque module) Vérification automatique par go mod
Maven Signatures PGP des artefacts Vérification par Gradle/Maven

Menaces sur la chaîne d'approvisionnement

Typosquatting

Un attaquant publie un paquet au nom proche d'un paquet populaire. L'utilisateur qui fait une faute de frappe installe le paquet malveillant.

Paquet legitime Paquet malveillant (exemple)
requests requets, request
lodash 1odash, lodash-utils
colors co1ors, colour

Mitigation : le miroir interne peut maintenir une liste blanche de paquets autorises, ou scanner automatiquement les nouvelles entrees.

Dependency confusion

Un attaquant publie sur le registre public un paquet portant le même nom qu'un paquet interne, avec un numero de version supérieur. Le gestionnaire de paquets résout vers la version publique.

Registre public :  @company/utils  v99.0.0   ← malveillant
Registre interne : @company/utils  v1.2.3    ← legitime

pip install @company/utils
→ Resout vers v99.0.0 (publique) si le registre public est interroge en premier

Mitigation :

  1. Dépôt group avec hosted en priorité
  2. Utiliser des namespaces/scopes (@company/ pour npm)
  3. Bloquer la résolution de noms internes sur les dépôts proxy

Mainteneur compromis

Un compte de mainteneur est compromis (credentials voles, social engineering) et une version malveillante est publiee sous le nom legitime du paquet.

Incident Paquet Impact
event-stream 2018 event-stream Vol de cryptomonnaies
ua-parser-js 2021 ua-parser-js Cryptomining + vol
colors.js 2022 colors Sabotage volontaire
xz-utils 2024 xz Backdoor SSH (liblzma)

Mitigation : delai de propagation configurable dans le proxy (ne pas servir immédiatement les nouvelles versions), scanning automatique, pinning des versions.


Vérification des signatures et content trust

Docker Content Trust (DCT)

# Activer la verification des signatures Docker
export DOCKER_CONTENT_TRUST=1

# Signer une image lors du push
docker push registry.internal:5000/app:v1.0.0
# Notary verifie la signature au pull
docker pull registry.internal:5000/app:v1.0.0

Cosign (Sigstore)

# Signer une image OCI
cosign sign --key cosign.key registry.internal:5000/app:v1.0.0

# Verifier la signature
cosign verify --key cosign.pub registry.internal:5000/app:v1.0.0

Vérification GPG pour les dépôts apt/rpm

# Importer la cle GPG du depot
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABCDEF1234567890

# Verifier la signature du fichier Release
gpg --verify Release.gpg Release

Le miroir doit preserver les signatures

Un miroir interne doit relayer les signatures et les metadonnees de provenance sans les altérer. Si le miroir re-signe les paquets, cela casse la chaîne de confiance et empeche les clients de vérifier l'authenticite aupres de la source originale.