PoC BunkerWeb 1.6.17 : docker-compose sur Proxmox, déployé par Ansible
Stack BunkerWeb (scheduler, UI, MariaDB, Redis), sites de test (nginx, Juice Shop, go-httpbin), filtrage DOCKER-USER, script de tests, README et schéma d'architecture. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
099584c95c
42 files changed
+4260
No files matched your search
@@ -0,0 +1,2 @@
|
||||
---
|
||||
bw_dir: "{{ poc_base_dir }}/bunkerweb"
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
- name: Créer le répertoire de la stack BunkerWeb
|
||||
ansible.builtin.file:
|
||||
path: "{{ bw_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
|
||||
- name: Créer le réseau partagé bw-services
|
||||
ansible.builtin.shell: docker network inspect bw-services >/dev/null 2>&1 || { docker network create bw-services && echo created; }
|
||||
register: bw_net
|
||||
changed_when: "'created' in bw_net.stdout"
|
||||
|
||||
- name: Générer le compose BunkerWeb
|
||||
ansible.builtin.template:
|
||||
src: compose.yml.j2
|
||||
dest: "{{ bw_dir }}/compose.yml"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0600" # contient les secrets
|
||||
validate: docker compose -f %s config -q
|
||||
|
||||
- name: Démarrer la stack BunkerWeb
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ bw_dir }}"
|
||||
project_name: bunkerweb
|
||||
pull: missing
|
||||
remove_orphans: true
|
||||
state: present
|
||||
register: bw_compose
|
||||
|
||||
- name: Attendre que BunkerWeb réponde sur 443
|
||||
ansible.builtin.wait_for:
|
||||
host: "{{ ansible_host }}"
|
||||
port: 443
|
||||
timeout: 300
|
||||
|
||||
- name: Attendre que le site api réponde au travers du WAF
|
||||
ansible.builtin.uri:
|
||||
url: "https://{{ ansible_host }}/get"
|
||||
headers:
|
||||
Host: "api.{{ poc_domain }}"
|
||||
validate_certs: false
|
||||
status_code: 200
|
||||
register: bw_probe
|
||||
until: bw_probe.status == 200
|
||||
retries: 30
|
||||
delay: 10
|
||||
|
||||
- name: Écrire le récapitulatif des accès côté contrôleur (credentials/ACCES.txt)
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ playbook_dir }}/../credentials/ACCES.txt"
|
||||
mode: "0600"
|
||||
content: |
|
||||
UI BunkerWeb : https://bwui.{{ poc_domain }}/ (WAF {{ ansible_host }})
|
||||
Identifiant : {{ bw_ui_admin_user }}
|
||||
Mot de passe : {{ bw_ui_admin_password }}
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Rappel des accès
|
||||
ansible.builtin.debug:
|
||||
msg: "UI BunkerWeb : https://bwui.{{ poc_domain }}/ , identifiants dans credentials/ACCES.txt"
|
||||
@@ -0,0 +1,133 @@
|
||||
# {{ ansible_managed }}
|
||||
# Stack BunkerWeb {{ bunkerweb_version }} : WAF + scheduler + UI + MariaDB + Redis
|
||||
# Mode {{ poc_mode }}{% if poc_mode == 'split' %}, applis sur {{ apps_ip }}{% endif %}
|
||||
|
||||
{% macro upstream(name, site) -%}
|
||||
{%- if site.upstream is match('^https?://') -%}
|
||||
{{ site.upstream }}
|
||||
{%- elif poc_mode == 'single' -%}
|
||||
http://poc-{{ site.upstream }}:{{ apps_internal_ports[site.upstream] }}
|
||||
{%- else -%}
|
||||
http://{{ apps_ip }}:{{ apps_ports[site.upstream] }}
|
||||
{%- endif -%}
|
||||
{%- endmacro %}
|
||||
{% macro val(v) %}{{ (v | string | replace('$', '$$')) | to_json }}{% endmacro %}
|
||||
x-db-env: &db-env
|
||||
DATABASE_URI: {{ val('mariadb+pymysql://bunkerweb:' ~ bw_db_password ~ '@bw-db:3306/db') }}
|
||||
|
||||
x-api-env: &api-env
|
||||
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24"
|
||||
|
||||
services:
|
||||
bunkerweb:
|
||||
image: bunkerity/bunkerweb:{{ bunkerweb_version }}
|
||||
container_name: bunkerweb
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:8080/tcp"
|
||||
- "443:8443/tcp"
|
||||
- "443:8443/udp" # HTTP/3 (QUIC)
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
<<: [*db-env, *api-env]
|
||||
networks:
|
||||
- bw-universe
|
||||
- bw-services
|
||||
|
||||
bw-scheduler:
|
||||
image: bunkerity/bunkerweb-scheduler:{{ bunkerweb_version }}
|
||||
container_name: bw-scheduler
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- bunkerweb
|
||||
- bw-db
|
||||
- bw-redis
|
||||
volumes:
|
||||
- bw-storage:/data
|
||||
environment:
|
||||
<<: [*db-env, *api-env]
|
||||
BUNKERWEB_INSTANCES: "bunkerweb"
|
||||
SERVER_NAME: {{ val(bw_sites.keys() | map('regex_replace', '$', '.' ~ poc_domain) | join(' ')) }}
|
||||
# --- Réglages globaux ---
|
||||
{% for k, v in bw_global_settings.items() %}
|
||||
{{ k }}: {{ val(v) }}
|
||||
{% endfor %}
|
||||
{% for name, site in bw_sites.items() %}
|
||||
{% set fqdn = name ~ '.' ~ poc_domain %}
|
||||
# --- {{ fqdn }} ---
|
||||
{{ fqdn }}_USE_REVERSE_PROXY: "yes"
|
||||
{{ fqdn }}_REVERSE_PROXY_URL: "/"
|
||||
{{ fqdn }}_REVERSE_PROXY_HOST: {{ val(upstream(name, site)) }}
|
||||
{{ fqdn }}_SELF_SIGNED_SSL_SUBJ: {{ val('/CN=' ~ fqdn ~ '/') }}
|
||||
{% for k, v in (site.settings | default({})).items() %}
|
||||
{{ fqdn }}_{{ k }}: {{ val(v) }}
|
||||
{% endfor %}
|
||||
{% for k, v in (site.custom_confs | default({})).items() %}
|
||||
{{ fqdn }}_CUSTOM_CONF_{{ k }}: {{ val(v) }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
networks:
|
||||
- bw-universe
|
||||
- bw-db
|
||||
|
||||
bw-ui:
|
||||
image: bunkerity/bunkerweb-ui:{{ bunkerweb_version }}
|
||||
container_name: bw-ui
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- bw-db
|
||||
volumes:
|
||||
- bw-ui-data:/data # secrets Flask, clés TOTP et Biscuit
|
||||
environment:
|
||||
<<: *db-env
|
||||
ADMIN_USERNAME: {{ val(bw_ui_admin_user) }}
|
||||
ADMIN_PASSWORD: {{ val(bw_ui_admin_password) }}
|
||||
TZ: "Europe/Paris"
|
||||
networks:
|
||||
- bw-universe
|
||||
- bw-db
|
||||
|
||||
bw-db:
|
||||
image: {{ mariadb_image }}
|
||||
container_name: bw-db
|
||||
restart: unless-stopped
|
||||
command: --max-allowed-packet=67108864
|
||||
environment:
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
|
||||
MYSQL_DATABASE: "db"
|
||||
MYSQL_USER: "bunkerweb"
|
||||
MYSQL_PASSWORD: {{ val(bw_db_password) }}
|
||||
volumes:
|
||||
- bw-data:/var/lib/mysql
|
||||
networks:
|
||||
- bw-db
|
||||
|
||||
bw-redis:
|
||||
image: {{ redis_image }}
|
||||
container_name: bw-redis
|
||||
restart: unless-stopped
|
||||
command: ["redis-server", "--requirepass", {{ val(bw_redis_password) }}, "--save", "60", "1"]
|
||||
volumes:
|
||||
- bw-redis:/data
|
||||
networks:
|
||||
- bw-universe
|
||||
|
||||
volumes:
|
||||
bw-data:
|
||||
bw-storage:
|
||||
bw-ui-data:
|
||||
bw-redis:
|
||||
|
||||
networks:
|
||||
bw-universe:
|
||||
name: bw-universe
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: 10.20.30.0/24 # seul réseau autorisé à parler à l'API BunkerWeb
|
||||
bw-services:
|
||||
name: bw-services # réseau des applis (mode single), créé par Ansible
|
||||
external: true
|
||||
bw-db:
|
||||
name: bw-db
|
||||
Reference in new issue
Block a user