Proxmox lancelot : compte API dédié, VLAN 200 LAB en DHCP
Clonage par l'API (community.proxmox) avec bwpoc@pve limité au pool bwpoc ; modèle créé une fois en root avec l'agent QEMU, qui sert à lire les IP DHCP écrites dans inventory/host_vars/<vm>/dhcp.yml. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
099584c95c
commit
5846487f07
15 files changed
+502
-348
No files matched your search
@@ -33,25 +33,70 @@ Le domaine par défaut est `bwpoc.internal` (TLD réservé par l'ICANN pour l'us
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Un nœud Proxmox VE 8 joignable en SSH **root** depuis le poste Ansible, avec accès Internet (image Debian, images Docker, listes noires communautaires).
|
||||
- 3 IP libres sur le réseau des VM (1 en mode tout-en-un). Le playbook vérifie par ping qu'elles sont libres avant de créer les VM.
|
||||
- Sur le poste Ansible : `ansible-core` 2.16 ou plus, une paire de clés SSH.
|
||||
- Un nœud Proxmox VE 8 ou 9 (ici `lancelot`, 172.16.16.7) avec accès Internet (image Debian, images Docker, listes noires communautaires).
|
||||
- Un accès SSH **root** au nœud, utilisé **une seule fois** pour créer le modèle de VM et le pool `bwpoc`. Tout le reste passe par l'API avec un compte dédié (voir plus bas).
|
||||
- Un réseau de VM avec DHCP : ici le VLAN 200 "LAB", qui fournit IP, passerelle et DNS. Le poste Ansible doit pouvoir joindre ce VLAN en SSH.
|
||||
- Sur le poste Ansible : `ansible-core` 2.17 ou plus (exigé par `community.proxmox`), `proxmoxer` et `requests` en Python, une paire de clés SSH.
|
||||
|
||||
```bash
|
||||
git clone git@gitea.vlab.bzh:vLab-BZH/bunkerwebpoc.git && cd bunkerwebpoc
|
||||
make deps # installe community.docker et ansible.posix dans ./collections
|
||||
make deps # collections community.docker et community.proxmox, puis proxmoxer
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Tout ce qui dépend de votre infra est marqué `A ADAPTER` :
|
||||
|
||||
1. [`inventory/hosts.yml`](inventory/hosts.yml) : IP du nœud Proxmox, IP et VMID des 3 VM, CPU, RAM, disque.
|
||||
2. [`inventory/group_vars/all.yml`](inventory/group_vars/all.yml) : domaine, passerelle, DNS, stockage Proxmox, pont, VLAN, clé SSH publique.
|
||||
1. [`inventory/hosts.yml`](inventory/hosts.yml) : nœud Proxmox, VMID des 3 VM, CPU, RAM, disque. Pas d'IP : elles viennent du DHCP.
|
||||
2. [`inventory/group_vars/all.yml`](inventory/group_vars/all.yml) : domaine, nœud, stockage, pont et VLAN, compte API, clé SSH publique.
|
||||
3. [`inventory/group_vars/bunkerweb.yml`](inventory/group_vars/bunkerweb.yml) : les réglages BunkerWeb, globaux et par site. C'est le fichier à modifier pour jouer avec les fonctionnalités.
|
||||
|
||||
Les mots de passe (MariaDB, Redis, admin de l'UI) sont générés au premier lancement dans `credentials/` côté poste Ansible (ignoré par git). Pour les mettre sous `ansible-vault`, remplacez les `lookup('password')` de `bunkerweb.yml` par vos variables chiffrées.
|
||||
|
||||
## Compte Proxmox dédié
|
||||
|
||||
Le clonage et le pilotage des VM passent par l'API avec l'utilisateur `bwpoc@pve` et un jeton, limité à un pool `bwpoc`. Seule la création du modèle (import d'une image disque par chemin, réservé à `root@pam`) se fait en SSH root, une fois.
|
||||
|
||||
Privilèges nécessaires, regroupés dans un rôle `BWPoC` :
|
||||
|
||||
| Privilège | Pour quoi faire |
|
||||
|---|---|
|
||||
| `VM.Allocate`, `VM.Clone` | créer les clones dans le pool, les supprimer |
|
||||
| `VM.Config.CPU`, `VM.Config.Memory`, `VM.Config.Disk`, `VM.Config.Network`, `VM.Config.Cloudinit`, `VM.Config.Options`, `VM.Config.HWType`, `VM.Config.CDROM` | régler CPU, RAM, disque, cloud-init, démarrage auto, tags |
|
||||
| `VM.PowerMgmt` | démarrer et arrêter les VM |
|
||||
| `VM.Audit`, `Pool.Audit` | lire l'état des VM et du pool |
|
||||
| `VM.GuestAgent.Audit` (PVE 9) ou `VM.Monitor` (PVE 8) | lire l'IP DHCP par l'agent QEMU |
|
||||
|
||||
Et les ACL, au plus juste :
|
||||
|
||||
| Chemin | Rôle | Pourquoi |
|
||||
|---|---|---|
|
||||
| `/pool/bwpoc` | `BWPoC` | les VM du PoC et le modèle 9100, placé dans le pool |
|
||||
| `/storage/local-lvm` | `PVEDatastoreUser` | allouer les disques des clones |
|
||||
| `/sdn/zones/localnetwork/vmbr0/200` | `PVESDNUser` | brancher les VM sur le VLAN 200 (et seulement lui) |
|
||||
| `/nodes/lancelot` | `PVEAuditor` | lecture du nœud par le module Ansible |
|
||||
|
||||
En root sur `lancelot` (sur PVE 8, remplacer `VM.GuestAgent.Audit` par `VM.Monitor`) :
|
||||
|
||||
```bash
|
||||
pveum pool add bwpoc --comment "PoC BunkerWeb"
|
||||
pveum role add BWPoC --privs "VM.Allocate,VM.Clone,VM.Audit,VM.PowerMgmt,VM.Config.CPU,VM.Config.Memory,VM.Config.Disk,VM.Config.Network,VM.Config.Cloudinit,VM.Config.Options,VM.Config.HWType,VM.Config.CDROM,VM.GuestAgent.Audit,Pool.Audit"
|
||||
pveum user add bwpoc@pve --comment "PoC BunkerWeb (Ansible)"
|
||||
pveum user token add bwpoc@pve ansible --privsep 0 # affiche le secret une seule fois
|
||||
pveum acl modify /pool/bwpoc --users bwpoc@pve --roles BWPoC
|
||||
pveum acl modify /storage/local-lvm --users bwpoc@pve --roles PVEDatastoreUser
|
||||
pveum acl modify /sdn/zones/localnetwork/vmbr0/200 --users bwpoc@pve --roles PVESDNUser
|
||||
pveum acl modify /nodes/lancelot --users bwpoc@pve --roles PVEAuditor
|
||||
```
|
||||
|
||||
Si le réseau "LAB" est un VNet SDN plutôt qu'un tag sur `vmbr0`, l'ACL réseau devient `/sdn/zones/<zone>/LAB` et, dans `all.yml`, `pve_bridge: LAB` avec `pve_vlan_tag: ""`.
|
||||
|
||||
Le secret du jeton reste hors du dépôt, dans l'environnement :
|
||||
|
||||
```bash
|
||||
export PVE_TOKEN_SECRET='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
|
||||
```
|
||||
|
||||
## Déploiement
|
||||
|
||||
```bash
|
||||
@@ -60,7 +105,7 @@ make deploy # = ansible-playbook playbooks/site.yml
|
||||
|
||||
| Étape | Playbook | Ce qu'elle fait |
|
||||
|---|---|---|
|
||||
| 1 | `00-proxmox.yml` | télécharge l'image Debian 13 genericcloud, crée le modèle cloud-init (VMID 9100), clone les VM, injecte IP et clé SSH, agrandit les disques, démarre |
|
||||
| 1 | `00-proxmox.yml` | en root (une fois) : télécharge l'image Debian 13 genericcloud, y ajoute l'agent QEMU, crée le modèle cloud-init (VMID 9100) et le pool `bwpoc`. Puis par l'API avec `bwpoc@pve` : clone les VM dans le pool, cloud-init en DHCP + clé SSH, agrandit les disques, démarre, lit l'IP obtenue par l'agent QEMU et l'écrit dans `inventory/host_vars/<vm>/dhcp.yml` |
|
||||
| 2 | `10-base.yml` | paquets de base, agent QEMU, résolution locale des noms du PoC vers le WAF, Docker CE depuis le dépôt officiel |
|
||||
| 3 | `20-apps.yml` | stack des applis, filtrage `DOCKER-USER` (mode split) |
|
||||
| 4 | `30-bunkerweb.yml` | stack BunkerWeb, attente qu'`api` réponde au travers du WAF, écriture de `credentials/ACCES.txt` |
|
||||
@@ -76,12 +121,18 @@ ansible-playbook playbooks/render.yml # écrit build/split/... ou build/single
|
||||
|
||||
Un exemple de rendu (secrets remplacés par `CHANGEME`) est versionné dans [`examples/split/`](examples/split/) (`bunkerweb.compose.yml`, `apps.compose.yml`, `bwpoc-firewall.sh`).
|
||||
|
||||
### Adresses IP et DHCP
|
||||
|
||||
Les VM démarrent sur le VLAN 200 "LAB" en DHCP. Le modèle embarque l'agent QEMU : le playbook lit l'IP de chaque VM par l'API Proxmox, l'enregistre dans `inventory/host_vars/<vm>/dhcp.yml` (ignoré par git) et recharge l'inventaire. Les playbooks suivants, et vos relances (`make waf`...), utilisent ces fichiers.
|
||||
|
||||
Comme l'IP du WAF sert au filtrage `DOCKER-USER` et aux `/etc/hosts`, **réservez les baux DHCP** des trois VM (adresses MAC visibles dans Proxmox). Si une IP change quand même, relancez `make vms base apps waf client` : les fichiers `dhcp.yml` et les règles sont régénérés.
|
||||
|
||||
### Accéder aux sites depuis votre poste
|
||||
|
||||
Les VM du PoC résolvent déjà les noms (bloc dans `/etc/hosts`). Sur votre poste, ajoutez la ligne suivante à `/etc/hosts`, ou déclarez les enregistrements dans votre DNS de labo :
|
||||
|
||||
```
|
||||
192.168.200.61 www.bwpoc.internal shop.bwpoc.internal api.bwpoc.internal bwui.bwpoc.internal
|
||||
<IP de bw-waf> www.bwpoc.internal shop.bwpoc.internal api.bwpoc.internal bwui.bwpoc.internal
|
||||
```
|
||||
|
||||
Puis ouvrez `https://bwui.bwpoc.internal/` (certificat auto-signé à accepter). Identifiants : `make creds`.
|
||||
@@ -115,7 +166,7 @@ Depuis `bw-client` (ou n'importe quel poste avec `curl` et `jq`, le script utili
|
||||
|
||||
```bash
|
||||
make tests # depuis le poste Ansible
|
||||
ssh debian@192.168.200.63 bwpoc-tests # ou directement sur le client
|
||||
ssh debian@<IP de bw-client> bwpoc-tests # ou directement sur le client
|
||||
```
|
||||
|
||||
Le script enchaîne une vingtaine de contrôles et affiche `OK`, `KO` ou `INFO` :
|
||||
@@ -143,7 +194,7 @@ Le script enchaîne une vingtaine de contrôles et affiche `OK`, `KO` ou `INFO`
|
||||
Les derniers tests **bannissent volontairement votre IP** du site `api` pendant 5 minutes (`bw_ban_time`). Pour lever le ban : menu *Bans* de l'UI, ou sur `bw-waf` :
|
||||
|
||||
```bash
|
||||
docker exec bw-scheduler bwcli unban 192.168.200.63
|
||||
docker exec bw-scheduler bwcli unban <IP du client>
|
||||
```
|
||||
|
||||
### Avec et sans WAF
|
||||
@@ -152,12 +203,12 @@ Pour mesurer l'apport du WAF, autorisez le client à joindre les applis en direc
|
||||
|
||||
```yaml
|
||||
# inventory/group_vars/all.yml
|
||||
apps_direct_access_sources: [192.168.200.63]
|
||||
apps_direct_access_sources: ["<IP de bw-client>"]
|
||||
```
|
||||
|
||||
```bash
|
||||
make apps
|
||||
ssh debian@192.168.200.63 bwpoc-tests --direct
|
||||
ssh debian@<IP de bw-client> bwpoc-tests --direct
|
||||
```
|
||||
|
||||
La SQLi de Juice Shop renvoie alors la liste complète des produits (200) au lieu d'un 403, et le `PUT` passe.
|
||||
@@ -175,7 +226,7 @@ La SQLi de Juice Shop renvoie alors la liste complète des produits (200) au lie
|
||||
|
||||
```bash
|
||||
make waf # réapplique la conf BunkerWeb après modification de bunkerweb.yml
|
||||
make destroy # supprime les VM (confirmation demandée), modèle conservé
|
||||
make destroy # supprime les VM en root sur le nœud (confirmation demandée), modèle conservé
|
||||
ansible-playbook playbooks/99-destroy.yml -e destroy_template=true # supprime aussi le modèle
|
||||
```
|
||||
|
||||
@@ -194,8 +245,8 @@ Sur `bw-waf`, la stack vit dans `/opt/bwpoc/bunkerweb` (`docker compose ps`, `lo
|
||||
inventory/ hosts.yml (3 VM), single.yml (tout-en-un), group_vars/
|
||||
playbooks/ 00 à 50 + site.yml, render.yml, 99-destroy.yml
|
||||
roles/
|
||||
proxmox_template/ modèle Debian 13 cloud-init via qm
|
||||
proxmox_vm/ clonage, cloud-init, démarrage
|
||||
proxmox_template/ modèle Debian 13 cloud-init + agent QEMU, pool (root, une fois)
|
||||
proxmox_vm/ clonage par l'API (bwpoc@pve), DHCP, lecture des IP
|
||||
common/ paquets, agent QEMU, /etc/hosts
|
||||
docker/ Docker CE + compose (dépôt officiel)
|
||||
apps/ compose des applis, vitrine, filtrage DOCKER-USER
|
||||
|
||||
Reference in new issue
Block a user