Doc et exemples à jour : publication en *-bwpoc.vlab.bzh derrière Traefik, modèle 9100 avec agent QEMU
- README : noms des sites, accès via Traefik, configuration retenue sur vLab, variante BunkerWeb en frontal avec Let's Encrypt, prérequis du modèle - examples/split régénérés depuis la configuration actuelle (secrets en CHANGEME) - schéma : libellé des sites en *-bwpoc.vlab.bzh Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
e395fae4c6
commit
f0f61548d2
5 files changed
+82
-56
No files matched your search
@@ -24,17 +24,17 @@ Chaque site met en avant un groupe de fonctionnalités :
|
||||
|
||||
| Site | Appli | Ce qu'on y teste |
|
||||
|---|---|---|
|
||||
| `www.<domaine>` | vitrine nginx statique (page d'accueil + formulaire de contact) | antibot JavaScript, en-têtes de sécurité, redirection HTTPS, XSS via formulaire dans le navigateur |
|
||||
| `shop.<domaine>` | [OWASP Juice Shop](https://owasp.org/www-project-juice-shop/), appli volontairement vulnérable | ModSecurity + OWASP CRS 4 (SQLi, XSS, traversée), websockets, User-Agents malveillants |
|
||||
| `api.<domaine>` | [go-httpbin](https://github.com/mccutchen/go-httpbin), API qui renvoie ce qu'elle reçoit | limitation de débit, méthodes autorisées, taille max du corps, bad behavior et bannissement, règle ModSecurity maison, compression, `X-Forwarded-For` |
|
||||
| `bwui.<domaine>` | interface web de BunkerWeb | rapports d'attaques, bannissements, réglages, journaux |
|
||||
| `www<suffixe>` | vitrine nginx statique (page d'accueil + formulaire de contact) | antibot JavaScript, en-têtes de sécurité, redirection HTTPS, XSS via formulaire dans le navigateur |
|
||||
| `shop<suffixe>` | [OWASP Juice Shop](https://owasp.org/www-project-juice-shop/), appli volontairement vulnérable | ModSecurity + OWASP CRS 4 (SQLi, XSS, traversée), websockets, User-Agents malveillants |
|
||||
| `api<suffixe>` | [go-httpbin](https://github.com/mccutchen/go-httpbin), API qui renvoie ce qu'elle reçoit | limitation de débit, méthodes autorisées, taille max du corps, bad behavior et bannissement, règle ModSecurity maison, compression, `X-Forwarded-For` |
|
||||
| `bwui<suffixe>` | interface web de BunkerWeb | rapports d'attaques, bannissements, réglages, journaux |
|
||||
|
||||
Le domaine par défaut est `bwpoc.internal` (TLD réservé par l'ICANN pour l'usage privé). Les certificats sont auto-signés par BunkerWeb, site par site.
|
||||
Le nom complet d'un site est `<site><poc_fqdn_suffix>`. Sur le labo vLab, le PoC est publié derrière le Traefik de `*.vlab.bzh` : **`www-bwpoc.vlab.bzh`, `shop-bwpoc.vlab.bzh`, `api-bwpoc.vlab.bzh` et `bwui-bwpoc.vlab.bzh`** (un seul niveau sous le wildcard, Let's Encrypt géré par Traefik, voir [Exposer le PoC](#exposer-le-poc-sur-un-domaine-public)). Pour un labo fermé, `poc_domain: bwpoc.internal` et `poc_fqdn_suffix: ".bwpoc.internal"` (TLD réservé par l'ICANN pour l'usage privé) donnent `www.bwpoc.internal`... Sauf avec `poc_tls: letsencrypt`, BunkerWeb présente ses propres certificats auto-signés, site par site.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- 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 modèle cloud-init Debian 13 **avec qemu-guest-agent installé** et un machine-id vierge (sur lancelot : 9100 `debian13-bwpoc`, dérivé de 9001). À défaut, `pve_template_create: true` le fabrique depuis l'image officielle, ce qui demande un accès SSH root au nœud une seule fois. Tout le reste passe par l'API.
|
||||
- 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.
|
||||
|
||||
@@ -55,7 +55,7 @@ Les mots de passe (MariaDB, Redis, admin de l'UI) sont générés au premier lan
|
||||
|
||||
## 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`. Par défaut, le PoC clone un modèle cloud-init Debian 13 existant (`pve_template_vmid`, 9001 sur lancelot : VLAN 200, agent QEMU), donc aucun SSH root n'est nécessaire. Avec `pve_template_create: true`, le modèle 9100 est fabriqué en SSH root (import d'une image disque par chemin, réservé à `root@pam`), une fois.
|
||||
Le clonage et le pilotage des VM passent par l'API avec l'utilisateur `bwpoc@pve` et un jeton, limité à un pool `bwpoc`. Par défaut, le PoC clone un modèle cloud-init existant (`pve_template_vmid`, 9100 `debian13-bwpoc` sur lancelot : le 9001 de base + qemu-guest-agent + `cloud-init clean --machine-id`), donc aucun SSH root n'est nécessaire. Sans agent QEMU dans le modèle, le playbook ne peut pas lire les IP DHCP. Avec `pve_template_create: true`, le modèle 9100 est fabriqué en SSH root (import d'une image disque par chemin, réservé à `root@pam`), une fois.
|
||||
|
||||
Privilèges nécessaires, regroupés dans un rôle `BWPoC` :
|
||||
|
||||
@@ -136,19 +136,19 @@ Comme l'IP du WAF sert au filtrage `DOCKER-USER` et aux `/etc/hosts`, **réserve
|
||||
|
||||
### 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 :
|
||||
Sur vLab, les noms publics passent par Traefik : ouvrez `https://bwui-bwpoc.vlab.bzh/` (réservée aux IP privées, voir `poc_allowed_sources`). Identifiants : `make creds` (utilisateur `admin`).
|
||||
|
||||
Les VM du PoC résolvent les noms vers le WAF directement (bloc dans `/etc/hosts`), ce qui permet aux tests de contourner Traefik. En labo fermé (`bwpoc.internal`), faites de même sur votre poste :
|
||||
|
||||
```
|
||||
<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`.
|
||||
|
||||
## Comment BunkerWeb est configuré ici
|
||||
|
||||
Intégration **Docker** officielle (pas l'autoconf) : toute la configuration est portée par les variables d'environnement du `bw-scheduler`, qui génère la configuration nginx et la pousse à l'instance `bunkerweb` par son API (réseau `bw-universe` 10.20.30.0/24, seul autorisé par `API_WHITELIST_IP`). Ce choix permet de protéger des backends situés sur une autre VM, ce que les labels de l'autoconf ne savent pas faire.
|
||||
|
||||
`MULTISITE=yes` : chaque réglage peut être préfixé par le nom du site (`api.bwpoc.internal_LIMIT_REQ_RATE=5r/s`). Dans Ansible, il suffit de remplir le dictionnaire `bw_sites` :
|
||||
`MULTISITE=yes` : chaque réglage peut être préfixé par le nom du site (`api-bwpoc.vlab.bzh_LIMIT_REQ_RATE=5r/s`). Dans Ansible, il suffit de remplir le dictionnaire `bw_sites` :
|
||||
|
||||
```yaml
|
||||
bw_sites:
|
||||
@@ -158,7 +158,7 @@ bw_sites:
|
||||
ALLOWED_METHODS: "GET|POST|HEAD"
|
||||
MAX_CLIENT_SIZE: "1m"
|
||||
LIMIT_REQ_RATE: "5r/s"
|
||||
custom_confs: # devient api.<domaine>_CUSTOM_CONF_MODSEC_poc-rule
|
||||
custom_confs: # devient api<suffixe>_CUSTOM_CONF_MODSEC_poc-rule
|
||||
MODSEC_poc-rule: >-
|
||||
SecRule ARGS:poc "@streq attack" "id:10001,phase:2,deny,status:403,log,msg:'PoC'"
|
||||
```
|
||||
@@ -223,15 +223,31 @@ La SQLi de Juice Shop renvoie alors la liste complète des produits (200) au lie
|
||||
### Aller plus loin à la main
|
||||
|
||||
- **sqlmap** contre Juice Shop, d'abord avec son User-Agent par défaut (bloqué par la liste communautaire), puis avec `--random-agent` pour voir le CRS prendre le relais :
|
||||
`sqlmap -u "https://shop.bwpoc.internal/rest/products/search?q=test" --random-agent --batch`
|
||||
`sqlmap -u "https://shop-bwpoc.vlab.bzh/rest/products/search?q=test" --random-agent --batch` (uniquement contre votre propre PoC)
|
||||
- **Antibot** dans le navigateur : passez `www` en `captcha` ou `cookie` dans `bunkerweb.yml`, relancez `make waf`.
|
||||
- **Faux positifs** : naviguez dans Juice Shop (connexion, panier, avis). Ce que le CRS bloque à tort apparaît dans l'UI (*Reports*) avec l'ID de règle ; on l'exclut par un `custom_confs` de type `MODSEC_CRS` (exemple : `SecRuleRemoveById 942100`).
|
||||
- **Mode détection seule** : `MODSECURITY_SEC_RULE_ENGINE: "DetectionOnly"` sur un site, pour observer avant de bloquer, comme on le ferait en production.
|
||||
- **Journaux** : `docker logs -f bunkerweb` sur `bw-waf`, et l'audit ModSecurity dans `/var/log/bunkerweb/modsec_audit.log` du conteneur.
|
||||
|
||||
## Exposer le PoC sur un domaine public (Let's Encrypt)
|
||||
## Exposer le PoC sur un domaine public
|
||||
|
||||
Par défaut tout est en `bwpoc.internal` avec des certificats auto-signés. Pour un vrai domaine (exemple : `lab.naoned.net`) :
|
||||
### Configuration retenue sur vLab : derrière Traefik, `*-bwpoc.vlab.bzh`
|
||||
|
||||
`*.vlab.bzh` est un wildcard DNS qui pointe sur le Traefik du labo (172.16.16.21 côté LAN), qui gère seul Let's Encrypt. Un nom à deux niveaux (`www.bwpoc.vlab.bzh`) n'étant pas bien pris en charge par ce Traefik, les sites sont nommés avec un tiret. Réglages actuels de [`all.yml`](inventory/group_vars/all.yml) :
|
||||
|
||||
```yaml
|
||||
poc_domain: vlab.bzh
|
||||
poc_fqdn_suffix: "-bwpoc.{{ poc_domain }}" # www-bwpoc.vlab.bzh, shop-bwpoc.vlab.bzh...
|
||||
poc_tls: selfsigned # le TLS public est porté par Traefik
|
||||
poc_trusted_proxies: ["172.16.16.21"] # IP réelle des clients via X-Forwarded-For
|
||||
poc_allowed_sources: ["172.16.0.0/12", "192.168.0.0/16"] # UI réservée au LAN
|
||||
```
|
||||
|
||||
Côté Traefik, un routeur par nom (ou un seul avec les 4 `Host`) vers `https://<IP de bw-waf>:443` avec `insecureSkipVerify`, voir l'exemple plus bas. Réservez le bail DHCP de bw-waf pour que cette IP ne bouge pas.
|
||||
|
||||
### Variante : BunkerWeb en frontal avec Let's Encrypt
|
||||
|
||||
Si le WAF reçoit directement 80/443 (exemple : `lab.naoned.net`) :
|
||||
|
||||
1. DNS : `www`, `shop`, `api` et `bwui` du domaine pointent sur l'IP publique NATée vers le WAF.
|
||||
2. Pare-feu : 80 et 443 (TCP, plus 443/UDP pour HTTP/3) vers l'IP du WAF ; réservation DHCP sur la MAC du WAF pour que l'IP ne bouge pas.
|
||||
@@ -258,7 +274,7 @@ http:
|
||||
routers:
|
||||
bwpoc:
|
||||
rule: "Host(`www-bwpoc.vlab.bzh`) || Host(`shop-bwpoc.vlab.bzh`) || Host(`api-bwpoc.vlab.bzh`) || Host(`bwui-bwpoc.vlab.bzh`)"
|
||||
entryPoints: [websecure]
|
||||
entryPoints: [websecure] # sur vLab : extranetfree
|
||||
service: bwpoc
|
||||
tls: { certResolver: letsencrypt }
|
||||
services:
|
||||
|
||||
Reference in new issue
Block a user