# Stupid Simple Network Inventory ![Python](https://img.shields.io/badge/Python-3.11-3776AB?logo=python&logoColor=white) ![FastAPI](https://img.shields.io/badge/FastAPI-009688?logo=fastapi&logoColor=white) ![Vue.js](https://img.shields.io/badge/Vue.js-3-4FC08D?logo=vue.js&logoColor=white) ![SQLite](https://img.shields.io/badge/SQLite-003B57?logo=sqlite&logoColor=white) ![Nginx](https://img.shields.io/badge/Nginx-009639?logo=nginx&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=white) Application web auto-hébergée pour l'inventaire manuel de réseau et la visualisation de topologie réseau logique. ![Vue Topologie](img/tpology.png) ## Fonctionnalités - **Inventaire manuel** — ajout et gestion d'équipements (18 types) avec IPs, VLANs, descriptions et liens web optionnels - **Vue topologie** — disposition en cards par réseau (LAN / VLAN 802.1Q), avec sections WAN et passerelle - **Ping ICMP** — vérification de l'accessibilité de tous les hôtes connus en un clic - **Découverte automatique** — ping sweep + lookup PTR DNS sur un sous-réseau pour importer de nouveaux hôtes - **Authentification** — connexion JWT avec changement de mot de passe forcé à la première utilisation - **Mode sombre** — bascule thème clair / sombre - **Logos de marques** — détection et affichage automatiques des logos éditeurs/fabricants (Proxmox, Cisco, Synology, Docker, et plus de 30 autres) - **i18n** — français, anglais, espagnol ## Stack | Couche | Technologie | |--------|------------| | Backend | FastAPI + SQLAlchemy + SQLite (Python 3.11) | | Frontend | Vue 3 + Vite, servi par Nginx | | Auth | JWT HS256, expiration 24h | | Runtime | Docker Compose | --- ## Démarrage rapide ```bash # 1. Cloner et entrer dans le projet git clone https://git.raspot.in/olivier/stupid-simple-network-inventory.git cd stupid-simple-network-inventory # 2. Créer le répertoire de données appartenant à l'utilisateur courant mkdir -p db_data # 3. Configurer l'environnement (requis pour la propriété correcte du bind-mount) cp .env.example .env # Éditer .env : # DOCKER_UID / DOCKER_GID → résultat de : id -u && id -g # INITIAL_ADMIN_PASSWORD → à définir pour éviter le bootstrap admin/admin par défaut # 4. Construire et démarrer docker compose --env-file .env up --build -d # 5. Ouvrir http://localhost:8080 dans votre navigateur ``` ### Première connexion | Cas | Identifiants | Comportement | |-----|-------------|--------------| | `INITIAL_ADMIN_PASSWORD` défini | `admin` / `` | Connexion normale | | `INITIAL_ADMIN_PASSWORD` non défini | `admin` / `admin` | Changement de mot de passe forcé avant d'accéder à l'application | --- ## Configuration Toute la configuration se fait via des variables d'environnement. Voir `.env.example` pour la liste complète avec descriptions. | Variable | Défaut | Description | |----------|--------|-------------| | `SECRET_KEY` | auto-générée | Clé de signature JWT. À définir explicitement en production. | | `INITIAL_ADMIN_PASSWORD` | _(vide)_ | Mot de passe admin de bootstrap. Si non défini, `admin/admin` est utilisé avec changement forcé. | | `ALLOWED_ORIGINS` | `*` | Origines CORS autorisées (séparées par des virgules). À définir sur votre domaine en production. | | `BIND_ADDRESS` | `0.0.0.0` | Adresse IP d'écoute. À définir sur l'interface face au reverse proxy. | | `DOCKER_UID` / `DOCKER_GID` | `1000` | UID/GID pour le processus backend. Doit correspondre à l'utilisateur propriétaire de `./db_data/`. | ### Utilisation de .env avec Docker Compose ```bash cp .env.example .env # Éditer .env — définir au minimum DOCKER_UID, DOCKER_GID, INITIAL_ADMIN_PASSWORD docker compose --env-file .env up --build -d ``` --- ## Sécurité ### Gestion des secrets Deux options selon vos exigences de sécurité. #### Option A — Secret auto-généré (recommandé pour un nœud unique) Laisser `SECRET_KEY` non défini (ou vide) dans `.env`. Au premier démarrage, le backend génère une clé hexadécimale aléatoire de 64 caractères, l'écrit dans `db_data/secret_key.txt` avec les permissions **0600**, et la réutilise à chaque redémarrage. Le secret n'apparaît jamais dans une variable d'environnement, un fichier compose ou un log. ```bash # .env — laisser la ligne vide ou la supprimer SECRET_KEY= ``` La seule exigence est que `db_data/` soit sauvegardé (il contient déjà la base de données). #### Option B — Secret via fichier Docker Compose Stocke le secret dans un fichier sur l'hôte, hors du contrôle de version, et le monte dans le conteneur. La valeur n'apparaît jamais dans une variable d'environnement. ```bash # Générer et stocker le secret en dehors du répertoire du projet mkdir -p ~/.secrets python3 -c "import secrets; print(secrets.token_hex(32))" > ~/.secrets/topologie_secret_key chmod 600 ~/.secrets/topologie_secret_key ``` Décommenter ensuite les blocs `secrets:` dans `docker-compose.yml` (voir les commentaires dans ce fichier) et supprimer `SECRET_KEY` de `.env`. Docker Compose fusionne la surcharge automatiquement : ```bash docker compose up -d ``` --- ### Rotation de clé Pour faire tourner le secret JWT (invalide toutes les sessions actives) : ```bash # Option A — variable d'environnement (recommandé) # Définir un nouveau SECRET_KEY dans la configuration de déploiement et redémarrer # Option B — rotation par fichier docker compose stop backend rm db_data/secret_key.txt docker compose start backend # Tous les utilisateurs devront se reconnecter ``` ### HTTPS Cette application ne termine pas TLS. Pour un usage en production, placez-la derrière un reverse proxy gérant HTTPS : ```nginx # Exemple de reverse proxy nginx (externe, sur l'hôte ou un conteneur dédié) server { listen 443 ssl; server_name inventory.example.com; ssl_certificate /etc/letsencrypt/live/inventory.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/inventory.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Pour un usage local uniquement, lier à la boucle locale pour éviter une exposition LAN accidentelle : ```yaml # docker-compose.override.yml services: frontend: ports: - "127.0.0.1:8080:8080" ``` ### Durcissement des conteneurs Les conteneurs s'exécutent avec des privilèges réduits : | Mesure | Backend | Frontend | |--------|---------|----------| | Utilisateur non-root | `DOCKER_UID:DOCKER_GID` (utilisateur hôte) | `nginx` (UID 101) | | `cap_drop: ALL` | ✓ | ✓ | | `cap_add: NET_RAW` | ✓ (ping) | — | | `no-new-privileges` | — ¹ | ✓ | | Healthcheck | ✓ | ✓ | ¹ Omis sur le backend : le ping utilise les file capabilities (`cap_net_raw=ep`) ; `no-new-privileges` supprimerait le bit effectif du fichier et empêcherait le sous-processus d'acquérir `CAP_NET_RAW` dans son ensemble effectif même si le parent le détient dans son ensemble permis. --- ## Persistance des données Toutes les données sont stockées dans `./db_data/` : | Fichier | Description | |---------|-------------| | `topology.db` | Base de données SQLite | | `secret_key.txt` | Secret JWT auto-généré (permissions 0600) | **Sauvegarde** : `cp -r db_data/ db_data.bak/` **Restauration** : arrêter la stack, remplacer `db_data/`, redémarrer. --- ## Développement ### Tests backend ```bash cd backend pip install -r requirements.txt -r requirements-test.txt pytest tests/ -v ``` ### Dev local (sans Docker) ```bash # Backend cd backend pip install -r requirements.txt uvicorn main:app --reload # Frontend (terminal séparé) cd frontend npm install npm run dev # Serveur dev Vite sur :5173, proxifie /api/ vers :8000 ``` --- ## Architecture Voir [`docs/architecture.md`](docs/architecture.md) pour le flux de requêtes détaillé, la configuration Docker et le modèle d'authentification.