Nexus Repository Manager

Concepts : gestionnaire de depots

Un gestionnaire de depots (repository manager) centralise le stockage et la distribution de tous les artefacts logiciels d'une organisation : packages RPM, images Docker, modules npm, packages Python, etc.

Pourquoi miroir les packages en local ?

Avantage Explication
Air-gap L'infrastructure fonctionne meme sans Internet
Performance Les packages sont telecharges une seule fois, puis servis localement a debit LAN
Fiabilite Pas de dependance aux CDN externes (pannes, rate-limiting)
Securite Point de controle unique pour auditer les packages entrants
Reproductibilite Les versions des packages sont figees dans le cache local

Types de repositories dans Nexus

Nexus propose trois types de repositories :

graph LR
    subgraph NEXUS["Nexus Repository Manager"]
        PROXY["Proxy<br/>(miroir upstream)"]
        HOSTED["Hosted<br/>(artefacts internes)"]
        GROUP["Group<br/>(agregation)"]
        PROXY --> GROUP
        HOSTED --> GROUP
    end

    UPSTREAM["Upstream<br/>(dl.rockylinux.org,<br/>pypi.org, etc.)"] -->|"Cache on first request"| PROXY
    CLIENT["Client<br/>(yum, docker, pip)"] -->|"Single URL"| GROUP

    style GROUP fill:#27ae60,color:#fff
    style PROXY fill:#3498db,color:#fff
    style HOSTED fill:#e67e22,color:#fff
