Homelab/Cartographie Réseau et IPAM avec Scanopy
LAN192.168.1.243 / 10.0.0.20

Cartographie Réseau et IPAM avec Scanopy

Cartographie réseau & IPAM

📊 LAB : Cartographie Réseau et IPAM avec Scanopy

 _____                                   
/  ___|                                  
\ `--.  ___ __ _ _ __   ___  _ __  _   _ 
 `--. \/ __/ _` | '_ \ / _ \| '_ \| | | |
/\__/ / (_| (_| | | | | (_) | |_) | |_| |
\____/ \___\__,_|_| |_|\___/| .__/ \__, |
                            | |     __/ |
                            |_|    |___/ 

Type OS Service Role Network

Rôle : Administrateur Réseau / Ingénieur DevOps

Mission : Déployer Scanopy, une solution de cartographie réseau distribuée qui agit comme un annuaire IPAM dynamique. Contrairement à un simple scanner, Scanopy s'appuie sur une architecture décentralisée (un serveur central + des démons déportés) pour scanner simultanément plusieurs sous-réseaux isolés (VLANs, DMZ, LAN physique). Il utilise des requêtes de Niveau 2 (ARP) et Niveau 3/4 (ICMP, TCP, UDP, SNMP) pour découvrir les équipements, identifier les ports ouverts, et construire une topologie visuelle interactive.


L'intérêt technique 🎯

  1. Visibilité Couche 2 (ARP) : Déployer des démons locaux sur chaque sous-réseau permet de récupérer les adresses MAC et de détecter les hôtes furtifs qui bloquent le ping (ICMP), chose impossible au travers d'un routeur.
  2. Architecture Zero Trust : Le serveur central est isolé en DMZ. Les sondes communiquent avec lui via un modèle Polling (ce sont les sondes qui initient la connexion, le serveur n'ouvre aucun flux vers l'extérieur) en utilisant des jetons d'authentification uniques (API Tokens).
  3. Sécurité par Design (Moindre Privilège) : Abandon du mode Docker privilégié (privileged: true) au profit d'une élévation de privilèges granulaire via les Linux Capabilities (NET_RAW, NET_ADMIN).

🛠️ Architecture du Lab

  • Environnement : Serveur Proxmox VE
  • Serveur Central (UI + API + DB) : VM Docker (Debian 13)
    • IP : 10.0.0.20 (Zone DMZ, sur vmbr2)
    • Port d'écoute API/Web : 60072 TCP
  • Sonde Locale (DMZ) : Conteneur Docker sur la même VM (10.0.0.20), chargé de scanner la zone 10.0.0.0/24
  • Sonde Déportée (LAN) : Conteneur LXC (Debian 13) dédié au scan du réseau physique
    • IP : 192.168.1.243 (Zone LAN, sur vmbr0)
  • Routeur / Pare-feu : pfSense (192.168.1.251 côté WAN)

1️⃣ Installation du Serveur Central (Docker Compose)

Le serveur central et sa base de données sont déployés via Docker Compose sur la VM 10.0.0.20. Le fichier intègre également une sonde locale pour scanner la DMZ.

nano docker-compose.yml

⚠️ Sécurité : Le bloc daemon officiel utilise privileged: true, qui donne un accès complet au noyau de la VM hôte. On le remplace par les cap_add strictement nécessaires pour forger des trames réseau.

name: scanopy

services:
  # --- BASE DE DONNÉES ---
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: scanopy
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-<MOT_DE_PASSE>}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - scanopy

  # --- SERVEUR CENTRAL ---
  server:
    image: ghcr.io/scanopy/scanopy/server:latest
    ports:
      - "60072:60072"
    environment:
      SCANOPY_LOG_LEVEL: ${SCANOPY_LOG_LEVEL:-info}
      SCANOPY_DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-<MOT_DE_PASSE>}@postgres:5432/scanopy
      SCANOPY_WEB_EXTERNAL_PATH: /app/static
      SCANOPY_PUBLIC_URL: ${SCANOPY_PUBLIC_URL:-http://10.0.0.20:60072}
      SCANOPY_INTEGRATED_DAEMON_URL: http://host.docker.internal:60073
    volumes:
      - ./data:/data
    extra_hosts:
      - "host.docker.internal:host-gateway"
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - scanopy

  # --- SONDE LOCALE (DMZ) ---
  daemon:
    image: ghcr.io/scanopy/scanopy/daemon:latest
    container_name: scanopy-daemon
    network_mode: host                 # Obligatoire pour le scan ARP (couche 2)
    cap_add:                           # Moindre Privilège : remplace "privileged: true"
      - NET_RAW                        # Forger des paquets bruts (ARP, ICMP)
      - NET_ADMIN                      # Modifier les interfaces réseau
    restart: unless-stopped
    environment:
      SCANOPY_LOG_LEVEL: ${SCANOPY_LOG_LEVEL:-info}
      SCANOPY_SERVER_URL: http://127.0.0.1:60072
    volumes:
      - daemon-config:/root/.config/daemon
      - /var/run/docker.sock:/var/run/docker.sock:ro  # Lecture seule des conteneurs

volumes:
  postgres_data:
  daemon-config:

networks:
  scanopy:
    driver: bridge

Démarrage de l'infrastructure :

docker compose up -d

L'interface Web est accessible sur http://10.0.0.20:60072.


2️⃣ Configuration IPAM (Interface Web)

Avant de déployer une sonde sur un autre sous-réseau, il faut déclarer ce réseau dans l'application pour générer une identité sécurisée.

  1. Création du Réseau Logique : Networks > Add Network → Nom : Network LAN
  2. Création du Sous-réseau : Subnets > Add Subnet → Type : LAN, CIDR : 192.168.1.0/24, Parent : Network LAN
  3. Génération de l'Identité du Démon : Daemons > Create a daemon → Réseau Network LAN, Nom : scanopy-daemon-network-lan
    • Copier la commande d'installation, le Token API et l'ID réseau.

3️⃣ Déploiement de la Sonde Déportée (LXC)

Création d'un conteneur LXC Debian 13 non privilégié sur Proxmox :

CPU : 1 Cœur | RAM : 512 Mo | Disque : 2 Go
Réseau : vmbr0 | IP : 192.168.1.243/24 | Gateway : 192.168.1.254

A. Routage inter-zones (LAN → DMZ)

La sonde LAN (192.168.1.0/24) doit contacter le serveur en DMZ (10.0.0.0/24). La box domestique ne gère pas le routage interne — on configure un routage statique local (host-based routing) via pfSense.

nano /etc/network/interfaces
auto eth0
iface eth0 inet static
    address 192.168.1.243/24
    gateway 192.168.1.254
    # Route statique : trafic DMZ via pfSense
    up ip route add 10.0.0.0/24 via 192.168.1.251

Redémarrer le conteneur ou injecter à chaud : ip route add 10.0.0.0/24 via 192.168.1.251.

Règle de pare-feu pfSense : Firewall > Rules > WAN

ParamètreValeur
ActionPass
ProtocolTCP
Source192.168.1.243
Destination10.0.0.20
Port60072

B. Installation et Configuration du Service Systemd

# Installation des pré-requis
apt update && apt install -y curl sudo

# Lancement du script officiel (remplacer localhost par l'IP DMZ)
bash -c "$(curl -fsSL https://raw.githubusercontent.com/scanopy/scanopy/refs/heads/main/install.sh)" \
  && sudo scanopy-daemon \
    --server-url http://10.0.0.20:60072 \
    --network-id <VOTRE_ID> \
    --daemon-api-key <VOTRE_TOKEN> \
    --user-id <VOTRE_USER_ID> \
    --name scanopy-daemon-network-lan \
    --mode daemon_poll

⚠️ Le script installe le binaire mais les variables d'environnement peuvent être perdues au redémarrage. Configurer le fichier Systemd en dur pour la fiabilisation.

nano /etc/systemd/system/scanopy-daemon.service
[Unit]
Description=Scanopy Network Discovery Daemon
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/scanopy-daemon \
  --server-url http://10.0.0.20:60072 \
  --network-id <VOTRE_ID> \
  --daemon-api-key <VOTRE_TOKEN> \
  --user-id <VOTRE_USER_ID> \
  --name scanopy-daemon-network-lan \
  --mode daemon_poll
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

⚠️ La syntaxe du mode exige daemon_poll (underscore) et non DaemonPoll.

systemctl daemon-reload
systemctl enable --now scanopy-daemon
journalctl -fu scanopy-daemon

Le message Connected to server dans les journaux confirme que le routage, le pare-feu et l'authentification sont fonctionnels. La découverte réseau démarre automatiquement sur l'interface web.

connecting

daemons

network

Topologie

topo


📋 Résumé

  • Service : Scanopy — cartographie réseau distribuée et IPAM
  • Serveur : Docker Compose sur VM 10.0.0.20:60072 (DMZ)
  • Sonde DMZ : conteneur Docker en network_mode: host avec cap_add (pas de privileged)
  • Sonde LAN : LXC 192.168.1.243 avec routage statique vers la DMZ via pfSense
  • Protocoles : ARP (L2), ICMP/TCP/UDP (L3/L4), SNMP
  • Sécurité : tokens API uniques, modèle polling (sonde → serveur), moindre privilège (capabilities)

📚 Références