From b923810fe3e66c21c4fe9f9b6d19aebcfa1c0f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=2E=20Nam=C3=A8che?= Date: Wed, 21 Jan 2026 15:29:56 +0300 Subject: [PATCH] First version in Galaxy --- .gitignore | 1 + LICENSE.md | 30 +++ README.md | 196 +----------------- roles/caddy/.gitignore | 1 - roles/consul/notes.txt | 62 ------ {roles/caddy => seb4itik/byow}/README.md | 137 ++++++++---- seb4itik/byow/galaxy.yml | 15 ++ seb4itik/byow/meta/runtime.yml | 1 + seb4itik/byow/plugins/README.md | 31 +++ seb4itik/byow/roles/caddy/README.md | 5 + .../byow/roles}/caddy/defaults/main.yml | 0 .../caddy/files/bot_barrier_template.html | 0 .../roles}/caddy/filter_plugins/filters.py | 0 .../byow/roles}/caddy/handlers/main.yml | 0 .../byow/roles}/caddy/tasks/caddy_config.yml | 0 .../byow/roles}/caddy/tasks/caddy_install.yml | 0 .../byow/roles}/caddy/tasks/main.yml | 0 .../roles}/caddy/tasks/plugin_install.yml | 0 .../byow/roles}/caddy/templates/Caddyfile | 0 .../byow/roles}/caddy/templates/caddy.service | 0 .../byow/roles}/caddy/templates/coraza.conf | 0 .../roles}/caddy/templates/crs-setup.conf | 0 .../templates/exclusions-request-before.conf | 0 .../templates/exclusions-response-after.conf | 0 .../byow/roles}/caddy/vars/main.yml | 0 seb4itik/byow/roles/common/README.md | 5 + .../byow/roles}/common/defaults/main.yml | 0 .../byow/roles}/common/tasks/main.yml | 0 .../roles}/common/tasks/setup_packages.yml | 0 .../common/tasks/setup_proxy_client.yml | 0 .../roles}/common/templates/apt_proxy.conf | 0 seb4itik/byow/roles/consul/README.md | 5 + .../byow/roles}/consul/defaults/main.yml | 0 .../byow/roles}/consul/handlers/main.yml | 0 .../byow/roles}/consul/tasks/main.yml | 0 .../byow/roles}/consul/templates/config.json | 0 .../roles}/consul/templates/consul.service | 0 seb4itik/byow/roles/keepalived/README.md | 5 + .../byow/roles}/keepalived/defaults/main.yml | 0 .../byow/roles}/keepalived/handlers/main.yml | 0 .../byow/roles}/keepalived/tasks/main.yml | 0 .../keepalived/templates/keepalived.conf | 0 seb4itik/byow/roles/local_ca/README.md | 5 + .../byow/roles}/local_ca/defaults/main.yml | 0 .../byow/roles}/local_ca/tasks/main.yml | 0 seb4itik/byow/roles/local_ca_certs/README.md | 5 + .../roles}/local_ca_certs/defaults/main.yml | 0 .../roles}/local_ca_certs/handlers/main.yml | 0 .../local_ca_certs/tasks/create_cert.yml | 0 .../byow/roles}/local_ca_certs/tasks/main.yml | 0 seb4itik/byow/roles/mysql/README.md | 5 + .../byow/roles}/mysql/defaults/main.yml | 0 .../byow/roles}/mysql/handlers/main.yml | 0 .../byow/roles}/mysql/tasks/main.yml | 0 seb4itik/byow/roles/nfs_client/README.md | 5 + .../byow/roles}/nfs_client/defaults/main.yml | 0 .../byow/roles}/nfs_client/tasks/main.yml | 0 seb4itik/byow/roles/nfs_server/README.md | 5 + .../byow/roles}/nfs_server/defaults/main.yml | 0 .../byow/roles}/nfs_server/handlers/main.yml | 0 .../byow/roles}/nfs_server/tasks/main.yml | 0 .../byow/roles}/nfs_server/templates/exports | 0 seb4itik/byow/roles/ovh_ldp/README.md | 5 + .../byow/roles}/ovh_ldp/defaults/main.yml | 0 .../byow/roles}/ovh_ldp/handlers/main.yml | 0 .../byow/roles}/ovh_ldp/tasks/main.yml | 0 .../roles}/ovh_ldp/templates/ldp-ovh.conf | 0 seb4itik/byow/roles/unbound/README.md | 5 + .../byow/roles}/unbound/defaults/main.yml | 0 .../byow/roles}/unbound/handlers/main.yml | 0 .../byow/roles}/unbound/tasks/main.yml | 0 .../roles}/unbound/templates/unbound.conf | 0 seb4itik/byow/roles/wordpress/README.md | 5 + .../byow/roles}/wordpress/defaults/main.yml | 0 .../byow/roles}/wordpress/handlers/main.yml | 0 .../wordpress/tasks/install_plugins.yml | 0 .../byow/roles}/wordpress/tasks/main.yml | 0 .../wordpress/templates/nginx_vhost.conf | 0 seb4itik/byow/seb4itik-byow-0.1.0.tar.gz | Bin 0 -> 33683 bytes 79 files changed, 235 insertions(+), 299 deletions(-) create mode 100644 LICENSE.md delete mode 100644 roles/caddy/.gitignore delete mode 100644 roles/consul/notes.txt rename {roles/caddy => seb4itik/byow}/README.md (54%) create mode 100644 seb4itik/byow/galaxy.yml create mode 100644 seb4itik/byow/meta/runtime.yml create mode 100644 seb4itik/byow/plugins/README.md create mode 100644 seb4itik/byow/roles/caddy/README.md rename {roles => seb4itik/byow/roles}/caddy/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/caddy/files/bot_barrier_template.html (100%) rename {roles => seb4itik/byow/roles}/caddy/filter_plugins/filters.py (100%) rename {roles => seb4itik/byow/roles}/caddy/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/caddy/tasks/caddy_config.yml (100%) rename {roles => seb4itik/byow/roles}/caddy/tasks/caddy_install.yml (100%) rename {roles => seb4itik/byow/roles}/caddy/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/caddy/tasks/plugin_install.yml (100%) rename {roles => seb4itik/byow/roles}/caddy/templates/Caddyfile (100%) rename {roles => seb4itik/byow/roles}/caddy/templates/caddy.service (100%) rename {roles => seb4itik/byow/roles}/caddy/templates/coraza.conf (100%) rename {roles => seb4itik/byow/roles}/caddy/templates/crs-setup.conf (100%) rename {roles => seb4itik/byow/roles}/caddy/templates/exclusions-request-before.conf (100%) rename {roles => seb4itik/byow/roles}/caddy/templates/exclusions-response-after.conf (100%) rename {roles => seb4itik/byow/roles}/caddy/vars/main.yml (100%) create mode 100644 seb4itik/byow/roles/common/README.md rename {roles => seb4itik/byow/roles}/common/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/common/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/common/tasks/setup_packages.yml (100%) rename {roles => seb4itik/byow/roles}/common/tasks/setup_proxy_client.yml (100%) rename {roles => seb4itik/byow/roles}/common/templates/apt_proxy.conf (100%) create mode 100644 seb4itik/byow/roles/consul/README.md rename {roles => seb4itik/byow/roles}/consul/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/consul/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/consul/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/consul/templates/config.json (100%) rename {roles => seb4itik/byow/roles}/consul/templates/consul.service (100%) create mode 100644 seb4itik/byow/roles/keepalived/README.md rename {roles => seb4itik/byow/roles}/keepalived/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/keepalived/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/keepalived/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/keepalived/templates/keepalived.conf (100%) create mode 100644 seb4itik/byow/roles/local_ca/README.md rename {roles => seb4itik/byow/roles}/local_ca/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/local_ca/tasks/main.yml (100%) create mode 100644 seb4itik/byow/roles/local_ca_certs/README.md rename {roles => seb4itik/byow/roles}/local_ca_certs/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/local_ca_certs/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/local_ca_certs/tasks/create_cert.yml (100%) rename {roles => seb4itik/byow/roles}/local_ca_certs/tasks/main.yml (100%) create mode 100644 seb4itik/byow/roles/mysql/README.md rename {roles => seb4itik/byow/roles}/mysql/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/mysql/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/mysql/tasks/main.yml (100%) create mode 100644 seb4itik/byow/roles/nfs_client/README.md rename {roles => seb4itik/byow/roles}/nfs_client/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/nfs_client/tasks/main.yml (100%) create mode 100644 seb4itik/byow/roles/nfs_server/README.md rename {roles => seb4itik/byow/roles}/nfs_server/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/nfs_server/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/nfs_server/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/nfs_server/templates/exports (100%) create mode 100644 seb4itik/byow/roles/ovh_ldp/README.md rename {roles => seb4itik/byow/roles}/ovh_ldp/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/ovh_ldp/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/ovh_ldp/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/ovh_ldp/templates/ldp-ovh.conf (100%) create mode 100644 seb4itik/byow/roles/unbound/README.md rename {roles => seb4itik/byow/roles}/unbound/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/unbound/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/unbound/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/unbound/templates/unbound.conf (100%) create mode 100644 seb4itik/byow/roles/wordpress/README.md rename {roles => seb4itik/byow/roles}/wordpress/defaults/main.yml (100%) rename {roles => seb4itik/byow/roles}/wordpress/handlers/main.yml (100%) rename {roles => seb4itik/byow/roles}/wordpress/tasks/install_plugins.yml (100%) rename {roles => seb4itik/byow/roles}/wordpress/tasks/main.yml (100%) rename {roles => seb4itik/byow/roles}/wordpress/templates/nginx_vhost.conf (100%) create mode 100644 seb4itik/byow/seb4itik-byow-0.1.0.tar.gz diff --git a/.gitignore b/.gitignore index 998d9a7..3f6153d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/notes/ .ansible/ __pycache__/ infra-*/ diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f269e6f --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,30 @@ +Copyright (c) 2026 Sébastien Namèche (iTik). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. All advertising materials mentioning features or use of this software must +display the following acknowledgement: +This product includes software developed by Sébastien Namèche (iTik). + +4. Neither the name of the copyright holder nor the names the copyright holder +nor the names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 9d99142..dae6133 100644 --- a/README.md +++ b/README.md @@ -1,197 +1,5 @@ # BYOW - Build Your Own WAF -Ce rôle Ansible déploie un WAF basé sur Caddy, Coraza et les OWASP Core Security Rules. +A WAF _à la carte_. -## Principes - -### Go - -Caddy, Coraza, le module Coraza pour Caddy et l'outil `xcaddy` sont -développés avec le langage Go. - -L'outil `xcaddy` a besoin d'une version récente des outils de -développement Go. C'est pourquoi le rôle installe Go depuis -le site de téléchargement officiel et non via le gestionnaire -de paquets de la distribution Linux. - -Go est installé dans le répertoire `/usr/local/go-1.25.5/go` et -un lien symbolique est créé de `/usr/local/bin/go` vers -`/usr/local/go-1.25.5/go/bin/go`. - -### Caddy - -Caddy est un serveur Web et reverse proxy HTTP puissant et versatile. - -Étant développé en Go, son déploiement prend la forme d'un simble -binaire exécutable qui contient toutes les librairies requises. Ce -programme est construit avec l'outil `xcaddy` puis copié dans le -fichier `/usr/local/bin/caddy`. La ligne de commande utilisée pour -construire ce binaire est enregsitrée dans le fichier -`/usr/local/bin/.caddy.buil`. - -Le fichier de configuration de caddy utilise le format `Caddyfile`. -Il est généré automatiquement à partir des paramètres du rôle puis -enregistré sous `/etc/caddy/Caddyfile`. - -### Coraza - -Coraza est directement inclus dans le binaire `caddy` - -### Module Coraza pour Caddy - -### xcaddy - -qui permet de lier tous les modules Go requis -pour le WAF - -### Plugins OWASP CRS - -(À ne pas confondre avec les plugins Coraza.) - -Voir: https://github.com/coreruleset/plugin-registry - - - name: "drupal-rule-exclusions" - - name: "wordpress-rule-exclusions" - - name: "nextcloud-rule-exclusions" - - name: "dokuwiki-rule-exclusions" - - name: "phpmyadmin-rule-exclusions" - - name: "roundcube-rule-exclusions" - - name: "sogo-rule-exclusions" - - -## Paramètres du rôle Ansible - - - -## TODO - -Fonctionnalités déjà implémentées: - -- Déploiement et configuration avec Ansible -- Serveurs transient -- VIP (avec Keepalived) -- DNS dynamique (via Nomad) -- Cluster via Nomad -- OWASP CRS -- Multisite (avec configuration complète des CRS par site) -- Alias avec redirection optionnelle vers nom canonique -- Redirection HTTP vers HTTPS -- Certificats SSL (personnalisés automatiques via Let's Encrypt) -- Filtrage (blacklists) par: - - adresses IP - - réseaux IP -- Antibot par: - - défi JavaScript -- Passive backend checks -- Compression Gzip et zstd -- Mode détection sans blocage par les CRS -- Filtrage par: - - méthode HTTP -- En-têtes de sécurité: - - HSTS - - CSP - - X-Frame-Options - - X-Content-Type-Options - - Referrer Policy - - Permissions Policy - - Keep Headers - - Cookie Flags - - Custom headers - - suppression d'en-têtes -- Collecte des logs via OVH LDP - -Urgemment: - -- Connexion à consul, ACL consul -- Collection Ansible -- Revérifier gestion CORS -- Active backend checks -- Correction de la collecte des logs via OVH LDP - -Fomctionnalités à ajouter: - -- Rate limiting distribué -- Antibot par: - - Cookie - - Captcha - - reCAPTCHA - - hCaptcha - - Turnstile - - mCaptcha -- Filtrage par: - - rDNS - - DNSBL - - ASN - - User-Agent (robots, crawlers, IA bots) - - taille - - URI patterns - - pays - - (ip:danmeuk-tor-exit, ua:mitchellkrogza-bad-user-agents, /etc/hapee-1.9/blacklist.acl) -- Client cache -- Proxy cache -- Compression Brotli -- Reverse scan -- Robots.txt (DarkVisitors API/Community Lists/Custom URLs/Manual Rules) -- Gestion des sessions -- Whitelist -- Bad behavior (via Caddy events ?) -- Authentification -- Anti DDoS -- Greylist -- HTML injection -- Metrics (Elasticsearch + Metabase) -- Static files et FastCGI pour PHP (est-ce une bonne idée ?!) -- Crowdsec -- https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list - - -## Ressources - -- [Documentation officielle Caddy](https://caddyserver.com/docs/) -- [Site Officiel de Coraza](https://coraza.io) -- [Coraza WAF Caddy module](https://github.com/corazawaf/coraza-caddy) -- [Documentation AWOSP CRS](https://coreruleset.org/docs/) -- https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x) - -Modules -- []() -- []() - - -### Installation d'Ansible avec pipx - -1. Désinstaller *Ansible* et *ansible-lint* s'ils sont déjà installés. Par - exemple avec *Homebrew*: - ``` - brew uninstall ansible ansible-lint - ``` -1. Installer *pipx*. Par exemple avec *Homebrew*: - ``` - brew install pipx - ``` -1. Inscrire le chemin de recherche des exécutables de *pipx* dans les - scripts d'ouverture de session (fermer le shell et en ouvrir un nouveau - pour activer ce chemin de recherche): - ``` - pipx ensurepath - ``` -1. Installer *Ansible* (version 12, et au moins version core 2.16.9, pour - être compatible avec *Mitogen*) dans un environnement isolé (qui sera - nommé `ansible`) puis injecter *ansible-lint* et les librairies requises - dans cet environnement: - ``` - pipx install ansible==12.3.0 --include-deps - pipx inject ansible ansible-lint --include-apps - pipx inject ansible requests - pipx inject ansible pip-system-certs - pipx inject ansible passlib # pour |password_hash sur macOS (et autres) - pipx inject ansible jmespath # pour |query_result - pipx inject ansible pytz # pour plugin inventory auto - pipx inject ansible mitogen # optionnel, pour utiliser Mitogen - ``` -1. Vérifier l'environnement: - ``` - pipx list --include-injected - ansible --version -> ansible [core 2.19.5] - ansible-lint --version -> ansible-lint 26.1.1 - ``` +See [seb4itik/byow/README.md](seb4itik/byow/README.md) diff --git a/roles/caddy/.gitignore b/roles/caddy/.gitignore deleted file mode 100644 index 298c305..0000000 --- a/roles/caddy/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/docs/ \ No newline at end of file diff --git a/roles/consul/notes.txt b/roles/consul/notes.txt deleted file mode 100644 index e8a040c..0000000 --- a/roles/consul/notes.txt +++ /dev/null @@ -1,62 +0,0 @@ -Security: -- Gossip protocol encryption -- Built-in ACL -- Consul agent communication -- mTLS for authentitication and encryption -- Certificate authority - - -FIXME: -- Ne fonctionne pas sous Debian 13 - - - "acl": { - "enabled": true, -{% if not consul_acl_bootstraped %} - "default_policy": "allow", -{% else %} - "default_policy": "deny", - "tokens": { - "agent": "FIXME" - }, -{% endif %} - "down_policy": "extend-cache" - }, - - -FIXME: -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'ca_file' field is deprecated. Use the 'tls.defaults.ca_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'cert_file' field is deprecated. Use the 'tls.defaults.cert_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'key_file' field is deprecated. Use the 'tls.defaults.key_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'verify_incoming' field is deprecated. Use the 'tls.defaults.verify_incoming' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'verify_outgoing' field is deprecated. Use the 'tls.defaults.verify_outgoing' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'verify_server_hostname' field is deprecated. Use the 'tls.internal_rpc.verify_server_hostname' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: The 'ui' field is deprecated. Use the 'ui_config.enabled' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.976+0300 [WARN] agent: bootstrap_expect > 0: expecting 3 servers -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'ca_file' field is deprecated. Use the 'tls.defaults.ca_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'cert_file' field is deprecated. Use the 'tls.defaults.cert_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'key_file' field is deprecated. Use the 'tls.defaults.key_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'verify_incoming' field is deprecated. Use the 'tls.defaults.verify_incoming' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'verify_outgoing' field is deprecated. Use the 'tls.defaults.verify_outgoing' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'verify_server_hostname' field is deprecated. Use the 'tls.internal_rpc.verify_server_hostname' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: The 'ui' field is deprecated. Use the 'ui_config.enabled' field instead. -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'ca_file' field is deprecated. Use the 'tls.defaults.ca_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: 2026-01-20T14:00:20.983+0300 [WARN] agent.auto_config: bootstrap_expect > 0: expecting 3 servers -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'cert_file' field is deprecated. Use the 'tls.defaults.cert_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'key_file' field is deprecated. Use the 'tls.defaults.key_file' field instead. -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'verify_incoming' field is deprecated. Use the 'tls.defaults.verify_incoming' field instead. -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'verify_outgoing' field is deprecated. Use the 'tls.defaults.verify_outgoing' field instead. -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'verify_server_hostname' field is deprecated. Use the 'tls.internal_rpc.verify_server_hostname' field instead. -Jan 20 14:00:20 waf1 consul[3863]: agent.auto_config: The 'ui' field is deprecated. Use the 'ui_config.enabled' field instead. - - -FIXME: -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/demo/v1/recordlabel -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/demo/v1/artist -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/demo/v1/album -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/demo/v1/concept -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/demo/v2/festival -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/multicluster/v2/exportedservices -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/multicluster/v2/namespaceexportedservices -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/multicluster/v2/partitionexportedservices -Jan 20 15:32:40 waf1 consul[2072]: agent.http: Registered resource endpoint: endpoint=/api/internal/v1/tombstone diff --git a/roles/caddy/README.md b/seb4itik/byow/README.md similarity index 54% rename from roles/caddy/README.md rename to seb4itik/byow/README.md index b211142..aec5285 100644 --- a/roles/caddy/README.md +++ b/seb4itik/byow/README.md @@ -1,4 +1,6 @@ -# Web Application Firewall +# BYOW - Build Your Own WAF + +A WAF _à la carte_. Ce rôle Ansible déploie un WAF basé sur Caddy, Coraza et les OWASP Core Security Rules. @@ -67,50 +69,26 @@ Voir: https://github.com/coreruleset/plugin-registry Fonctionnalités déjà implémentées: -- Multisite (cavec configuration des CRS par site) -- Redirection vers nom canonique -- Rediction HTTP vers HTTPS -- Certificats SSL (autmotiques via Let's Encrypt et customs) +- Déploiement et configuration avec Ansible +- Serveurs transient +- VIP (avec Keepalived) +- DNS dynamique (via Nomad) +- Cluster via Nomad - OWASP CRS -- Redirect (SSL et www et autres) -- Filtrage par: +- Multisite (avec configuration complète des CRS par site) +- Alias avec redirection optionnelle vers nom canonique +- Redirection HTTP vers HTTPS +- Certificats SSL (personnalisés automatiques via Let's Encrypt) +- Filtrage (blacklists) par: - adresses IP - réseaux IP - Antibot par: - défi JavaScript - Passive backend checks -- Compression Gzip et zstd - - -Fomctionnalités à ajouter: - -- Active backend checks -- Antibot par: - - Cookie - - Captcha - - reCAPTCHA - - hCaptcha - - Turnstile - - mCaptcha -- Changement de format de configuration: Caddyfile -> JSON -- Mise en œuvre d'un cluster Redis (ou Consul) pour le partage de informations entre les WAF d'un cluster -- Mieux tester le configuration des CRS -- Mode détection sans blocage +- Compression Gzip et zstd +- Mode détection sans blocage par les CRS - Filtrage par: - - rDNS - - DNSBL - - ASN - - User-Agent (robots, crawlers, IA bots) - méthode HTTP - - taille - - URI patterns - - pays - - (ip:danmeuk-tor-exit, ua:mitchellkrogza-bad-user-agents, /etc/hapee-1.9/blacklist.acl) -- Gestion CORS -- Client cache -- Proxy cache -- Filtrage par pays -- Compression Brotli - En-têtes de sécurité: - HSTS - CSP @@ -121,17 +99,52 @@ Fomctionnalités à ajouter: - Keep Headers - Cookie Flags - Custom headers + - suppression d'en-têtes +- Collecte des logs via OVH LDP + +Urgemment: + +- Connexion à consul, ACL consul +- Collection Ansible +- Revérifier gestion CORS +- Active backend checks +- Correction de la collecte des logs via OVH LDP + +Fomctionnalités à ajouter: + +- Rate limiting distribué +- Antibot par: + - Cookie + - Captcha + - reCAPTCHA + - hCaptcha + - Turnstile + - mCaptcha +- Filtrage par: + - rDNS + - DNSBL + - ASN + - User-Agent (robots, crawlers, IA bots) + - taille + - URI patterns + - pays + - (ip:danmeuk-tor-exit, ua:mitchellkrogza-bad-user-agents, /etc/hapee-1.9/blacklist.acl) +- Client cache +- Proxy cache +- Compression Brotli - Reverse scan - Robots.txt (DarkVisitors API/Community Lists/Custom URLs/Manual Rules) -- Sessions +- Gestion des sessions - Whitelist -- Bad behavior -- Auth -- Anti DoDS +- Bad behavior (via Caddy events ?) +- Authentification +- Anti DDoS - Greylist - HTML injection - Metrics (Elasticsearch + Metabase) -- Static files et FastCGI pour PHP +- Static files et FastCGI pour PHP (est-ce une bonne idée ?!) +- Crowdsec +- https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list ## Ressources @@ -140,7 +153,47 @@ Fomctionnalités à ajouter: - [Site Officiel de Coraza](https://coraza.io) - [Coraza WAF Caddy module](https://github.com/corazawaf/coraza-caddy) - [Documentation AWOSP CRS](https://coreruleset.org/docs/) +- https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x) Modules - []() - []() + + +### Installation d'Ansible avec pipx + +1. Désinstaller *Ansible* et *ansible-lint* s'ils sont déjà installés. Par + exemple avec *Homebrew*: + ``` + brew uninstall ansible ansible-lint + ``` +1. Installer *pipx*. Par exemple avec *Homebrew*: + ``` + brew install pipx + ``` +1. Inscrire le chemin de recherche des exécutables de *pipx* dans les + scripts d'ouverture de session (fermer le shell et en ouvrir un nouveau + pour activer ce chemin de recherche): + ``` + pipx ensurepath + ``` +1. Installer *Ansible* (version 12, et au moins version core 2.16.9, pour + être compatible avec *Mitogen*) dans un environnement isolé (qui sera + nommé `ansible`) puis injecter *ansible-lint* et les librairies requises + dans cet environnement: + ``` + pipx install ansible==12.3.0 --include-deps + pipx inject ansible ansible-lint --include-apps + pipx inject ansible requests + pipx inject ansible pip-system-certs + pipx inject ansible passlib # pour |password_hash sur macOS (et autres) + pipx inject ansible jmespath # pour |query_result + pipx inject ansible pytz # pour plugin inventory auto + pipx inject ansible mitogen # optionnel, pour utiliser Mitogen + ``` +1. Vérifier l'environnement: + ``` + pipx list --include-injected + ansible --version -> ansible [core 2.19.5] + ansible-lint --version -> ansible-lint 26.1.1 + ``` diff --git a/seb4itik/byow/galaxy.yml b/seb4itik/byow/galaxy.yml new file mode 100644 index 0000000..e9ea74d --- /dev/null +++ b/seb4itik/byow/galaxy.yml @@ -0,0 +1,15 @@ +namespace: "seb4itik" +name: "byow" +version: "0.1.0" +readme: "README.md" +authors: +- "S. Namèche " +description: "Build Your Own WAF" +license: +- "BSD-4-Clause" +tags: ['waf'] +dependencies: {} +repository: "https://lab.itik.fr/itik/bgwaf" +documentation: "https://lab.itik.fr/itik/bgwaf/src/branch/main/README.md" +homepage: "https://lab.itik.fr/itik/bgwaf" +issues: "https://lab.itik.fr/itik/bgwaf/issues" diff --git a/seb4itik/byow/meta/runtime.yml b/seb4itik/byow/meta/runtime.yml new file mode 100644 index 0000000..3e3704b --- /dev/null +++ b/seb4itik/byow/meta/runtime.yml @@ -0,0 +1 @@ +requires_ansible: '>=2.19.5' diff --git a/seb4itik/byow/plugins/README.md b/seb4itik/byow/plugins/README.md new file mode 100644 index 0000000..74076b6 --- /dev/null +++ b/seb4itik/byow/plugins/README.md @@ -0,0 +1,31 @@ +# Collections Plugins Directory + +This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that +is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that +would contain module utils and modules respectively. + +Here is an example directory of the majority of plugins currently supported by Ansible: + +``` +└── plugins + ├── action + ├── become + ├── cache + ├── callback + ├── cliconf + ├── connection + ├── filter + ├── httpapi + ├── inventory + ├── lookup + ├── module_utils + ├── modules + ├── netconf + ├── shell + ├── strategy + ├── terminal + ├── test + └── vars +``` + +A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.19/plugins/plugins.html). diff --git a/seb4itik/byow/roles/caddy/README.md b/seb4itik/byow/roles/caddy/README.md new file mode 100644 index 0000000..5e801db --- /dev/null +++ b/seb4itik/byow/roles/caddy/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Caddy diff --git a/roles/caddy/defaults/main.yml b/seb4itik/byow/roles/caddy/defaults/main.yml similarity index 100% rename from roles/caddy/defaults/main.yml rename to seb4itik/byow/roles/caddy/defaults/main.yml diff --git a/roles/caddy/files/bot_barrier_template.html b/seb4itik/byow/roles/caddy/files/bot_barrier_template.html similarity index 100% rename from roles/caddy/files/bot_barrier_template.html rename to seb4itik/byow/roles/caddy/files/bot_barrier_template.html diff --git a/roles/caddy/filter_plugins/filters.py b/seb4itik/byow/roles/caddy/filter_plugins/filters.py similarity index 100% rename from roles/caddy/filter_plugins/filters.py rename to seb4itik/byow/roles/caddy/filter_plugins/filters.py diff --git a/roles/caddy/handlers/main.yml b/seb4itik/byow/roles/caddy/handlers/main.yml similarity index 100% rename from roles/caddy/handlers/main.yml rename to seb4itik/byow/roles/caddy/handlers/main.yml diff --git a/roles/caddy/tasks/caddy_config.yml b/seb4itik/byow/roles/caddy/tasks/caddy_config.yml similarity index 100% rename from roles/caddy/tasks/caddy_config.yml rename to seb4itik/byow/roles/caddy/tasks/caddy_config.yml diff --git a/roles/caddy/tasks/caddy_install.yml b/seb4itik/byow/roles/caddy/tasks/caddy_install.yml similarity index 100% rename from roles/caddy/tasks/caddy_install.yml rename to seb4itik/byow/roles/caddy/tasks/caddy_install.yml diff --git a/roles/caddy/tasks/main.yml b/seb4itik/byow/roles/caddy/tasks/main.yml similarity index 100% rename from roles/caddy/tasks/main.yml rename to seb4itik/byow/roles/caddy/tasks/main.yml diff --git a/roles/caddy/tasks/plugin_install.yml b/seb4itik/byow/roles/caddy/tasks/plugin_install.yml similarity index 100% rename from roles/caddy/tasks/plugin_install.yml rename to seb4itik/byow/roles/caddy/tasks/plugin_install.yml diff --git a/roles/caddy/templates/Caddyfile b/seb4itik/byow/roles/caddy/templates/Caddyfile similarity index 100% rename from roles/caddy/templates/Caddyfile rename to seb4itik/byow/roles/caddy/templates/Caddyfile diff --git a/roles/caddy/templates/caddy.service b/seb4itik/byow/roles/caddy/templates/caddy.service similarity index 100% rename from roles/caddy/templates/caddy.service rename to seb4itik/byow/roles/caddy/templates/caddy.service diff --git a/roles/caddy/templates/coraza.conf b/seb4itik/byow/roles/caddy/templates/coraza.conf similarity index 100% rename from roles/caddy/templates/coraza.conf rename to seb4itik/byow/roles/caddy/templates/coraza.conf diff --git a/roles/caddy/templates/crs-setup.conf b/seb4itik/byow/roles/caddy/templates/crs-setup.conf similarity index 100% rename from roles/caddy/templates/crs-setup.conf rename to seb4itik/byow/roles/caddy/templates/crs-setup.conf diff --git a/roles/caddy/templates/exclusions-request-before.conf b/seb4itik/byow/roles/caddy/templates/exclusions-request-before.conf similarity index 100% rename from roles/caddy/templates/exclusions-request-before.conf rename to seb4itik/byow/roles/caddy/templates/exclusions-request-before.conf diff --git a/roles/caddy/templates/exclusions-response-after.conf b/seb4itik/byow/roles/caddy/templates/exclusions-response-after.conf similarity index 100% rename from roles/caddy/templates/exclusions-response-after.conf rename to seb4itik/byow/roles/caddy/templates/exclusions-response-after.conf diff --git a/roles/caddy/vars/main.yml b/seb4itik/byow/roles/caddy/vars/main.yml similarity index 100% rename from roles/caddy/vars/main.yml rename to seb4itik/byow/roles/caddy/vars/main.yml diff --git a/seb4itik/byow/roles/common/README.md b/seb4itik/byow/roles/common/README.md new file mode 100644 index 0000000..ff975e7 --- /dev/null +++ b/seb4itik/byow/roles/common/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Common diff --git a/roles/common/defaults/main.yml b/seb4itik/byow/roles/common/defaults/main.yml similarity index 100% rename from roles/common/defaults/main.yml rename to seb4itik/byow/roles/common/defaults/main.yml diff --git a/roles/common/tasks/main.yml b/seb4itik/byow/roles/common/tasks/main.yml similarity index 100% rename from roles/common/tasks/main.yml rename to seb4itik/byow/roles/common/tasks/main.yml diff --git a/roles/common/tasks/setup_packages.yml b/seb4itik/byow/roles/common/tasks/setup_packages.yml similarity index 100% rename from roles/common/tasks/setup_packages.yml rename to seb4itik/byow/roles/common/tasks/setup_packages.yml diff --git a/roles/common/tasks/setup_proxy_client.yml b/seb4itik/byow/roles/common/tasks/setup_proxy_client.yml similarity index 100% rename from roles/common/tasks/setup_proxy_client.yml rename to seb4itik/byow/roles/common/tasks/setup_proxy_client.yml diff --git a/roles/common/templates/apt_proxy.conf b/seb4itik/byow/roles/common/templates/apt_proxy.conf similarity index 100% rename from roles/common/templates/apt_proxy.conf rename to seb4itik/byow/roles/common/templates/apt_proxy.conf diff --git a/seb4itik/byow/roles/consul/README.md b/seb4itik/byow/roles/consul/README.md new file mode 100644 index 0000000..4b429ec --- /dev/null +++ b/seb4itik/byow/roles/consul/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Consul diff --git a/roles/consul/defaults/main.yml b/seb4itik/byow/roles/consul/defaults/main.yml similarity index 100% rename from roles/consul/defaults/main.yml rename to seb4itik/byow/roles/consul/defaults/main.yml diff --git a/roles/consul/handlers/main.yml b/seb4itik/byow/roles/consul/handlers/main.yml similarity index 100% rename from roles/consul/handlers/main.yml rename to seb4itik/byow/roles/consul/handlers/main.yml diff --git a/roles/consul/tasks/main.yml b/seb4itik/byow/roles/consul/tasks/main.yml similarity index 100% rename from roles/consul/tasks/main.yml rename to seb4itik/byow/roles/consul/tasks/main.yml diff --git a/roles/consul/templates/config.json b/seb4itik/byow/roles/consul/templates/config.json similarity index 100% rename from roles/consul/templates/config.json rename to seb4itik/byow/roles/consul/templates/config.json diff --git a/roles/consul/templates/consul.service b/seb4itik/byow/roles/consul/templates/consul.service similarity index 100% rename from roles/consul/templates/consul.service rename to seb4itik/byow/roles/consul/templates/consul.service diff --git a/seb4itik/byow/roles/keepalived/README.md b/seb4itik/byow/roles/keepalived/README.md new file mode 100644 index 0000000..e61f8d7 --- /dev/null +++ b/seb4itik/byow/roles/keepalived/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Keepalived diff --git a/roles/keepalived/defaults/main.yml b/seb4itik/byow/roles/keepalived/defaults/main.yml similarity index 100% rename from roles/keepalived/defaults/main.yml rename to seb4itik/byow/roles/keepalived/defaults/main.yml diff --git a/roles/keepalived/handlers/main.yml b/seb4itik/byow/roles/keepalived/handlers/main.yml similarity index 100% rename from roles/keepalived/handlers/main.yml rename to seb4itik/byow/roles/keepalived/handlers/main.yml diff --git a/roles/keepalived/tasks/main.yml b/seb4itik/byow/roles/keepalived/tasks/main.yml similarity index 100% rename from roles/keepalived/tasks/main.yml rename to seb4itik/byow/roles/keepalived/tasks/main.yml diff --git a/roles/keepalived/templates/keepalived.conf b/seb4itik/byow/roles/keepalived/templates/keepalived.conf similarity index 100% rename from roles/keepalived/templates/keepalived.conf rename to seb4itik/byow/roles/keepalived/templates/keepalived.conf diff --git a/seb4itik/byow/roles/local_ca/README.md b/seb4itik/byow/roles/local_ca/README.md new file mode 100644 index 0000000..5db9962 --- /dev/null +++ b/seb4itik/byow/roles/local_ca/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Local CA diff --git a/roles/local_ca/defaults/main.yml b/seb4itik/byow/roles/local_ca/defaults/main.yml similarity index 100% rename from roles/local_ca/defaults/main.yml rename to seb4itik/byow/roles/local_ca/defaults/main.yml diff --git a/roles/local_ca/tasks/main.yml b/seb4itik/byow/roles/local_ca/tasks/main.yml similarity index 100% rename from roles/local_ca/tasks/main.yml rename to seb4itik/byow/roles/local_ca/tasks/main.yml diff --git a/seb4itik/byow/roles/local_ca_certs/README.md b/seb4itik/byow/roles/local_ca_certs/README.md new file mode 100644 index 0000000..153d0f9 --- /dev/null +++ b/seb4itik/byow/roles/local_ca_certs/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Local CA certificates diff --git a/roles/local_ca_certs/defaults/main.yml b/seb4itik/byow/roles/local_ca_certs/defaults/main.yml similarity index 100% rename from roles/local_ca_certs/defaults/main.yml rename to seb4itik/byow/roles/local_ca_certs/defaults/main.yml diff --git a/roles/local_ca_certs/handlers/main.yml b/seb4itik/byow/roles/local_ca_certs/handlers/main.yml similarity index 100% rename from roles/local_ca_certs/handlers/main.yml rename to seb4itik/byow/roles/local_ca_certs/handlers/main.yml diff --git a/roles/local_ca_certs/tasks/create_cert.yml b/seb4itik/byow/roles/local_ca_certs/tasks/create_cert.yml similarity index 100% rename from roles/local_ca_certs/tasks/create_cert.yml rename to seb4itik/byow/roles/local_ca_certs/tasks/create_cert.yml diff --git a/roles/local_ca_certs/tasks/main.yml b/seb4itik/byow/roles/local_ca_certs/tasks/main.yml similarity index 100% rename from roles/local_ca_certs/tasks/main.yml rename to seb4itik/byow/roles/local_ca_certs/tasks/main.yml diff --git a/seb4itik/byow/roles/mysql/README.md b/seb4itik/byow/roles/mysql/README.md new file mode 100644 index 0000000..ce77f7f --- /dev/null +++ b/seb4itik/byow/roles/mysql/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## MySQL diff --git a/roles/mysql/defaults/main.yml b/seb4itik/byow/roles/mysql/defaults/main.yml similarity index 100% rename from roles/mysql/defaults/main.yml rename to seb4itik/byow/roles/mysql/defaults/main.yml diff --git a/roles/mysql/handlers/main.yml b/seb4itik/byow/roles/mysql/handlers/main.yml similarity index 100% rename from roles/mysql/handlers/main.yml rename to seb4itik/byow/roles/mysql/handlers/main.yml diff --git a/roles/mysql/tasks/main.yml b/seb4itik/byow/roles/mysql/tasks/main.yml similarity index 100% rename from roles/mysql/tasks/main.yml rename to seb4itik/byow/roles/mysql/tasks/main.yml diff --git a/seb4itik/byow/roles/nfs_client/README.md b/seb4itik/byow/roles/nfs_client/README.md new file mode 100644 index 0000000..95c1748 --- /dev/null +++ b/seb4itik/byow/roles/nfs_client/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## NFS client diff --git a/roles/nfs_client/defaults/main.yml b/seb4itik/byow/roles/nfs_client/defaults/main.yml similarity index 100% rename from roles/nfs_client/defaults/main.yml rename to seb4itik/byow/roles/nfs_client/defaults/main.yml diff --git a/roles/nfs_client/tasks/main.yml b/seb4itik/byow/roles/nfs_client/tasks/main.yml similarity index 100% rename from roles/nfs_client/tasks/main.yml rename to seb4itik/byow/roles/nfs_client/tasks/main.yml diff --git a/seb4itik/byow/roles/nfs_server/README.md b/seb4itik/byow/roles/nfs_server/README.md new file mode 100644 index 0000000..4de2fc1 --- /dev/null +++ b/seb4itik/byow/roles/nfs_server/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## NFS Server diff --git a/roles/nfs_server/defaults/main.yml b/seb4itik/byow/roles/nfs_server/defaults/main.yml similarity index 100% rename from roles/nfs_server/defaults/main.yml rename to seb4itik/byow/roles/nfs_server/defaults/main.yml diff --git a/roles/nfs_server/handlers/main.yml b/seb4itik/byow/roles/nfs_server/handlers/main.yml similarity index 100% rename from roles/nfs_server/handlers/main.yml rename to seb4itik/byow/roles/nfs_server/handlers/main.yml diff --git a/roles/nfs_server/tasks/main.yml b/seb4itik/byow/roles/nfs_server/tasks/main.yml similarity index 100% rename from roles/nfs_server/tasks/main.yml rename to seb4itik/byow/roles/nfs_server/tasks/main.yml diff --git a/roles/nfs_server/templates/exports b/seb4itik/byow/roles/nfs_server/templates/exports similarity index 100% rename from roles/nfs_server/templates/exports rename to seb4itik/byow/roles/nfs_server/templates/exports diff --git a/seb4itik/byow/roles/ovh_ldp/README.md b/seb4itik/byow/roles/ovh_ldp/README.md new file mode 100644 index 0000000..1dd2e2d --- /dev/null +++ b/seb4itik/byow/roles/ovh_ldp/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## OVH Log Data Platform diff --git a/roles/ovh_ldp/defaults/main.yml b/seb4itik/byow/roles/ovh_ldp/defaults/main.yml similarity index 100% rename from roles/ovh_ldp/defaults/main.yml rename to seb4itik/byow/roles/ovh_ldp/defaults/main.yml diff --git a/roles/ovh_ldp/handlers/main.yml b/seb4itik/byow/roles/ovh_ldp/handlers/main.yml similarity index 100% rename from roles/ovh_ldp/handlers/main.yml rename to seb4itik/byow/roles/ovh_ldp/handlers/main.yml diff --git a/roles/ovh_ldp/tasks/main.yml b/seb4itik/byow/roles/ovh_ldp/tasks/main.yml similarity index 100% rename from roles/ovh_ldp/tasks/main.yml rename to seb4itik/byow/roles/ovh_ldp/tasks/main.yml diff --git a/roles/ovh_ldp/templates/ldp-ovh.conf b/seb4itik/byow/roles/ovh_ldp/templates/ldp-ovh.conf similarity index 100% rename from roles/ovh_ldp/templates/ldp-ovh.conf rename to seb4itik/byow/roles/ovh_ldp/templates/ldp-ovh.conf diff --git a/seb4itik/byow/roles/unbound/README.md b/seb4itik/byow/roles/unbound/README.md new file mode 100644 index 0000000..8ac12cc --- /dev/null +++ b/seb4itik/byow/roles/unbound/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Unbound diff --git a/roles/unbound/defaults/main.yml b/seb4itik/byow/roles/unbound/defaults/main.yml similarity index 100% rename from roles/unbound/defaults/main.yml rename to seb4itik/byow/roles/unbound/defaults/main.yml diff --git a/roles/unbound/handlers/main.yml b/seb4itik/byow/roles/unbound/handlers/main.yml similarity index 100% rename from roles/unbound/handlers/main.yml rename to seb4itik/byow/roles/unbound/handlers/main.yml diff --git a/roles/unbound/tasks/main.yml b/seb4itik/byow/roles/unbound/tasks/main.yml similarity index 100% rename from roles/unbound/tasks/main.yml rename to seb4itik/byow/roles/unbound/tasks/main.yml diff --git a/roles/unbound/templates/unbound.conf b/seb4itik/byow/roles/unbound/templates/unbound.conf similarity index 100% rename from roles/unbound/templates/unbound.conf rename to seb4itik/byow/roles/unbound/templates/unbound.conf diff --git a/seb4itik/byow/roles/wordpress/README.md b/seb4itik/byow/roles/wordpress/README.md new file mode 100644 index 0000000..4e64afb --- /dev/null +++ b/seb4itik/byow/roles/wordpress/README.md @@ -0,0 +1,5 @@ +# BYOW - Build Your Own WAF + +A WAF _à la carte_. + +## Wordpress diff --git a/roles/wordpress/defaults/main.yml b/seb4itik/byow/roles/wordpress/defaults/main.yml similarity index 100% rename from roles/wordpress/defaults/main.yml rename to seb4itik/byow/roles/wordpress/defaults/main.yml diff --git a/roles/wordpress/handlers/main.yml b/seb4itik/byow/roles/wordpress/handlers/main.yml similarity index 100% rename from roles/wordpress/handlers/main.yml rename to seb4itik/byow/roles/wordpress/handlers/main.yml diff --git a/roles/wordpress/tasks/install_plugins.yml b/seb4itik/byow/roles/wordpress/tasks/install_plugins.yml similarity index 100% rename from roles/wordpress/tasks/install_plugins.yml rename to seb4itik/byow/roles/wordpress/tasks/install_plugins.yml diff --git a/roles/wordpress/tasks/main.yml b/seb4itik/byow/roles/wordpress/tasks/main.yml similarity index 100% rename from roles/wordpress/tasks/main.yml rename to seb4itik/byow/roles/wordpress/tasks/main.yml diff --git a/roles/wordpress/templates/nginx_vhost.conf b/seb4itik/byow/roles/wordpress/templates/nginx_vhost.conf similarity index 100% rename from roles/wordpress/templates/nginx_vhost.conf rename to seb4itik/byow/roles/wordpress/templates/nginx_vhost.conf diff --git a/seb4itik/byow/seb4itik-byow-0.1.0.tar.gz b/seb4itik/byow/seb4itik-byow-0.1.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..b39e09d41953814ec02b1d8314f863d57af08921 GIT binary patch literal 33683 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