NetBox (IPAM / DCIM)¶
Rôle¶
NetBox est la source de vérité IPAM/DCIM de l'infrastructure Indio : plans d'adressage, réservations IP, inventaire des VM (rôle, plateforme, cluster), et pilotage de l'allocation IP de la quasi-totalité des autres projets Terraform via son provider dédié (e-breuninger/netbox).
Architecture¶
- VM unique INDSERV011, zone admin (
seg-service),10.100.2.140/26, 2 vCPU / 4 Go, clone du template Rocky 9.6 durci. - Pile applicative en conteneurs Podman (déployée par Ansible, pas de compose/systemd-quadlet) : PostgreSQL 16, Redis 7 (cache + file de tâches asynchrones), NetBox (gunicorn) exposé directement en HTTP sur le port 8080, et un worker RQ dédié aux tâches asynchrones. Tous les conteneurs communiquent sur un réseau Podman dédié (
netbox-net). - 18 des 19 projets IaC de la flotte lisent leur IP via le provider Terraform
e-breuninger/netbox(data netbox_ip_addressesfiltrée surdns_name) au lieu d'une IP en dur.netboxlui-même reste en IP fixe (dépendance circulaire : il ne peut pas dépendre de l'API qu'il héberge).veeamest le seul projet applicatif qui n'a pas basculé — voir Veeam. - Jeton API Terraform dédié, lecture seule (
write_enabled=false), stocké dans leterraform.tfvars(gitignored) de chaque projet consommateur.
Structure du dépôt¶
| Fichier / dossier | Contenu |
|---|---|
main.tf |
VM unique vsphere_virtual_machine.netbox, IP fixe |
variables.tf |
vm_name=INDSERV011, vsphere_network=seg-service, cpu=2, ram=4096 |
versions.tf |
Provider hashicorp/vsphere uniquement (pas de provider netbox ici) |
ansible/deploy.yml |
Playbook, rôle unique netbox |
ansible/roles/netbox/tasks/main.yml |
Podman : réseau, PostgreSQL, Redis, NetBox, worker |
ansible/roles/netbox/templates/netbox.env.j2 |
Fichier d'environnement (secrets ansible-vault) |
seed/populate.py |
Seed initial complet — piège noms obsolètes, voir Points d'attention |
seed/add_k8s_vms.py |
Ajout ciblé : 6 VM cluster Kubernetes |
seed/add_postfix_vms.py |
Ajout ciblé : 2 VM Postfix |
seed/add_identity_bare_vms.py |
Ajout ciblé : 4 VM segment identité |
README du dépôt partiellement daté
Le README.md du dépôt décrit une architecture avec un frontal Caddy/nginx devant NetBox — inexistant dans le code réel : le rôle Ansible expose gunicorn directement sur le port 8080 (podman run ... -p {{ netbox_http_port }}:8080), sans aucun reverse proxy local. Cette page reflète le contenu réel de roles/netbox/tasks/main.yml au 2026-07-19, pas le README.
Vue d'ensemble¶
flowchart LR
subgraph NB["VM netbox — INDSERV011 (10.100.2.140:8080)"]
direction TB
APP["NetBox (gunicorn)"]
WRK["worker RQ"]
PG[("PostgreSQL 16")]
RD[("Redis 7")]
APP --> PG
APP --> RD
WRK --> PG
WRK --> RD
end
subgraph Consumers["Projets Terraform consommateurs (data netbox_ip_addresses)"]
K8S["k8s"]
GLPI["glpi"]
OCS["ocs"]
PFX["postfix"]
AUTRES["... 14 autres projets"]
end
Consumers -->|"GET /api/ipam/ip-addresses/?dns_name=...<br/>jeton lecture seule"| APP
subgraph Seed["Scripts seed/*.py (jeton temporaire provisionné puis révoqué)"]
POP["populate.py<br/>seed initial"]
ADDK8S["add_k8s_vms.py"]
ADDPFX["add_postfix_vms.py"]
ADDID["add_identity_bare_vms.py"]
end
Seed -->|"POST/PATCH ponctuel"| APP
Provisioning Terraform¶
main.tf: VM uniquevsphere_virtual_machine.netbox, IP fixe (var.vm_ip, défaut10.100.2.140) — pas de lookup NetBox pour sa propre IP (bootstrap circulaire).- Variables clés (
variables.tf) :vm_name= INDSERV011,vsphere_network=seg-service,vm_cpu= 2,vm_ram= 4096. - Providers (
versions.tf) :hashicorp/vsphereuniquement — contrairement aux autres projets, pas de providernetboxici.
Configuration Ansible¶
ansible/deploy.ymlapplique le rôle uniquenetboxsur l'hôtenetbox(inventory.ini).- Rôle
netbox(roles/netbox/tasks/main.yml) : installe Podman, crée le réseaunetbox-net, lance dans l'ordre les conteneurs PostgreSQL (postgres:16-alpine) puis Redis (redis:7-alpine,--requirepass), attendpg_isready(jusqu'à 20 tentatives), ouvre le port HTTP en firewalld (zonedrop), lance le conteneur NetBox (netboxcommunity/netbox:{{ netbox_version }},--env-file netbox.env, port 8080), attend que/login/réponde 200 (jusqu'à 40 tentatives × 15 s — migrations de schéma au premier démarrage), puis lance le worker RQ (manage.py rqworker). Toutes les commandespodman runsont gardées parpodman container exists <nom> ||pour l'idempotence.podman-restart.serviceactivé pour la persistance des conteneurs au reboot. - Fichier d'environnement
/opt/netbox/netbox.env(templatenetbox.env.j2, mode 0600) : toutes les valeurs sensibles (mots de passe DB/Redis, clé secrète Django, mot de passe superutilisateur) proviennent degroup_vars/all.yml, chiffrées en ansible-vault (netbox_db_password,netbox_redis_password,netbox_superuser_password,netbox_secret_key).
Procédure manuelle¶
- Jeton API Terraform (lecture seule) — créé une fois, manuellement, via l'API/UI NetBox (
write_enabled=false), puis copié dans leterraform.tfvars(gitignored) de chaque projet consommateur. Aucune ressource Terraform/Ansible ne génère ce jeton — mécanisme de rotation à gérer hors IaC (coffre-fort de secrets Indio). - Exécution ponctuelle de
seed/populate.py— jouée une seule fois à la mise en place initiale de l'IPAM (RIR, site, cluster, rôles, prefixes, VM/IP de la flotte de l'époque). Toute VM ajoutée depuis passe par un script ciblé dédié (add_k8s_vms.py,add_postfix_vms.py,add_identity_bare_vms.py), jamais par un rejeu du seed complet — voir Points d'attention.
Procédure de déploiement¶
terraform apply→ provisionne la VMnetbox.ansible-playbook deploy.yml→ déploie la pile Podman complète.python3 seed/populate.py(mise en place initiale uniquement) → peuple le modèle IPAM/DCIM complet : RIR, site, cluster, rôles de zone et rôles fonctionnels, prefixes, IP flottantes/VIP, VM avec interface et IP primaire. Idempotent (get-or-create), authentification via un jeton API provisionné puis révoqué à la fin du script.- Scripts d'ajout ciblés (
seed/add_k8s_vms.py,seed/add_postfix_vms.py,seed/add_identity_bare_vms.py) → ajoutent uniquement les VM d'un projet précis après coup, sans toucher au reste du modèle. - Bascule progressive des projets Terraform de la flotte vers une lecture d'IP via le provider NetBox (déjà effective pour 18 des 19 projets applicatifs).
Contrôle de santé / Vérification¶
curl -sk -o /dev/null -w '%{http_code}\n' http://10.100.2.140:8080/login/ # 200 attendu
podman ps --filter name=netbox # 4 conteneurs Up
podman exec netbox-postgres pg_isready -U <netbox_db_user>
Points d'attention¶
Piège majeur (seed) — déjà rencontré, a créé 31 VM fantômes
seed/populate.py est idempotent (get-or-create/patch) mais sa liste VMS contient encore des noms antérieurs à la convention IND<SEGMENT><NNN> du 2026-07-04. Vérifié dans le code au 2026-07-19, 7 entrées sont toujours dans l'ancien format : haproxy-01/02/03, proxy-01/02, proxy-dns-01/02, ntp-01/02/03 (netbox et nexus sont des exceptions volontaires, jamais renommées). Comme get_or_create filtre par name, rejouer le script entier ne retrouve aucune de ces VM (elles s'appellent désormais INDSERV002/003/004 etc.) et en recrée une fantôme par ancienne entrée. Déjà arrivé une fois (31 VM fantômes créées en ajoutant 10 lignes puis en relançant tout le script), nettoyé via un script ad hoc. Pour ajouter une VM, toujours écrire ou réutiliser un script ciblé (voir add_k8s_vms.py/add_postfix_vms.py/add_identity_bare_vms.py comme modèles) — ne jamais relancer populate.py en entier tant que ces 7 entrées n'ont pas été corrigées ou retirées.
netboxest volontairement exclu de l'allocation IP via son propre provider Terraform (dépendance circulaire) et reste en IP fixe dans sesvariables.tf.- Les scripts
seed/*.pyprovisionnent un jeton API dédié (/users/tokens/provision/) et le révoquent systématiquement en fin d'exécution (blocfinally) — distinct du jeton Terraform persistant (lecture seule), qui lui n'est jamais révoqué automatiquement. - Les identifiants par défaut utilisés par les scripts de seed (variables d'environnement
NB_USER/NB_PASS) ont une valeur de repli codée en dur dans le code source si ces variables ne sont pas positionnées — à surcharger systématiquement via l'environnement plutôt que de s'appuyer sur ce comportement par défaut. - Intégration DNS FreeIPA/AD (NetBox source de vérité → enregistrements A/PTR poussés automatiquement) encore marquée comme en attente dans le README du dépôt.
- Accès direct au port 8080 non joignable depuis tous les segments (le nœud de contrôle management ne route pas vers
seg-service:8080— testé le 2026-07-19) : passer par un hôte déjà routé (proxy DMZ, bastion) pour toute vérification API depuis l'extérieur de la zone admin.