Type Role Exemple
Proxy Miroir d'un depot distant. Telecharge depuis l'upstream au premier acces, puis sert depuis le cache rocky-baseosdl.rockylinux.org
Hosted Stocke des artefacts crees en interne (pas d'upstream) Packages RPM internes, images Docker custom
Group Combine plusieurs proxy et/ou hosted sous une seule URL rpm-all regroupe tous les proxies YUM

Fonctionnement du cache proxy

Quand un client demande un package pour la premiere fois, Nexus le telecharge depuis l'upstream (via le proxy Squid + Fortigate), le stocke dans son cache local, puis le sert au client. Les requetes suivantes pour le meme package sont servies directement depuis le cache, sans aucun acces Internet.


Architecture Nexus

Parametre Valeur
Nom VM INF-PDEV40B
Adresse IP 10.15.100.65 (VLAN 106 -- Services)
Ressources 2 vCPU, 8 Go RAM
URL https://repo.infra.indio (port 443)
Version Nexus OSS (Sonatype Nexus Repository Manager)
TLS Certificat emis par Vault PKI Intermediate CA
Proxy sortant http://10.15.50.3:3128 (Squid VIP)
Systeme Rocky Linux 9.6
graph TB
    subgraph INFRA["Infrastructure interne"]
        VM1["VMs Rocky<br/>(yum)"]
        VM2["VMs Docker<br/>(docker pull)"]
        VM3["VMs Dev<br/>(npm, pip)"]
    end

    subgraph NEXUS["Nexus — repo.infra.indio:443"]
        RPM["rpm-all<br/>(group)"]
        DOCKER["docker-all<br/>(group)"]
        NPM["npm-all<br/>(group)"]
        PYPI["pypi-all<br/>(group)"]
    end

    subgraph EXTERNAL["Internet (via Squid + FGT)"]
        UPS1["dl.rockylinux.org"]
        UPS2["registry-1.docker.io"]
        UPS3["registry.npmjs.org"]
        UPS4["pypi.org"]
    end

    VM1 -->|"HTTPS"| RPM
    VM2 -->|"HTTPS"| DOCKER
    VM3 -->|"HTTPS"| NPM
    VM3 -->|"HTTPS"| PYPI

    RPM -.->|"Cache miss"| UPS1
    DOCKER -.->|"Cache miss"| UPS2
    NPM -.->|"Cache miss"| UPS3
    PYPI -.->|"Cache miss"| UPS4

    style NEXUS fill:#27ae60,color:#fff

Repositories group (points d'acces clients)

Les clients n'utilisent que les URLs des groups. Chaque group agregue un ou plusieurs repositories proxy (et eventuellement hosted) :

Type Group URL complete Contenu
RPM/YUM rpm-all https://repo.infra.indio/repository/rpm-all/ Tous les proxies YUM ci-dessous
Docker docker-all https://repo.infra.indio/repository/docker-all/ Docker Hub, GHCR, Quay (proxies)
npm npm-all https://repo.infra.indio/repository/npm-all/ npmjs.org (proxy)
PyPI pypi-all https://repo.infra.indio/repository/pypi-all/ pypi.org (proxy)

Proxies YUM configures

Chaque repository proxy est configure avec l'URL upstream correspondante. Nexus telecharge et met en cache les packages automatiquement au premier acces.

Repository proxy URL upstream Contenu
rocky-baseos https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os/ Packages de base Rocky Linux 9
rocky-appstream https://dl.rockylinux.org/pub/rocky/9/AppStream/x86_64/os/ Packages applicatifs Rocky 9
epel-9 https://download.fedoraproject.org/pub/epel/9/Everything/x86_64/ Extra Packages for Enterprise Linux 9
elastic-8 https://artifacts.elastic.co/packages/8.x/yum/ Elasticsearch, Kibana, Logstash 8.x
wazuh-4 https://packages.wazuh.com/4.x/yum/ Wazuh Manager, agents, Wazuh Indexer
docker-ce https://download.docker.com/linux/centos/9/x86_64/stable/ Docker Community Edition
gitlab-ce https://packages.gitlab.com/gitlab/gitlab-ce/el/9/x86_64/ GitLab Community Edition
zabbix-7 https://repo.zabbix.com/zabbix/7.0/rhel/9/x86_64/ Zabbix Server, agents, frontend
hashicorp https://rpm.releases.hashicorp.com/RHEL/9/x86_64/stable/ Vault, Terraform, Packer

Pas de GPG check sur les proxies

Nexus ne verifie pas les signatures GPG en interne. C'est le client yum/dnf qui effectue la verification GPG cote VM avec gpgcheck=1. La chaine de confiance est maintenue de bout en bout.


Configuration des clients via Ansible

Le role Ansible common deploie automatiquement les fichiers de configuration YUM sur toutes les VMs pour pointer vers Nexus :

# /etc/yum.repos.d/nexus-rocky-baseos.repo
[nexus-rocky-baseos]
name=Rocky Linux 9 - BaseOS (Nexus)
baseurl=https://repo.infra.indio/repository/rocky-baseos/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
Directive Role
baseurl Pointe vers le repository Nexus (pas l'upstream)
gpgcheck=1 Verification de la signature GPG des packages
sslverify=1 Verification du certificat TLS de Nexus
sslcacert Chemin vers le bundle CA (inclut la CA Vault)

Le role common desactive egalement les fichiers repo d'origine (/etc/yum.repos.d/rocky*.repo) pour eviter tout telechargement direct depuis Internet.


Docker registry via Nexus

Nexus expose un proxy Docker qui permet de telecharger des images de conteneurs sans acces direct a Docker Hub.

Fonctionnement

sequenceDiagram
    participant D as Docker Client
    participant N as Nexus (docker-all)
    participant R as Docker Hub

    D->>N: docker pull repo.infra.indio/repository/docker-all/nginx:latest
    alt Image en cache
        N-->>D: Image servie depuis le cache
    else Premier telechargement
        N->>R: Pull depuis registry-1.docker.io (via Squid)
        R-->>N: Layers de l'image
        N->>N: Stockage en cache
        N-->>D: Image servie
    end

Commande de pull

# Pull d'une image via Nexus (prefixer par le hostname Nexus)
docker pull repo.infra.indio/repository/docker-all/nginx:latest

# Equivalent a : docker pull docker.io/library/nginx:latest
# mais via le cache Nexus

Configuration Docker daemon

Le Docker daemon des VMs est configure pour utiliser Nexus comme registry mirror. Le certificat CA de la PKI Vault est installe dans le trust store Docker (/etc/docker/certs.d/repo.infra.indio/ca.crt).


TLS et chaine de confiance

Le certificat HTTPS de Nexus est emis par la PKI Vault (Intermediate CA) :

Parametre Valeur
Emetteur (Issuer) CN=Infra Indio Intermediate CA
Subject CN=repo.infra.indio
SAN DNS:repo.infra.indio, IP:10.15.100.65
Validite 1 an
CRL https://10.15.100.74:8200/v1/pki_int/crl
OCSP https://10.15.100.74:8200/v1/pki_int/ocsp

La CA chain (Root CA + Intermediate CA) est distribuee sur toutes les VMs par le role Ansible common dans /etc/pki/ca-trust/source/anchors/. Ainsi, sslverify=1 fonctionne pour yum, docker, pip et npm sans erreur de certificat.


Capacite air-gap

Grace a Nexus, l'infrastructure peut fonctionner sans acces Internet :

graph TB
    subgraph ONLINE["Mode connecte (normal)"]
        N1["Nexus"] -->|"Proxy cache"| UP["Upstreams Internet"]
        N1 -->|"Sert depuis cache"| VM1["VMs"]
    end

    subgraph OFFLINE["Mode air-gap (coupure)"]
        N2["Nexus<br/>(cache local)"] -->|"Sert depuis cache"| VM2["VMs"]
        N2 -.-x|"Pas d'acces"| UP2["Internet"]
    end

    style OFFLINE fill:#f9f9f9
    style UP2 fill:#e74c3c,color:#fff

Prerequis pour le mode air-gap

Pour qu'un package soit disponible en air-gap, il faut qu'il ait ete telecharge au moins une fois pendant que l'acces Internet etait disponible. Il est recommande de faire un yum makecache et un docker pull de toutes les images necessaires avant une coupure planifiee.