First commit
This commit is contained in:
1
ansible/roles/bgwaf/.gitignore
vendored
Normal file
1
ansible/roles/bgwaf/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/docs/
|
||||
146
ansible/roles/bgwaf/README.md
Normal file
146
ansible/roles/bgwaf/README.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Web Application Firewall
|
||||
|
||||
Ce rôle Ansible déploie un WAF basé sur Caddy, Coraza et les OWASP Core Security Rules.
|
||||
|
||||
## 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:
|
||||
|
||||
- Multisite (cavec configuration des CRS par site)
|
||||
- Redirection vers nom canonique
|
||||
- Rediction HTTP vers HTTPS
|
||||
- Certificats SSL (autmotiques via Let's Encrypt et customs)
|
||||
- OWASP CRS
|
||||
- Redirect (SSL et www et autres)
|
||||
- Filtrage 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
|
||||
- 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
|
||||
- X-Frame-Options
|
||||
- X-Content-Type-Options
|
||||
- Referrer Policy
|
||||
- Permissions Policy
|
||||
- Keep Headers
|
||||
- Cookie Flags
|
||||
- Custom headers
|
||||
- Reverse scan
|
||||
- Robots.txt (DarkVisitors API/Community Lists/Custom URLs/Manual Rules)
|
||||
- Sessions
|
||||
- Whitelist
|
||||
- Bad behavior
|
||||
- Auth
|
||||
- Anti DoDS
|
||||
- Greylist
|
||||
- HTML injection
|
||||
- Metrics (Elasticsearch + Metabase)
|
||||
- Static files et FastCGI pour PHP
|
||||
|
||||
|
||||
## 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/)
|
||||
|
||||
Modules
|
||||
- []()
|
||||
- []()
|
||||
63
ansible/roles/bgwaf/defaults/main.yml
Normal file
63
ansible/roles/bgwaf/defaults/main.yml
Normal file
@@ -0,0 +1,63 @@
|
||||
bgwaf_go_version: "1.25.5"
|
||||
bgwaf_xcaddy_version: "0.4.5"
|
||||
bgwaf_caddy_version: "2.10.2"
|
||||
bgwaf_coraza_caddy_version: "2.1.0" # Coraza v3.3.3
|
||||
bgwaf_owasp_crs_version: "4.21.0"
|
||||
|
||||
# Cluster mode (e.g. with consul)
|
||||
bgwaf_cluster: false
|
||||
|
||||
# Required unless not site.custom_cert
|
||||
bgwaf_email: null
|
||||
|
||||
# Required if site.bot_barrier
|
||||
bgwaf_bot_barrier_secret: null
|
||||
|
||||
# Optionnal
|
||||
bgwaf_local_ca_name: null
|
||||
bgwaf_ca_root: null
|
||||
|
||||
# Cf.: https://github.com/coreruleset/plugin-registry
|
||||
bgwaf_crs_plugins:
|
||||
- name: "drupal-rule-exclusions"
|
||||
version: "1.0.0"
|
||||
- name: "wordpress-rule-exclusions"
|
||||
version: "1.2.0"
|
||||
- name: "nextcloud-rule-exclusions"
|
||||
version: "1.5.0"
|
||||
- name: "dokuwiki-rule-exclusions"
|
||||
version: "1.0.0"
|
||||
- name: "phpmyadmin-rule-exclusions"
|
||||
version: "1.0.0"
|
||||
- name: "roundcube-rule-exclusions"
|
||||
version: "1.0.4"
|
||||
provider: "EsadCetiner"
|
||||
- name: "sogo-rule-exclusions"
|
||||
version: "1.0.4"
|
||||
provider: "EsadCetiner"
|
||||
|
||||
bgwaf_sites: []
|
||||
# - name: ""
|
||||
# site: ""
|
||||
# paths:
|
||||
# - path: "*"
|
||||
# addrs:
|
||||
# - ""
|
||||
# blacklist:
|
||||
# - ""
|
||||
# aliases:
|
||||
# - ""
|
||||
# plugins: FIXME:TODO
|
||||
# - ""
|
||||
# exceptions:
|
||||
# before_request:
|
||||
# - ""
|
||||
# after_response:
|
||||
# - ""
|
||||
# redirect_from_aliases: true
|
||||
# custom_cert: true
|
||||
# custom_cert_file: ""
|
||||
# custom_key_file: ""
|
||||
# rate_events: 1000
|
||||
# rate_window: "1m"
|
||||
# bot_barrier: false
|
||||
71
ansible/roles/bgwaf/files/bot_barrier_template.html
Normal file
71
ansible/roles/bgwaf/files/bot_barrier_template.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Security Check</title>
|
||||
<style nonce="{{ .CSPNonce }}">
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f9;
|
||||
color: #333;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.4em 0 0.3em;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin: 2em 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 5px solid #ccc;
|
||||
border-top: 5px solid #333;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- English Section -->
|
||||
<h1>Just a moment...</h1>
|
||||
<p>A small mathematical challenge is running<br>
|
||||
in the background - fully automatic to confirm<br>
|
||||
you're not a bot 🔒.</p>
|
||||
|
||||
<!-- Spinner -->
|
||||
<div class="spinner"></div>
|
||||
|
||||
<p>⏳ You'll be redirected shortly.</p>
|
||||
</div>
|
||||
|
||||
<script nonce="{{ .CSPNonce }}">{{ .Script }}</script>
|
||||
</body>
|
||||
</html>
|
||||
10
ansible/roles/bgwaf/handlers/main.yml
Normal file
10
ansible/roles/bgwaf/handlers/main.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
- name: Restart Caddy
|
||||
ansible.builtin.service:
|
||||
name: "caddy"
|
||||
state: "restarted"
|
||||
daemon_reload: true
|
||||
|
||||
- name: Reload Caddy
|
||||
ansible.builtin.service:
|
||||
name: "caddy"
|
||||
state: "reloaded"
|
||||
47
ansible/roles/bgwaf/tasks/install_plugin.yml
Normal file
47
ansible/roles/bgwaf/tasks/install_plugin.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
- name: Download plugin {{ plugin.name }}
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/{{ plugin.provider | default('coreruleset') }}/{{ plugin.name }}-plugin/archive/refs/tags/v{{ plugin.version }}.tar.gz"
|
||||
dest: "/usr/local/src/"
|
||||
mode: "0644"
|
||||
register: "bgwaf_plugin_downloaded"
|
||||
|
||||
- name: Deploy plugin {{ plugin.name }}
|
||||
# noqa: no-handler
|
||||
when: "bgwaf_plugin_downloaded.changed"
|
||||
block:
|
||||
|
||||
- name: Get temp dir {{ plugin.name }}
|
||||
ansible.builtin.tempfile:
|
||||
state: "directory"
|
||||
register: "bgwaf_temp_plugin_dir"
|
||||
|
||||
- name: Unarchive plugin {{ plugin.name }}
|
||||
ansible.builtin.unarchive:
|
||||
src: "/usr/local/src/{{ plugin.name }}-plugin-{{ plugin.version }}.tar.gz"
|
||||
dest: "{{ bgwaf_temp_plugin_dir.path }}"
|
||||
remote_src: true
|
||||
|
||||
- name: Copy plugin files {{ plugin.name }}
|
||||
ansible.builtin.copy:
|
||||
src: "{{ bgwaf_temp_plugin_dir.path }}/{{ plugin.name }}-plugin-{{ plugin.version }}/plugins/"
|
||||
dest: "/etc/caddy/plugins/"
|
||||
mode: "0644"
|
||||
# directory_mode: "0750"
|
||||
group: "caddy"
|
||||
remote_src: true
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
# FIXME: bad hack, why is it required?
|
||||
- name: Adjust /etc/caddy/plugins permissions
|
||||
ansible.builtin.file:
|
||||
path: "/etc/caddy/plugins"
|
||||
state: "directory"
|
||||
group: "caddy"
|
||||
mode: "0750"
|
||||
|
||||
- name: Delete temp dir {{ plugin.name }}
|
||||
when: "bgwaf_temp_plugin_dir.path is defined"
|
||||
ansible.builtin.file:
|
||||
path: "{{ bgwaf_temp_plugin_dir.path }}"
|
||||
state: "absent"
|
||||
201
ansible/roles/bgwaf/tasks/main.yml
Normal file
201
ansible/roles/bgwaf/tasks/main.yml
Normal file
@@ -0,0 +1,201 @@
|
||||
- name: Remove packaged Go
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "golang"
|
||||
state: "absent"
|
||||
autoremove: true
|
||||
purge: true
|
||||
|
||||
- name: Install requirements
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "git"
|
||||
- "libnss3-tools"
|
||||
|
||||
- name: Create Go directory
|
||||
ansible.builtin.file:
|
||||
path: "/usr/local/go-{{ bgwaf_go_version }}"
|
||||
state: "directory"
|
||||
mode: "0755"
|
||||
|
||||
- name: Install Go
|
||||
ansible.builtin.unarchive:
|
||||
src: "https://go.dev/dl/go{{ bgwaf_go_version }}.linux-amd64.tar.gz"
|
||||
dest: "/usr/local/go-{{ bgwaf_go_version }}"
|
||||
remote_src: true
|
||||
|
||||
- name: Link Go
|
||||
ansible.builtin.file:
|
||||
src: "/usr/local/go-{{ bgwaf_go_version }}/go/bin/go"
|
||||
dest: "/usr/local/bin/go"
|
||||
state: "link"
|
||||
|
||||
- name: Install xcaddy
|
||||
when: |
|
||||
'xcaddy' not in ansible_facts.packages
|
||||
or ansible_facts.packages['xcaddy'][0]['version'] != bgwaf_xcaddy_version
|
||||
ansible.builtin.apt:
|
||||
deb: "{{ bgwaf_xcaddy_download }}/v{{ bgwaf_xcaddy_version }}/xcaddy_{{ bgwaf_xcaddy_version }}_linux_amd64.deb"
|
||||
force: true
|
||||
|
||||
- name: Create Caddy build command
|
||||
ansible.builtin.set_fact:
|
||||
bgwaf_build_command: >
|
||||
xcaddy build v{{ bgwaf_caddy_version }}
|
||||
{% if bgwaf_cluster %} --with github.com/pteich/caddy-tlsconsul{% endif %}
|
||||
--with github.com/corazawaf/coraza-caddy/v2@v{{ bgwaf_coraza_caddy_version }}
|
||||
--with github.com/mholt/caddy-ratelimit
|
||||
--with github.com/steffenbusch/caddy-bot-barrier
|
||||
--output /usr/local/bin/caddy
|
||||
|
||||
- name: Test Caddy version
|
||||
ansible.builtin.copy:
|
||||
dest: "/usr/local/bin/.caddy.build"
|
||||
content: "{{ bgwaf_build_command }}"
|
||||
mode: "0644"
|
||||
register: bgwaf_test_caddy_version
|
||||
|
||||
- name: Build Caddy
|
||||
# noqa: no-handler
|
||||
when: "bgwaf_test_caddy_version.changed"
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ bgwaf_build_command }}"
|
||||
creates: "/usr/local/bin/caddy"
|
||||
notify:
|
||||
- "Restart Caddy"
|
||||
|
||||
- name: Create caddy system group
|
||||
ansible.builtin.group:
|
||||
name: "caddy"
|
||||
system: true
|
||||
|
||||
- name: Create caddy system user
|
||||
ansible.builtin.user:
|
||||
name: "caddy"
|
||||
group: "caddy"
|
||||
groups: ["ssl-cert"]
|
||||
password: "!"
|
||||
system: true
|
||||
home: "/opt/caddy"
|
||||
|
||||
- name: Create caddy config directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: "directory"
|
||||
group: "caddy"
|
||||
mode: "0750"
|
||||
loop:
|
||||
- "/etc/caddy"
|
||||
- "/etc/caddy/plugins"
|
||||
- "/etc/caddy/sites"
|
||||
|
||||
- name: Create caddy log dir
|
||||
ansible.builtin.file:
|
||||
path: "/var/log/caddy"
|
||||
state: "directory"
|
||||
group: "caddy"
|
||||
mode: "0770"
|
||||
|
||||
- name: Install OWASP CRS
|
||||
ansible.builtin.unarchive:
|
||||
src: "https://github.com/coreruleset/coreruleset/archive/refs/tags/v{{ bgwaf_owasp_crs_version }}.tar.gz"
|
||||
dest: "/etc/caddy"
|
||||
group: "caddy"
|
||||
remote_src: true
|
||||
|
||||
- name: Install plugins
|
||||
loop: "{{ bgwaf_crs_plugins }}"
|
||||
loop_control:
|
||||
loop_var: "plugin"
|
||||
ansible.builtin.include_tasks: "install_plugin.yml"
|
||||
|
||||
- name: Create sites config directories
|
||||
loop: "{{ bgwaf_sites }}"
|
||||
loop_control:
|
||||
loop_var: "site"
|
||||
ansible.builtin.file:
|
||||
path: "/etc/caddy/sites/{{ site.name }}"
|
||||
state: "directory"
|
||||
group: "caddy"
|
||||
mode: "0750"
|
||||
|
||||
- name: Generate sites coraza.conf config file
|
||||
loop: "{{ bgwaf_sites }}"
|
||||
loop_control:
|
||||
loop_var: "site"
|
||||
ansible.builtin.template:
|
||||
src: "templates/coraza.conf"
|
||||
dest: "/etc/caddy/sites/{{ site.name }}/coraza.conf"
|
||||
group: "caddy"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
- name: Generate sites crs-setup config file
|
||||
loop: "{{ bgwaf_sites }}"
|
||||
loop_control:
|
||||
loop_var: "site"
|
||||
ansible.builtin.template:
|
||||
src: "templates/crs-setup.conf"
|
||||
dest: "/etc/caddy/sites/{{ site.name }}/crs-setup.conf"
|
||||
group: "caddy"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
- name: Generate sites exclusions before request file
|
||||
loop: "{{ bgwaf_sites }}"
|
||||
vars:
|
||||
bgwaf_site_exclusions: "{{ item.exceptions.before_request | default([]) }}"
|
||||
ansible.builtin.template:
|
||||
src: "templates/exclusions.conf"
|
||||
dest: "/etc/caddy/sites/{{ item.name }}/exclusions-request-before.conf"
|
||||
group: "caddy"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
- name: Generate sites exclusions after response file
|
||||
loop: "{{ bgwaf_sites }}"
|
||||
vars:
|
||||
bgwaf_site_exclusions: "{{ item.exceptions.after_response | default([]) }}"
|
||||
ansible.builtin.template:
|
||||
src: "templates/exclusions.conf"
|
||||
dest: "/etc/caddy/sites/{{ item.name }}/exclusions-response-after.conf"
|
||||
group: "caddy"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
- name: Generate Caddyfile
|
||||
ansible.builtin.template:
|
||||
src: "templates/Caddyfile"
|
||||
dest: "/etc/caddy/Caddyfile"
|
||||
group: "caddy"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
- name: Copy bot barrier template
|
||||
ansible.builtin.copy:
|
||||
src: "files/bot_barrier_template.html"
|
||||
dest: "/etc/caddy/bot_barrier_template.html"
|
||||
group: "caddy"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Caddy"
|
||||
|
||||
- name: Deploy caddy service file
|
||||
ansible.builtin.template:
|
||||
src: "templates/caddy.service"
|
||||
dest: "/etc/systemd/system/caddy.service"
|
||||
mode: "0644"
|
||||
notify:
|
||||
- "Restart Caddy"
|
||||
|
||||
- name: Enable and start Caddy
|
||||
ansible.builtin.service:
|
||||
name: "caddy"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
127
ansible/roles/bgwaf/templates/Caddyfile
Normal file
127
ansible/roles/bgwaf/templates/Caddyfile
Normal file
@@ -0,0 +1,127 @@
|
||||
{
|
||||
# storage redis
|
||||
grace_period 10s
|
||||
order coraza_waf first
|
||||
{% if bgwaf_email | default(None) != None %}
|
||||
email "{{ bgwaf_email }}"
|
||||
{% endif %}
|
||||
|
||||
{% if bgwaf_ca_root | default(None) != None %}
|
||||
tls {
|
||||
ca_root "{{ bgwaf_ca_root }}"
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
log waf {
|
||||
format json
|
||||
include "http.handlers.waf"
|
||||
output file /var/log/caddy/waf.log
|
||||
}
|
||||
{% if bgwaf_local_ca_name | default(None) != None %}
|
||||
|
||||
pki {
|
||||
ca local {
|
||||
name "{{ bgwaf_local_ca_name }}"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% for site in bgwaf_sites %}
|
||||
{% if (site.redirect_from_aliases | default(true)) and (site.aliases | default([]) | length) > 0 %}
|
||||
{{ site.aliases | join(', ') }} {
|
||||
redir https://{{ site.site }}{uri}
|
||||
}
|
||||
|
||||
{% else %}
|
||||
{% for alias in site.aliases | default([]) %}
|
||||
{{ alias }},
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{{ site.site }} {
|
||||
encode gzip zstd
|
||||
|
||||
{% for path in site.paths %}
|
||||
handle {{ path.path | default('*') }} {
|
||||
reverse_proxy {
|
||||
to {{ path.addrs | join(' ') }}
|
||||
header_up X-Real-IP {remote}
|
||||
lb_policy ip_hash
|
||||
# Active checks
|
||||
# health_uri /
|
||||
# health_interval 10s
|
||||
# health_timeout 5s
|
||||
# health_status 200
|
||||
# Passive checks
|
||||
fail_duration 30s
|
||||
max_fails 3
|
||||
unhealthy_latency 2000ms
|
||||
transport http {
|
||||
# tls_server_name {host}
|
||||
# tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
{% if site.custom_cert | default (false) %}
|
||||
tls {{ site.custom_cert_file }} {{ site.custom_key_file }}
|
||||
|
||||
{% endif %}
|
||||
{% if site.blacklist | default([]) | length > 0 %}
|
||||
@blocked {
|
||||
{% for ip in site.blacklist | default([]) %}
|
||||
remote_ip {{ ip }}
|
||||
{% endfor %}
|
||||
}
|
||||
respond @blocked "Access Denied" 403
|
||||
|
||||
{% endif %}
|
||||
{% if site.bot_barrier | default (false) %}
|
||||
bot_barrier {
|
||||
secret {{ bgwaf_bot_barrier_secret }}
|
||||
complexity 18
|
||||
valid_for 30m
|
||||
seed_cookie_name __chall_{{ site.name }}_seed
|
||||
solution_cookie_name __chall_{{ site.name }}_solution
|
||||
mac_cookie_name __chall_{{ site.name }}_mac
|
||||
template /etc/caddy/bot_barrier_template.html
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
rate_limit {
|
||||
# distributed
|
||||
zone remote_ip {
|
||||
key {remote.ip}
|
||||
events {{ site.rate_events | default('1000') }}
|
||||
window {{ site.rate_window | default('1m') }}
|
||||
}
|
||||
}
|
||||
|
||||
coraza_waf {
|
||||
load_owasp_crs
|
||||
directives `
|
||||
Include "/etc/caddy/sites/{{ site.name }}/coraza.conf"
|
||||
Include "/etc/caddy/sites/{{ site.name }}/crs-setup.conf"
|
||||
Include "/etc/caddy/plugins/*-config.conf"
|
||||
Include "/etc/caddy/plugins/*-before.conf"
|
||||
Include "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
||||
Include "/etc/caddy/coreruleset-{{ bgwaf_owasp_crs_version }}/rules/*.conf"
|
||||
Include "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
||||
Include "/etc/caddy/plugins/*-after.conf"
|
||||
SecRuleEngine On
|
||||
`
|
||||
}
|
||||
|
||||
handle_errors 403 {
|
||||
header X-Blocked "true"
|
||||
respond "Your request was blocked."
|
||||
}
|
||||
|
||||
log {
|
||||
format json
|
||||
output file /var/log/caddy/site_{{ site.name }}.log
|
||||
}
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
20
ansible/roles/bgwaf/templates/caddy.service
Normal file
20
ansible/roles/bgwaf/templates/caddy.service
Normal file
@@ -0,0 +1,20 @@
|
||||
[Unit]
|
||||
Description=Caddy
|
||||
Documentation=https://caddyserver.com/docs/
|
||||
After=network.target network-online.target
|
||||
Requires=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
User=caddy
|
||||
Group=caddy
|
||||
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
|
||||
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --force
|
||||
TimeoutStopSec=15s
|
||||
LimitNOFILE=1048576
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
158
ansible/roles/bgwaf/templates/coraza.conf
Normal file
158
ansible/roles/bgwaf/templates/coraza.conf
Normal file
@@ -0,0 +1,158 @@
|
||||
# -- Rule engine initialization ----------------------------------------------
|
||||
|
||||
# Enable Coraza, attaching it to every transaction. Use detection
|
||||
# only to start with, because that minimises the chances of post-installation
|
||||
# disruption.
|
||||
SecRuleEngine DetectionOnly
|
||||
|
||||
|
||||
# -- Request body handling ---------------------------------------------------
|
||||
|
||||
# Allow Coraza to access request bodies. If you don't, Coraza
|
||||
# won't be able to see any POST parameters, which opens a large security
|
||||
# hole for attackers to exploit.
|
||||
SecRequestBodyAccess On
|
||||
|
||||
# Enable XML request body parser.
|
||||
# Initiate XML Processor in case of xml content-type
|
||||
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" \
|
||||
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
|
||||
|
||||
# Enable JSON request body parser.
|
||||
# Initiate JSON Processor in case of JSON content-type; change accordingly
|
||||
# if your application does not use 'application/json'
|
||||
SecRule REQUEST_HEADERS:Content-Type "^application/json" \
|
||||
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
|
||||
|
||||
# Enable JSON request body parser for more subtypes.
|
||||
# Adapt this rule if you want to engage the JSON Processor for "+json" subtypes
|
||||
SecRule REQUEST_HEADERS:Content-Type "^application/[a-z0-9.-]+[+]json" \
|
||||
"id:'200006',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
|
||||
|
||||
# Maximum request body size we will accept for buffering. If you support
|
||||
# file uploads, this value must has to be as large as the largest file
|
||||
# you are willing to accept.
|
||||
SecRequestBodyLimit 13107200
|
||||
|
||||
# Maximum request body size that Coraza will store in memory. If the body
|
||||
# size exceeds this value, it will be saved to a temporary file on disk.
|
||||
SecRequestBodyInMemoryLimit 131072
|
||||
|
||||
# Maximum request body size we will accept for buffering, with files excluded.
|
||||
# You want to keep that value as low as practical.
|
||||
# Note: SecRequestBodyNoFilesLimit is currently NOT supported by Coraza
|
||||
# SecRequestBodyNoFilesLimit 131072
|
||||
|
||||
# What to do if the request body size is above our configured limit.
|
||||
# Keep in mind that this setting will automatically be set to ProcessPartial
|
||||
# when SecRuleEngine is set to DetectionOnly mode in order to minimize
|
||||
# disruptions when initially deploying Coraza.
|
||||
# Warning: Setting this directive to ProcessPartial introduces a potential bypass
|
||||
# risk, as attackers could prepend junk data equal to or greater than the inspected body size.
|
||||
SecRequestBodyLimitAction Reject
|
||||
|
||||
# Verify that we've correctly processed the request body.
|
||||
# As a rule of thumb, when failing to process a request body
|
||||
# you should reject the request (when deployed in blocking mode)
|
||||
# or log a high-severity alert (when deployed in detection-only mode).
|
||||
SecRule REQBODY_ERROR "!@eq 0" \
|
||||
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
|
||||
|
||||
# By default be strict with what we accept in the multipart/form-data
|
||||
# request body. If the rule below proves to be too strict for your
|
||||
# environment consider changing it to detection-only.
|
||||
# Do NOT remove it, as it will catch many evasion attempts.
|
||||
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
|
||||
"id:'200003',phase:2,t:none,log,deny,status:400, \
|
||||
msg:'Multipart request body failed strict validation.'"
|
||||
|
||||
# -- Response body handling --------------------------------------------------
|
||||
|
||||
# Allow Coraza to access response bodies.
|
||||
# You should have this directive enabled in order to identify errors
|
||||
# and data leakage issues.
|
||||
# Do keep in mind that enabling this directive does increases both
|
||||
# memory consumption and response latency.
|
||||
SecResponseBodyAccess On
|
||||
|
||||
# Which response MIME types do you want to inspect? You should adjust the
|
||||
# configuration below to catch documents but avoid static files
|
||||
# (e.g., images and archives).
|
||||
SecResponseBodyMimeType text/plain text/html text/xml
|
||||
|
||||
# Buffer response bodies of up to 512 KB in length.
|
||||
SecResponseBodyLimit 524288
|
||||
|
||||
# What happens when we encounter a response body larger than the configured
|
||||
# limit? By default, we process what we have and let the rest through.
|
||||
# That's somewhat less secure, but does not break any legitimate pages.
|
||||
SecResponseBodyLimitAction ProcessPartial
|
||||
|
||||
|
||||
# -- Filesystem configuration ------------------------------------------------
|
||||
|
||||
# The location where Coraza will keep its persistent data. This default setting
|
||||
# is chosen due to all systems have /tmp available however, it
|
||||
# too should be updated to a place that other users can't access.
|
||||
SecDataDir /tmp/
|
||||
|
||||
|
||||
# -- File uploads handling configuration -------------------------------------
|
||||
|
||||
# The location where Coraza stores intercepted uploaded files. This
|
||||
# location must be private to Coraza. You don't want other users on
|
||||
# the server to access the files, do you?
|
||||
#SecUploadDir /opt/coraza/var/upload/
|
||||
|
||||
# If On, the WAF will store the uploaded files in the SecUploadDir
|
||||
# directory.
|
||||
# Note: SecUploadKeepFiles is currently NOT supported by Coraza
|
||||
#SecUploadKeepFiles Off
|
||||
|
||||
# Uploaded files are by default created with permissions that do not allow
|
||||
# any other user to access them. You may need to relax that if you want to
|
||||
# interface Coraza to an external program (e.g., an anti-virus).
|
||||
# Note: SecUploadFileMode is currently NOT supported by Coraza
|
||||
#SecUploadFileMode 0600
|
||||
|
||||
|
||||
# -- Debug log configuration -------------------------------------------------
|
||||
|
||||
# Default debug log path
|
||||
# Debug levels:
|
||||
# 0: No logging (least verbose)
|
||||
# 1: Error
|
||||
# 2: Warn
|
||||
# 3: Info
|
||||
# 4-8: Debug
|
||||
# 9: Trace (most verbose)
|
||||
SecDebugLog /var/log/caddy/coraza-debug.log
|
||||
SecDebugLogLevel 4
|
||||
|
||||
|
||||
# -- Audit log configuration -------------------------------------------------
|
||||
|
||||
# Log the transactions that are marked by a rule, as well as those that
|
||||
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
|
||||
# level response status codes).
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLogRelevantStatus "^(?:(5|4)(0|1)[0-9])$"
|
||||
|
||||
# Define which parts of the transaction are going to be recorded in the audit log
|
||||
SecAuditLogParts ABIJDEFHZ
|
||||
|
||||
# Use a single file for logging. This is much easier to look at, but
|
||||
# assumes that you will use the audit log only occasionally.
|
||||
SecAuditLogType Serial
|
||||
|
||||
# The format used to write the audit log.
|
||||
# Can be one of JSON|JsonLegacy|Native|OCSF
|
||||
SecAuditLogFormat Native
|
||||
|
||||
# The following settings are not supported by Coraza
|
||||
# SecCookieFormat 0
|
||||
# SecArgumentSeparator &
|
||||
# SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \
|
||||
# "id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
|
||||
# SecRule TX:/^COR_/ "!@streq 0" \
|
||||
# "id:'200005',phase:2,t:none,deny,msg:'Coraza internal error flagged: %{MATCHED_VAR_NAME}'"
|
||||
876
ansible/roles/bgwaf/templates/crs-setup.conf
Normal file
876
ansible/roles/bgwaf/templates/crs-setup.conf
Normal file
@@ -0,0 +1,876 @@
|
||||
# ------------------------------------------------------------------------
|
||||
# OWASP CRS ver.4.20.0
|
||||
# Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved.
|
||||
# Copyright (c) 2021-2025 CRS project. All rights reserved.
|
||||
#
|
||||
# The OWASP CRS is distributed under
|
||||
# Apache Software License (ASL) version 2
|
||||
# Please see the enclosed LICENSE file for full details.
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Introduction ]] --------------------------------------------------------
|
||||
#
|
||||
# The OWASP CRS is a set of generic attack
|
||||
# detection rules that provide a base level of protection for any web
|
||||
# application. They are written for the open source, cross-platform
|
||||
# ModSecurity Web Application Firewall.
|
||||
#
|
||||
# See also:
|
||||
# https://coreruleset.org/
|
||||
# https://github.com/coreruleset/coreruleset
|
||||
# https://owasp.org/www-project-modsecurity-core-rule-set/
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# -- [[ System Requirements ]] -------------------------------------------------
|
||||
#
|
||||
# CRS requires ModSecurity version 2.8.0 or above.
|
||||
# We recommend to always use the newest ModSecurity version.
|
||||
#
|
||||
# The configuration directives/settings in this file are used to control
|
||||
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
|
||||
# ModSecurity settings (modsecurity.conf) such as SecRuleEngine,
|
||||
# SecRequestBodyAccess, SecAuditEngine, SecDebugLog, and XML processing.
|
||||
#
|
||||
# The CRS assumes that modsecurity.conf has been loaded. It is bundled with
|
||||
# ModSecurity. If you don't have it, you can get it from:
|
||||
# 2.x: https://raw.githubusercontent.com/owasp-modsecurity/ModSecurity/v2/master/modsecurity.conf-recommended
|
||||
# 3.x: https://raw.githubusercontent.com/owasp-modsecurity/ModSecurity/v3/master/modsecurity.conf-recommended
|
||||
#
|
||||
# The order of file inclusion in your webserver configuration should always be:
|
||||
# 1. modsecurity.conf
|
||||
# 2. crs-setup.conf (this file)
|
||||
# 3. rules/*.conf (the CRS rule files)
|
||||
#
|
||||
# Please refer to the INSTALL file for detailed installation instructions.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Mode of Operation: Anomaly Scoring vs. Self-Contained ]] ---------------
|
||||
#
|
||||
# The CRS can run in two modes:
|
||||
#
|
||||
# -- [[ Anomaly Scoring Mode (default) ]] --
|
||||
# In CRS3, anomaly mode is the default and recommended mode, since it gives the
|
||||
# most accurate log information and offers the most flexibility in setting your
|
||||
# blocking policies. It is also called "collaborative detection mode".
|
||||
# In this mode, each matching rule increases an 'anomaly score'.
|
||||
# At the conclusion of the inbound rules, and again at the conclusion of the
|
||||
# outbound rules, the anomaly score is checked, and the blocking evaluation
|
||||
# rules apply a disruptive action, by default returning an error 403.
|
||||
#
|
||||
# -- [[ Self-Contained Mode ]] --
|
||||
# In this mode, rules apply an action instantly. This was the CRS2 default.
|
||||
# It can lower resource usage, at the cost of less flexibility in blocking policy
|
||||
# and less informative audit logs (only the first detected threat is logged).
|
||||
# Rules inherit the disruptive action that you specify (i.e. deny, drop, etc).
|
||||
# The first rule that matches will execute this action. In most cases this will
|
||||
# cause evaluation to stop after the first rule has matched, similar to how many
|
||||
# IDSs function.
|
||||
#
|
||||
# -- [[ Alert Logging Control ]] --
|
||||
# In the mode configuration, you must also adjust the desired logging options.
|
||||
# There are three common options for dealing with logging. By default CRS enables
|
||||
# logging to the webserver error log (or Event viewer) plus detailed logging to
|
||||
# the ModSecurity audit log (configured under SecAuditLog in modsecurity.conf).
|
||||
#
|
||||
# - To log to both error log and ModSecurity audit log file, use: "log,auditlog"
|
||||
# - To log *only* to the ModSecurity audit log file, use: "nolog,auditlog"
|
||||
# - To log *only* to the error log file, use: "log,noauditlog"
|
||||
#
|
||||
# Examples for the various modes follow.
|
||||
# You must leave one of the following options enabled.
|
||||
# Note that you must specify the same line for phase:1 and phase:2.
|
||||
#
|
||||
|
||||
# Default: Anomaly Scoring mode, log to error log, log to ModSecurity audit log
|
||||
# - By default, offending requests are blocked with an error 403 response.
|
||||
# - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example
|
||||
# and review section 'Changing the Disruptive Action for Anomaly Mode'.
|
||||
# - In Apache, you can use ErrorDocument to show a friendly error page or
|
||||
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
|
||||
#
|
||||
SecDefaultAction "phase:1,log,auditlog,pass"
|
||||
SecDefaultAction "phase:2,log,auditlog,pass"
|
||||
|
||||
# Example: Anomaly Scoring mode, log only to ModSecurity audit log
|
||||
# - By default, offending requests are blocked with an error 403 response.
|
||||
# - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example
|
||||
# and review section 'Changing the Disruptive Action for Anomaly Mode'.
|
||||
# - In Apache, you can use ErrorDocument to show a friendly error page or
|
||||
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
|
||||
#
|
||||
# SecDefaultAction "phase:1,nolog,auditlog,pass"
|
||||
# SecDefaultAction "phase:2,nolog,auditlog,pass"
|
||||
|
||||
# Example: Self-contained mode, return error 403 on blocking
|
||||
# - In this configuration the default disruptive action becomes 'deny'. After a
|
||||
# rule triggers, it will stop processing the request and return an error 403.
|
||||
# - You can also use a different error status, such as 404, 406, et cetera.
|
||||
# - In Apache, you can use ErrorDocument to show a friendly error page or
|
||||
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
|
||||
#
|
||||
# SecDefaultAction "phase:1,log,auditlog,deny,status:403"
|
||||
# SecDefaultAction "phase:2,log,auditlog,deny,status:403"
|
||||
|
||||
# Example: Self-contained mode, redirect back to homepage on blocking
|
||||
# - In this configuration the 'tag' action includes the Host header data in the
|
||||
# log. This helps to identify which virtual host triggered the rule (if any).
|
||||
# - Note that this might cause redirect loops in some situations; for example
|
||||
# if a Cookie or User-Agent header is blocked, it will also be blocked when
|
||||
# the client subsequently tries to access the homepage. You can also redirect
|
||||
# to another custom URL.
|
||||
# SecDefaultAction "phase:1,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
|
||||
# SecDefaultAction "phase:2,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Paranoia Level Initialization ]] ---------------------------------------
|
||||
#
|
||||
# The Paranoia Level (PL) setting allows you to choose the desired level
|
||||
# of rule checks that will add to your anomaly scores.
|
||||
#
|
||||
# With each paranoia level increase, the CRS enables additional rules
|
||||
# giving you a higher level of security. However, higher paranoia levels
|
||||
# also increase the possibility of blocking some legitimate traffic due to
|
||||
# false alarms (also named false positives or FPs). If you use higher
|
||||
# paranoia levels, it is likely that you will need to add some exclusion
|
||||
# rules for certain requests and applications receiving complex input.
|
||||
#
|
||||
# - A paranoia level of 1 is default. In this level, most core rules
|
||||
# are enabled. PL1 is advised for beginners, installations
|
||||
# covering many different sites and applications, and for setups
|
||||
# with standard security requirements.
|
||||
# At PL1 you should face FPs rarely. If you encounter FPs, please
|
||||
# open an issue on the CRS GitHub site and don't forget to attach your
|
||||
# complete Audit Log record for the request with the issue.
|
||||
# - Paranoia level 2 includes many extra rules, for instance enabling
|
||||
# many regexp-based SQL and XSS injection protections, and adding
|
||||
# extra keywords checked for code injections. PL2 is advised
|
||||
# for moderate to experienced users desiring more complete coverage
|
||||
# and for installations with elevated security requirements.
|
||||
# PL2 comes with some FPs which you need to handle.
|
||||
# - Paranoia level 3 enables more rules and keyword lists, and tweaks
|
||||
# limits on special characters used. PL3 is aimed at users experienced
|
||||
# at the handling of FPs and at installations with a high security
|
||||
# requirement.
|
||||
# - Paranoia level 4 further restricts special characters.
|
||||
# The highest level is advised for experienced users protecting
|
||||
# installations with very high security requirements. Running PL4 will
|
||||
# likely produce a very high number of FPs which have to be
|
||||
# treated before the site can go productive.
|
||||
#
|
||||
# All rules will log their PL to the audit log;
|
||||
# example: [tag "paranoia-level/2"]. This allows you to deduct from the
|
||||
# audit log how the WAF behavior is affected by paranoia level.
|
||||
#
|
||||
# It is important to also look into the variable
|
||||
# tx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED)
|
||||
# defined below. Enabling it closes a possible bypass of CRS.
|
||||
#
|
||||
# Uncomment this rule to change the default:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900000,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.blocking_paranoia_level=1"
|
||||
|
||||
|
||||
# It is possible to execute rules from a higher paranoia level but not include
|
||||
# them in the anomaly scoring. This allows you to take a well-tuned system on
|
||||
# paranoia level 1 and add rules from paranoia level 2 without having to fear
|
||||
# the new rules would lead to false positives that raise your score above the
|
||||
# threshold.
|
||||
# This optional feature is enabled by uncommenting the following rule and
|
||||
# setting the tx.detection_paranoia_level.
|
||||
# Technically, rules up to the level defined in tx.detection_paranoia_level
|
||||
# will be executed, but only the rules up to tx.blocking_paranoia_level affect the
|
||||
# anomaly scores.
|
||||
# By default, tx.detection_paranoia_level is set to tx.blocking_paranoia_level.
|
||||
# tx.detection_paranoia_level must not be lower than tx.blocking_paranoia_level.
|
||||
#
|
||||
# Please notice that setting tx.detection_paranoia_level to a higher paranoia
|
||||
# level results in a performance impact that is equally high as setting
|
||||
# tx.blocking_paranoia_level to said level.
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900001,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.detection_paranoia_level=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Enforce Body Processor URLENCODED ]] -----------------------------------
|
||||
#
|
||||
# ModSecurity selects the body processor based on the Content-Type request
|
||||
# header. But clients are not always setting the Content-Type header for their
|
||||
# request body payloads. This will leave ModSecurity with limited vision into
|
||||
# the payload. The variable tx.enforce_bodyproc_urlencoded lets you force the
|
||||
# URLENCODED body processor in these situations. This is off by default, as it
|
||||
# implies a change of the behaviour of ModSecurity beyond CRS (the body
|
||||
# processor applies to all rules, not only CRS) and because it may lead to
|
||||
# false positives already on paranoia level 1. However, enabling this variable
|
||||
# closes a possible bypass of CRS so it should be considered.
|
||||
#
|
||||
# Uncomment this rule to change the default:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900010,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.enforce_bodyproc_urlencoded=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Anomaly Scoring Mode Severity Levels ]] --------------------------------
|
||||
#
|
||||
# Each rule in the CRS has an associated severity level.
|
||||
# These are the default scoring points for each severity level.
|
||||
# These settings will be used to increment the anomaly score if a rule matches.
|
||||
# You may adjust these points to your liking, but this is usually not needed.
|
||||
#
|
||||
# - CRITICAL severity: Anomaly Score of 5.
|
||||
# Mostly generated by the application attack rules (93x and 94x files).
|
||||
# - ERROR severity: Anomaly Score of 4.
|
||||
# Generated mostly from outbound leakage rules (95x files).
|
||||
# - WARNING severity: Anomaly Score of 3.
|
||||
# Generated mostly by malicious client rules (91x files).
|
||||
# - NOTICE severity: Anomaly Score of 2.
|
||||
# Generated mostly by the protocol rules (92x files).
|
||||
#
|
||||
# In anomaly mode, these scores are cumulative.
|
||||
# So it's possible for a request to hit multiple rules.
|
||||
#
|
||||
# (Note: In this file, we use 'phase:1' to set CRS configuration variables.
|
||||
# In general, 'phase:request' is used. However, we want to make absolutely sure
|
||||
# that all configuration variables are set before the CRS rules are processed.)
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900100,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.critical_anomaly_score=5,\
|
||||
# setvar:tx.error_anomaly_score=4,\
|
||||
# setvar:tx.warning_anomaly_score=3,\
|
||||
# setvar:tx.notice_anomaly_score=2"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Anomaly Scoring Mode Blocking Threshold Levels ]] ----------------------
|
||||
#
|
||||
# Here, you can specify at which cumulative anomaly score an inbound request,
|
||||
# or outbound response, gets blocked.
|
||||
#
|
||||
# Most detected inbound threats will give a critical score of 5.
|
||||
# Smaller violations, like violations of protocol/standards, carry lower scores.
|
||||
#
|
||||
# [ At default value ]
|
||||
# If you keep the blocking thresholds at the defaults, the CRS will work
|
||||
# similarly to previous CRS versions: a single critical rule match will cause
|
||||
# the request to be blocked and logged.
|
||||
#
|
||||
# [ Using higher values ]
|
||||
# If you want to make the CRS less sensitive, you can increase the blocking
|
||||
# thresholds, for instance to 7 (which would require multiple rule matches
|
||||
# before blocking) or 10 (which would require at least two critical alerts - or
|
||||
# a combination of many lesser alerts), or even higher. However, increasing the
|
||||
# thresholds might cause some attacks to bypass the CRS rules or your policies.
|
||||
#
|
||||
# [ New deployment strategy: Starting high and decreasing ]
|
||||
# It is a common practice to start a fresh CRS installation with elevated
|
||||
# anomaly scoring thresholds (>100) and then lower the limits as your
|
||||
# confidence in the setup grows. You may also look into the Sampling
|
||||
# Percentage section below for a different strategy to ease into a new
|
||||
# CRS installation.
|
||||
#
|
||||
# [ Anomaly Threshold / Paranoia Level Quadrant ]
|
||||
#
|
||||
# High Anomaly Limit | High Anomaly Limit
|
||||
# Low Paranoia Level | High Paranoia Level
|
||||
# -> Fresh Site | -> Experimental Site
|
||||
# ------------------------------------------------------
|
||||
# Low Anomaly Limit | Low Anomaly Limit
|
||||
# Low Paranoia Level | High Paranoia Level
|
||||
# -> Standard Site | -> High Security Site
|
||||
#
|
||||
# Uncomment this rule to change the defaults:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900110,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.inbound_anomaly_score_threshold=5,\
|
||||
# setvar:tx.outbound_anomaly_score_threshold=4"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Application Specific Rule Exclusions ]] --------------------------------
|
||||
#
|
||||
# CRS 3.x contained exclusion packages to tweak the CRS for use with common
|
||||
# web applications, lowering the number of false positives.
|
||||
#
|
||||
# In CRS 4, these are no longer part of the CRS itself, but they are available
|
||||
# as "CRS plugins". Some plugins improve support for web applications, and others
|
||||
# may bring new functionality. Plugins are not installed by default, but can be
|
||||
# downloaded from the plugin registry:
|
||||
# https://github.com/coreruleset/plugin-registry
|
||||
#
|
||||
# For detailed information about using and installing plugins, please see:
|
||||
# https://coreruleset.org/docs/concepts/plugins/
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Anomaly Score Reporting Level ]] ---------------------------------------
|
||||
#
|
||||
# When a request is blocked due to the anomaly score meeting or exceeding the
|
||||
# anomaly threshold then the blocking rule will also report the anomaly score.
|
||||
# This applies to the separate inbound and outbound anomaly scores.
|
||||
#
|
||||
# In phase 5, there are additional rules that can perform additional reporting
|
||||
# of anomaly scores with a verbosity that depends on the reporting level defined
|
||||
# below.
|
||||
#
|
||||
# By setting the reporting level you control whether you want additional
|
||||
# reporting beyond the blocking rule or not and, if yes, which requests should
|
||||
# be covered. The higher the reporting level, the more verbose the reporting is.
|
||||
#
|
||||
# There are 6 reporting levels:
|
||||
#
|
||||
# 0 - Reporting disabled
|
||||
# 1 - Reporting for requests with a blocking anomaly score >= a threshold
|
||||
# 2 - Reporting for requests with a detection anomaly score >= a threshold
|
||||
# 3 - Reporting for requests with a blocking anomaly score greater than 0
|
||||
# 4 - Reporting for requests with a detection anomaly score greater than 0
|
||||
# 5 - Reporting for all requests
|
||||
#
|
||||
# Note: Reporting levels 1 and 2 make it possible to differentiate between
|
||||
# requests that are blocked and requests that are *not* blocked but would have
|
||||
# been blocked if the blocking PL was equal to detection PL. This may be useful
|
||||
# for certain FP tuning methodologies, for example moving to a higher PL.
|
||||
#
|
||||
# A value of 5 can be useful on platforms where you are interested in logging
|
||||
# non-scoring requests, yet it is not possible to report this information in
|
||||
# the request/access log. This applies to Nginx, for example.
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900115,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.reporting_level=4"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Early Anomaly Scoring Mode Blocking ]] ------------------------------
|
||||
#
|
||||
# The anomaly scores for the request and the responses are generally summed up
|
||||
# and evaluated at the end of phase:2 and at the end of phase:4 respectively.
|
||||
# However, it is possible to enable an early evaluation of these anomaly scores
|
||||
# at the end of phase:1 and at the end of phase:3.
|
||||
#
|
||||
# If a request (or a response) hits the anomaly threshold in this early
|
||||
# evaluation, then blocking happens immediately (if blocking is enabled) and
|
||||
# the phase 2 (and phase 4 respectively) will no longer be executed.
|
||||
#
|
||||
# Enable the rule 900120 that sets the variable tx.early_blocking to 1 in order
|
||||
# to enable early blocking. The variable tx.early_blocking is set to 0 by
|
||||
# default. Early blocking is thus disabled by default.
|
||||
#
|
||||
# Please note that early blocking will hide potential alerts from you. This
|
||||
# means that a payload that would appear in an alert in phase 2 (or phase 4)
|
||||
# does not get evaluated if the request is being blocked early. So when you
|
||||
# disabled early blocking again at some point in the future, then new alerts
|
||||
# from phase 2 might pop up.
|
||||
#SecAction \
|
||||
# "id:900120,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.early_blocking=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Initialize Default Collections ]] -----------------------------------
|
||||
#
|
||||
# CRS provides a centralized option to initialize and populate collections
|
||||
# meant to be used by plugins (E.g.DoS protection plugin).
|
||||
# By default, Global and IP collections (see rule 901320),
|
||||
# being not used by core rules, are not initialized.
|
||||
#
|
||||
# Uncomment this rule to change the default:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900130,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.enable_default_collections=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ HTTP Policy Settings ]] ------------------------------------------------
|
||||
#
|
||||
# This section defines your policies for the HTTP protocol, such as:
|
||||
# - allowed HTTP versions, HTTP methods, allowed request Content-Types
|
||||
# - forbidden file extensions (e.g. .bak, .sql) and request headers (e.g. Proxy)
|
||||
#
|
||||
# These variables are used in the following rule files:
|
||||
# - REQUEST-911-METHOD-ENFORCEMENT.conf
|
||||
# - REQUEST-920-PROTOCOL-ENFORCEMENT.conf
|
||||
|
||||
# HTTP methods that a client is allowed to use.
|
||||
# Default: GET HEAD POST OPTIONS
|
||||
# Example: for RESTful APIs, add the following methods: PUT PATCH DELETE
|
||||
# Example: for WebDAV, add the following methods: CHECKOUT COPY DELETE LOCK
|
||||
# MERGE MKACTIVITY MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK
|
||||
# Uncomment this rule to change the default.
|
||||
#
|
||||
# The HTTP PUT method is normally used to upload data that is saved on the server at a user-supplied URL.
|
||||
# If enabled, an attacker may be able to inject arbitrary, and potentially malicious, content into the application or on to the file system of the web server.
|
||||
# Depending on the server's configuration, this may lead to compromise of other users (by uploading
|
||||
# client-executable scripts), compromise of the server (by uploading server-executable code), or other attacks.
|
||||
# For this reason, the PUT method is disabled by default.
|
||||
# GET, HEAD, POST and OPTIONS are seen as the minimal set of HTTP methods
|
||||
# from a security perspective. For static sites, removing the POST is
|
||||
# recommended. Add other HTTP methods as seen fit (see above).
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900200,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'"
|
||||
|
||||
# Content-Types that a client is allowed to send in a request.
|
||||
# Default: |application/x-www-form-urlencoded| |multipart/form-data| |text/xml|
|
||||
# |application/xml| |application/soap+xml| |application/json| |application/reports+json| |application/csp-report|
|
||||
#
|
||||
# Please note, that the rule where CRS uses this variable (920420) evaluates it with operator
|
||||
# `@within`, which is case sensitive, but uses t:lowercase. You must add your whole custom
|
||||
# Content-Type with lowercase.
|
||||
#
|
||||
# Bypass Warning: some applications may not rely on the content-type request header in order
|
||||
# to parse the request body. This could make an attacker able to send malicious URLENCODED/JSON/XML
|
||||
# payloads without being detected by the WAF. Allowing request content-type that doesn't activate any
|
||||
# body processor (for example: "text/plain", "application/x-amf", "application/octet-stream", etc..)
|
||||
# could lead to a WAF bypass. For example, a malicious JSON payload submitted with a "text/plain"
|
||||
# content type may still be interpreted as JSON by a backend application but would not trigger the
|
||||
# JSON body parser at the WAF, leading to a bypass. To avoid bypasses, you must enable the appropriate
|
||||
# body parser based on the expected data in the request bodies (For example JSON for JSON data, XML for XML data, etc).
|
||||
#
|
||||
# When additional JSON content types are legitimately used in a deployment,
|
||||
# e.g. application/cloudevents+json, it is extremely important to ensure that a
|
||||
# rule exists to enable the engine's JSON body processor for these additional
|
||||
# JSON content types. Failure to do so can lead to a request body bypass. The
|
||||
# default JSON rule in modsecurity.conf-recommended (200001) will only activate
|
||||
# the JSON body processor for the specific content type application/json. The
|
||||
# optional modsecurity.conf-recommended rule 200006 can be used to enable the
|
||||
# JSON body processor for a wide variety of JSON content types.
|
||||
#
|
||||
# To prevent blocking request with not allowed content-type by default, you can create an exclusion
|
||||
# rule that removes rule 920420. It's important that you enable the correct body parser when allowing
|
||||
# an additional content type to prevent bypasses. For example, this rule enables the JSON body processor
|
||||
# for the text/plain content type:
|
||||
#SecRule REQUEST_HEADERS:Content-Type "@beginsWith text/plain" \
|
||||
# "id:1234,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# chain"
|
||||
# SecRule REQUEST_URI "@rx ^/foo/bar" \
|
||||
# "t:none,\
|
||||
# ctl:ruleRemoveById=920420,\
|
||||
# ctl:requestBodyProcessor=JSON"
|
||||
#
|
||||
# See: https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v2.x)#ctl
|
||||
# See: https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x)#ctl
|
||||
#
|
||||
# Uncomment this rule to change the default.
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900220,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |text/xml| |application/xml| |application/soap+xml| |application/json| |application/reports+json| |application/csp-report|'"
|
||||
|
||||
# Allowed HTTP versions.
|
||||
# Default: HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0
|
||||
# Example for legacy clients: HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0
|
||||
# Note that some web server versions use 'HTTP/2', some 'HTTP/2.0', so
|
||||
# we include both version strings by default.
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900230,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0'"
|
||||
|
||||
# Forbidden file extensions.
|
||||
# Guards against unintended exposure of development/configuration files.
|
||||
# Default: .ani/ .asa/ .asax/ .ascx/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .cnf/ .com/ .compositefont/ .config/ .conf/ .copy/ .crt/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dist/ .dll/ .dos/ .dpkg-dist/ .drv/ .gadget/ .hta/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .inf/ .ini/ .jse/ .key/ .licx/ .lnk/ .log/ .mdb/ .msc/ .ocx/ .old/ .pass/ .pdb/ .pfx/ .pif/ .pem/ .pol/ .prf/ .printer/ .pwd/ .rdb/ .rdp/ .reg/ .resources/ .resx/ .save/ .scr/ .sct/ .shs/ .sql/ .sqlite/ .sqlite3/ .swp/ .sys/ .temp/ .tlb/ .tmp/ .vb/ .vbe/ .vbs/ .vbproj/ .vsdisco/ .vxd/ .webinfo/ .ws/ .wsc/ .wsf/ .wsh/ .xsd/ .xsx/
|
||||
# Example: .bak/ .config/ .conf/ .db/ .ini/ .log/ .old/ .pass/ .pdb/ .rdb/ .sql/
|
||||
# Note that .axd was removed due to false positives (see PR 1925).
|
||||
#
|
||||
# To additionally guard against configuration/install archive files from being
|
||||
# accidentally exposed, common archive file extensions can be added to the
|
||||
# restricted extensions list. An example list of common archive file extensions
|
||||
# is presented below:
|
||||
# .7z/ .br/ .bz/ .bz2/ .cab/ .cpio/ .gz/ .img/ .iso/ .jar/ .rar/ .tar/ .tbz2/ .tgz/ .txz/ .xz/ .zip/ .zst/
|
||||
# (Source: https://en.wikipedia.org/wiki/List_of_archive_formats)
|
||||
#
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900240,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.restricted_extensions=.ani/ .asa/ .asax/ .ascx/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .cnf/ .com/ .compositefont/ .config/ .conf/ .copy/ .crt/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dist/ .dll/ .dos/ .dpkg-dist/ .drv/ .gadget/ .hta/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .inf/ .ini/ .jse/ .key/ .licx/ .lnk/ .log/ .mdb/ .msc/ .ocx/ .old/ .pass/ .pdb/ .pfx/ .pif/ .pem/ .pol/ .prf/ .printer/ .pwd/ .rdb/ .rdp/ .reg/ .resources/ .resx/ .save/ .scr/ .sct/ .shs/ .sql/ .sqlite/ .sqlite3/ .swp/ .sys/ .temp/ .tlb/ .tmp/ .vb/ .vbe/ .vbs/ .vbproj/ .vsdisco/ .vxd/ .webinfo/ .ws/ .wsc/ .wsf/ .wsh/ .xsd/ .xsx/'"
|
||||
|
||||
# Restricted request headers.
|
||||
# The HTTP request headers that CRS restricts are split into two categories:
|
||||
# basic (always forbidden) and extended (may be forbidden). All header names
|
||||
# should be lowercase and enclosed by /slashes/ as delimiters.
|
||||
#
|
||||
# [ Basic ]
|
||||
# Includes deprecated headers and headers with known security risks. Always
|
||||
# forbidden.
|
||||
# Default: /content-encoding/ /proxy/ /lock-token/ /content-range/ /if/ /x-http-method-override/ /x-http-method/ /x-method-override/ /x-middleware-subrequest/ /expect/
|
||||
#
|
||||
# /content-encoding/
|
||||
# Used to list any encodings that have been applied to the original payload.
|
||||
# Only used for compression, which isn't supported by CRS by default since CRS
|
||||
# blocks newlines and null bytes inside the request body. Most compression
|
||||
# algorithms require at least null bytes per RFC. Blocking Content-Encoding
|
||||
# shouldn't break anything and increases security since WAF engines, including
|
||||
# ModSecurity, are typically incapable of properly scanning compressed request
|
||||
# bodies.
|
||||
#
|
||||
# /proxy/
|
||||
# Blocking this prevents the 'httpoxy' vulnerability: https://httpoxy.org
|
||||
#
|
||||
# /lock-token/
|
||||
#
|
||||
# /content-range/
|
||||
#
|
||||
# /if/
|
||||
#
|
||||
# /x-http-method-override/
|
||||
# /x-http-method/
|
||||
# /x-method-override/
|
||||
# Blocking these headers prevents method override attacks, as described here:
|
||||
# https://www.sidechannel.blog/en/http-method-override-what-it-is-and-how-a-pentester-can-use-it
|
||||
#
|
||||
# /x-middleware-subrequest/
|
||||
# CVE-2025-29927 (Next.js)
|
||||
#
|
||||
# /expect/
|
||||
# Blocking this header prevents Expect-based desync attacks
|
||||
# https://portswigger.net/research/http1-must-die#expect-based-desync-attacks
|
||||
#
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900250,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.restricted_headers_basic=/content-encoding/ /proxy/ /lock-token/ /content-range/ /if/ /x-http-method-override/ /x-http-method/ /x-method-override/ /x-middleware-subrequest/ /expect/'"
|
||||
#
|
||||
# [ Extended ]
|
||||
# Includes deprecated headers that are still in use (so false positives are
|
||||
# possible) and headers with possible security risks. Forbidden at a higher
|
||||
# paranoia level.
|
||||
# Default: /accept-charset/
|
||||
#
|
||||
# /accept-charset/
|
||||
# Deprecated header that should not be used by clients and should be ignored
|
||||
# by servers. Can be used for a response WAF bypass by asking for a charset
|
||||
# that the WAF cannot decode. Considered to be a good indicator of suspicious
|
||||
# behavior but produces too many false positives to be forbidden by default.
|
||||
# References:
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset
|
||||
# https://github.com/coreruleset/coreruleset/issues/3140
|
||||
#
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900255,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.restricted_headers_extended=/accept-charset/'"
|
||||
|
||||
# Content-Types charsets that a client is allowed to send in a request.
|
||||
# The content-types are enclosed by |pipes| as delimiters to guarantee exact matches.
|
||||
#
|
||||
# You can add additional character sets if something more exotic is required. One caveat: you will also need to edit 'regex-assembly/include/allowed-charsets.ra' and rebuild all the associated regular expressions using `crs-toolchain regex update --all`. See https://coreruleset.org/docs/6-development/6-2-crs-toolchain/.
|
||||
#
|
||||
# Warning: If the WAF engine is unable to fully and correctly decode a newly added character encoding then this can lead to a full request body or response body bypass. Additional permitted character encodings should be added with caution and tested to ensure inspection is not affected.
|
||||
#
|
||||
# Default: |utf-8| |iso-8859-1| |iso-8859-15| |windows-1252|
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900280,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:'tx.allowed_request_content_type_charset=|utf-8| |iso-8859-1| |iso-8859-15| |windows-1252|'"
|
||||
|
||||
#
|
||||
# -- [[ HTTP Argument/Upload Limits ]] -----------------------------------------
|
||||
#
|
||||
# Here you can define optional limits on HTTP get/post parameters and uploads.
|
||||
# This can help to prevent application specific DoS attacks.
|
||||
#
|
||||
# These values are checked in REQUEST-920-PROTOCOL-ENFORCEMENT.conf.
|
||||
# Beware of blocking legitimate traffic when enabling these limits.
|
||||
#
|
||||
|
||||
# Block request if number of arguments is too high
|
||||
# Default: unlimited
|
||||
# Example: 255
|
||||
# Note that a hard limit by the engine may also apply here (SecArgumentsLimit).
|
||||
# This would override this soft limit.
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900300,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.max_num_args=255"
|
||||
|
||||
# Block request if the length of any argument name is too high
|
||||
# Default: unlimited
|
||||
# Example: 100
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900310,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.arg_name_length=100"
|
||||
|
||||
# Block request if the length of any argument value is too high
|
||||
# Default: unlimited
|
||||
# Example: 400
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900320,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.arg_length=400"
|
||||
|
||||
# Block request if the total length of all combined arguments is too high
|
||||
# Default: unlimited
|
||||
# Example: 64000
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900330,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.total_arg_length=64000"
|
||||
|
||||
# Block request if the file size of any individual uploaded file is too high
|
||||
# Default: unlimited
|
||||
# Example: 1048576
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900340,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.max_file_size=1048576"
|
||||
|
||||
# Block request if the total size of all combined uploaded files is too high
|
||||
# Default: unlimited
|
||||
# Example: 1048576
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900350,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.combined_file_sizes=1048576"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Easing In / Sampling Percentage ]] -------------------------------------
|
||||
#
|
||||
# Adding the CRS to an existing productive site can lead to false
|
||||
# positives, unexpected performance issues and other undesired side effects.
|
||||
#
|
||||
# It can be beneficial to test the water first by enabling the CRS for a
|
||||
# limited number of requests only and then, when you have solved the issues (if
|
||||
# any) and you have confidence in the setup, to raise the ratio of requests
|
||||
# being sent into the ruleset.
|
||||
#
|
||||
# Adjust the percentage of requests that are funnelled into the Core Rules by
|
||||
# setting TX.sampling_percentage below. The default is 100, meaning that every
|
||||
# request gets checked by the CRS. The selection of requests, which are going
|
||||
# to be checked, is based on a pseudo random number generated by ModSecurity.
|
||||
#
|
||||
# If a request is allowed to pass without being checked by the CRS, there is no
|
||||
# entry in the audit log (for performance reasons), but an error log entry is
|
||||
# written. If you want to disable the error log entry, then issue the
|
||||
# following directive somewhere after the inclusion of the CRS
|
||||
# (E.g., RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf).
|
||||
#
|
||||
#SecRuleUpdateActionById 901450 "nolog"
|
||||
#
|
||||
# ATTENTION: If this TX.sampling_percentage is below 100, then some of the
|
||||
# requests will bypass the Core Rules completely and you lose the ability to
|
||||
# protect your service with ModSecurity.
|
||||
#
|
||||
# Uncomment this rule to enable this feature:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900400,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.sampling_percentage=100"
|
||||
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Check UTF-8 encoding ]] ------------------------------------------------
|
||||
#
|
||||
# The CRS can optionally check request contents for invalid UTF-8 encoding.
|
||||
# We only want to apply this check if UTF-8 encoding is actually used by the
|
||||
# site; otherwise it will result in false positives.
|
||||
#
|
||||
# Uncomment this rule to use this feature:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900950,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.crs_validate_utf8_encoding=1"
|
||||
|
||||
# -- [[ Skip Checking Responses ]] ------------------------------------------------
|
||||
#
|
||||
# CRS will perform analysis of the response contents if this is enabled and you have
|
||||
# the directive `SecResponseBodyAccess On`.
|
||||
#
|
||||
# Warning: this feature is _enabled_ by default, but depending on your applications
|
||||
# you might be targeted in a Request Filter Denial of Service (RFDoS) attack.
|
||||
#
|
||||
# References: https://blog.sicuranext.com/response-filter-denial-of-service-a-new-way-to-shutdown-a-website/
|
||||
#
|
||||
# Uncomment this rule to _skip checking responses_.
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900500,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# tag:'OWASP_CRS',\
|
||||
# ver:'OWASP_CRS/4.20.0',\
|
||||
# setvar:tx.crs_skip_response_analysis=1"
|
||||
|
||||
#
|
||||
# -- [[ End of setup ]] --------------------------------------------------------
|
||||
#
|
||||
# The CRS checks the tx.crs_setup_version variable to ensure that the setup
|
||||
# has been loaded. If you are not planning to use this setup template,
|
||||
# you must manually set the tx.crs_setup_version variable before including
|
||||
# the CRS rules/* files.
|
||||
#
|
||||
# The variable is a numerical representation of the CRS version number.
|
||||
# E.g., v3.0.0 is represented as 300.
|
||||
#
|
||||
SecAction \
|
||||
"id:900990,\
|
||||
phase:1,\
|
||||
pass,\
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/4.21.0',\
|
||||
setvar:tx.crs_setup_version=4210"
|
||||
3
ansible/roles/bgwaf/templates/exclusions.conf
Normal file
3
ansible/roles/bgwaf/templates/exclusions.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
{% for exclusion in bgwaf_site_exclusions %}
|
||||
{{ exclusion }}
|
||||
{% endfor %}
|
||||
1
ansible/roles/bgwaf/vars/main.yml
Normal file
1
ansible/roles/bgwaf/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
||||
bgwaf_xcaddy_download: "https://github.com/caddyserver/xcaddy/releases/download"
|
||||
10
ansible/roles/cert/defaults/main.yml
Normal file
10
ansible/roles/cert/defaults/main.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
# Defaults
|
||||
cert_not_after: "+365d" # valid for one year
|
||||
cert_not_before: "-1d" # valid since yesterday
|
||||
|
||||
# Required
|
||||
cert_domains: []
|
||||
cert_country_name: None
|
||||
cert_locality_name: None
|
||||
cert_organization_name: None
|
||||
cert_email_address: None
|
||||
2
ansible/roles/cert/handlers/main.yml
Normal file
2
ansible/roles/cert/handlers/main.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
- name: Reboot host
|
||||
ansible.builtin.reboot:
|
||||
53
ansible/roles/cert/tasks/main.yml
Normal file
53
ansible/roles/cert/tasks/main.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
- name: Install requirements
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "ssl-cert"
|
||||
|
||||
- name: Copy CA certificate file on server
|
||||
ansible.builtin.copy:
|
||||
src: "ca/ca-certificate.crt"
|
||||
dest: "/etc/ssl/certs/local-ca.crt"
|
||||
mode: "0644"
|
||||
|
||||
- name: Create private key for new certificate
|
||||
community.crypto.openssl_privatekey:
|
||||
path: "/etc/ssl/private/local.key"
|
||||
mode: "0640"
|
||||
group: "ssl-cert"
|
||||
|
||||
- name: Create CSR for new certificate
|
||||
community.crypto.openssl_csr:
|
||||
path: "/etc/ssl/certs/local.csr"
|
||||
privatekey_path: "/etc/ssl/private/local.key"
|
||||
common_name: "{{ cert_domains[0] }}"
|
||||
subject_alt_name: "{{ cert_domains }}"
|
||||
country_name: "{{ cert_country_name }}"
|
||||
locality_name: "{{ cert_locality_name }}"
|
||||
organization_name: "{{ cert_organization_name }}"
|
||||
email_address: "{{ cert_email_address }}"
|
||||
return_content: true
|
||||
register: cert_csr
|
||||
|
||||
- name: Sign certificate with our CA
|
||||
delegate_to: "localhost"
|
||||
# noqa: no-handler
|
||||
when: "cert_csr.changed"
|
||||
community.crypto.x509_certificate_pipe:
|
||||
csr_content: "{{ cert_csr.csr }}"
|
||||
provider: "ownca"
|
||||
ownca_path: "ca/ca-certificate.crt"
|
||||
ownca_privatekey_path: "ca/ca-certificate.key"
|
||||
ownca_privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
||||
ownca_not_after: "{{ cert_not_after }}"
|
||||
ownca_not_before: "{{ cert_not_before }}"
|
||||
register: cert_certificate
|
||||
|
||||
- name: Write certificate file on server
|
||||
# noqa: no-handler
|
||||
when: "cert_csr.changed"
|
||||
ansible.builtin.copy:
|
||||
dest: "/etc/ssl/certs/local.crt"
|
||||
content: "{{ cert_certificate.certificate }}"
|
||||
mode: "0644"
|
||||
notify:
|
||||
- "Reboot host"
|
||||
2
ansible/roles/common/tasks/main.yml
Normal file
2
ansible/roles/common/tasks/main.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
- name: Setup proxy client
|
||||
ansible.builtin.include_tasks: "setup_proxy_client.yml"
|
||||
24
ansible/roles/common/tasks/setup_proxy_client.yml
Normal file
24
ansible/roles/common/tasks/setup_proxy_client.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
- name: Create 00proxy.conf file
|
||||
ansible.builtin.template:
|
||||
src: "templates/apt_proxy.conf"
|
||||
dest: "/etc/apt/apt.conf.d/00proxy.conf"
|
||||
mode: "644"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
|
||||
- name: Add http_proxy and https_proxy variable to file /etc/environment
|
||||
ansible.builtin.lineinfile:
|
||||
path: "/etc/environment"
|
||||
regexp: '^{{ item.key }}='
|
||||
line: '{{ item.key }}="{{ item.value }}"'
|
||||
create: true
|
||||
mode: "644"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
with_items:
|
||||
- key: 'http_proxy'
|
||||
value: '{{ common_proxy_server }}'
|
||||
- key: 'https_proxy'
|
||||
value: '{{ common_proxy_server }}'
|
||||
- key: 'no_proxy'
|
||||
value: 'localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'
|
||||
2
ansible/roles/common/templates/apt_proxy.conf
Normal file
2
ansible/roles/common/templates/apt_proxy.conf
Normal file
@@ -0,0 +1,2 @@
|
||||
Acquire::http::Proxy "http://{{ common_proxy_server }}";
|
||||
Acquire::https::Proxy "https://{{ common_proxy_server }}";
|
||||
14
ansible/roles/consul/defaults/main.yml
Normal file
14
ansible/roles/consul/defaults/main.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
# Required
|
||||
consul_datacenter: null
|
||||
consul_secret_key: null
|
||||
consul_nodes: []
|
||||
consul_domain: None
|
||||
|
||||
# Defaults
|
||||
consul_version: "1.22.2"
|
||||
consul_key_file: "/etc/ssl/private/local.key"
|
||||
consul_cert_file: "/etc/ssl/certs/local.crt"
|
||||
consul_ca_file: "/etc/ssl/certs/local-ca.crt"
|
||||
consul_client_addr: "0.0.0.0"
|
||||
consul_bind_addr: "{{ ansible_default_ipv4.address }}"
|
||||
consul_advertise_addr: "{{ ansible_default_ipv4.address }}"
|
||||
10
ansible/roles/consul/handlers/main.yml
Normal file
10
ansible/roles/consul/handlers/main.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
- name: Restart Consul
|
||||
ansible.builtin.service:
|
||||
name: "consul"
|
||||
state: "restarted"
|
||||
daemon_reload: true
|
||||
|
||||
- name: Reload Consul
|
||||
ansible.builtin.service:
|
||||
name: "consul"
|
||||
state: "reloaded"
|
||||
78
ansible/roles/consul/tasks/main.yml
Normal file
78
ansible/roles/consul/tasks/main.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
- name: Install requirements
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "unzip"
|
||||
|
||||
- name: Create Consul directory
|
||||
ansible.builtin.file:
|
||||
path: "/usr/local/consul-{{ consul_version }}"
|
||||
state: "directory"
|
||||
mode: "0755"
|
||||
|
||||
- name: Install Consul
|
||||
ansible.builtin.unarchive:
|
||||
src: "https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_linux_amd64.zip"
|
||||
dest: "/usr/local/consul-{{ consul_version }}"
|
||||
remote_src: true
|
||||
notify:
|
||||
- "Restart Consul"
|
||||
|
||||
- name: Link Consul
|
||||
ansible.builtin.file:
|
||||
src: "/usr/local/consul-{{ consul_version }}/consul"
|
||||
dest: "/usr/local/bin/consul"
|
||||
state: "link"
|
||||
notify:
|
||||
- "Restart Consul"
|
||||
|
||||
- name: Create consul system group
|
||||
ansible.builtin.group:
|
||||
name: "consul"
|
||||
system: true
|
||||
|
||||
- name: Create consul system user
|
||||
ansible.builtin.user:
|
||||
name: "consul"
|
||||
group: "consul"
|
||||
groups: ["ssl-cert"]
|
||||
password: "!"
|
||||
system: true
|
||||
home: "/opt/consul"
|
||||
|
||||
- name: Create consul config directory
|
||||
ansible.builtin.file:
|
||||
path: "/etc/consul"
|
||||
state: "directory"
|
||||
group: "consul"
|
||||
mode: "0750"
|
||||
|
||||
- name: Create consul log dir
|
||||
ansible.builtin.file:
|
||||
path: "/var/log/consul"
|
||||
state: "directory"
|
||||
group: "consul"
|
||||
mode: "0770"
|
||||
|
||||
- name: Generate Consul config
|
||||
ansible.builtin.template:
|
||||
src: "templates/config.json"
|
||||
dest: "/etc/consul/config.json"
|
||||
group: "consul"
|
||||
mode: "0640"
|
||||
notify:
|
||||
- "Reload Consul"
|
||||
|
||||
- name: Deploy Consul service file
|
||||
ansible.builtin.template:
|
||||
src: "templates/consul.service"
|
||||
dest: "/etc/systemd/system/consul.service"
|
||||
mode: "0644"
|
||||
notify:
|
||||
- "Restart Consul"
|
||||
|
||||
- name: Enable and start Consul
|
||||
ansible.builtin.service:
|
||||
name: "consul"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
26
ansible/roles/consul/templates/config.json
Normal file
26
ansible/roles/consul/templates/config.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"log_level": "INFO",
|
||||
"node_name": "{{ ansible_hostname }}",
|
||||
"domain": "{{ consul_domain }}",
|
||||
"server": true,
|
||||
"key_file": "{{ consul_key_file }}",
|
||||
"cert_file": "{{ consul_cert_file }}",
|
||||
"ca_file": "{{ consul_ca_file }}",
|
||||
"verify_incoming": true,
|
||||
"verify_outgoing": true,
|
||||
"verify_server_hostname": true,
|
||||
"encrypt": "{{ consul_secret_key }}",
|
||||
"ui": true,
|
||||
"leave_on_terminate": true,
|
||||
"data_dir": "/opt/consul",
|
||||
"datacenter": "{{ consul_datacenter | mandatory }}",
|
||||
"client_addr": "{{ consul_client_addr }}",
|
||||
"bind_addr": "{{ consul_bind_addr }}",
|
||||
"advertise_addr": "{{ consul_advertise_addr }}",
|
||||
"bootstrap_expect": {{ consul_nodes | length }},
|
||||
"retry_join": ["{{ consul_nodes | join('", "') }}"],
|
||||
"enable_syslog": true,
|
||||
"performance": {
|
||||
"raft_multiplier": 1
|
||||
}
|
||||
}
|
||||
19
ansible/roles/consul/templates/consul.service
Normal file
19
ansible/roles/consul/templates/consul.service
Normal file
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description="HashiCorp Consul - A service mesh solution"
|
||||
Documentation=https://www.consul.io/
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
ConditionFileNotEmpty=/etc/consul/config.json
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
User=consul
|
||||
Group=consul
|
||||
ExecStart=/usr/local/bin/consul agent -config-file=/etc/consul/config.json
|
||||
ExecReload=/usr/local/bin/consul reload
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
11
ansible/roles/local_ca/defaults/main.yml
Normal file
11
ansible/roles/local_ca/defaults/main.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
# Defaults
|
||||
local_ca_key_size: 4096
|
||||
local_ca_key_type: "RSA"
|
||||
|
||||
# Required
|
||||
local_ca_common_name: None
|
||||
local_ca_passphrase: None
|
||||
local_ca_country_name: None
|
||||
local_ca_locality_name: None
|
||||
local_ca_organization_name: None
|
||||
local_ca_email_address: None
|
||||
51
ansible/roles/local_ca/tasks/main.yml
Normal file
51
ansible/roles/local_ca/tasks/main.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
- name: Create CA directory
|
||||
delegate_to: "localhost"
|
||||
run_once: true
|
||||
ansible.builtin.file:
|
||||
path: "ca"
|
||||
state: "directory"
|
||||
mode: "0700"
|
||||
|
||||
- name: Create private key with password protection
|
||||
delegate_to: "localhost"
|
||||
run_once: true
|
||||
community.crypto.openssl_privatekey:
|
||||
path: "ca/ca-certificate.key"
|
||||
passphrase: "{{ local_ca_passphrase }}"
|
||||
size: "{{ local_ca_key_size }}"
|
||||
type: "{{ local_ca_key_type }}"
|
||||
mode: "0640"
|
||||
|
||||
- name: Create certificate signing request (CSR) for CA certificate
|
||||
delegate_to: "localhost"
|
||||
run_once: true
|
||||
community.crypto.openssl_csr:
|
||||
path: "ca/ca-certificate.csr"
|
||||
privatekey_path: "ca/ca-certificate.key"
|
||||
privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
||||
common_name: "{{ local_ca_common_name }}"
|
||||
use_common_name_for_san: false # since we do not specify SANs, don't use CN as a SAN
|
||||
country_name: "{{ local_ca_country_name }}"
|
||||
locality_name: "{{ local_ca_locality_name }}"
|
||||
organization_name: "{{ local_ca_organization_name }}"
|
||||
email_address: "{{ local_ca_email_address }}"
|
||||
basic_constraints:
|
||||
- "CA:TRUE"
|
||||
basic_constraints_critical: true
|
||||
key_usage:
|
||||
- "keyCertSign"
|
||||
key_usage_critical: true
|
||||
return_content: true
|
||||
register: local_ca_csr
|
||||
|
||||
- name: Create self-signed CA certificate from CSR
|
||||
delegate_to: "localhost"
|
||||
run_once: true
|
||||
# noqa: no-handler
|
||||
when: "local_ca_csr.changed"
|
||||
community.crypto.x509_certificate:
|
||||
path: "ca/ca-certificate.crt"
|
||||
csr_content: "{{ local_ca_csr.csr }}"
|
||||
privatekey_path: "ca/ca-certificate.key"
|
||||
privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
||||
provider: "selfsigned"
|
||||
2
ansible/roles/squid/defaults/main.yml
Normal file
2
ansible/roles/squid/defaults/main.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
squid_authorized_networks: ["127.0.0.1"]
|
||||
squid_cache_size: 10240
|
||||
4
ansible/roles/squid/handlers/main.yml
Normal file
4
ansible/roles/squid/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- name: Restart squid
|
||||
ansible.builtin.systemd:
|
||||
name: "squid"
|
||||
state: "restarted"
|
||||
23
ansible/roles/squid/tasks/main.yml
Normal file
23
ansible/roles/squid/tasks/main.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
- name: Install squid package
|
||||
ansible.builtin.apt:
|
||||
name: "squid"
|
||||
notify:
|
||||
- "Restart squid"
|
||||
|
||||
- name: Deploy squid configuration file
|
||||
ansible.builtin.template:
|
||||
src: "templates/squid.conf"
|
||||
dest: "/etc/squid/squid.conf"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
notify:
|
||||
- "Restart squid"
|
||||
|
||||
- name: Enable squid
|
||||
ansible.builtin.systemd:
|
||||
name: "squid"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
notify:
|
||||
- "Restart squid"
|
||||
9387
ansible/roles/squid/templates/squid.conf
Normal file
9387
ansible/roles/squid/templates/squid.conf
Normal file
File diff suppressed because it is too large
Load Diff
4
ansible/roles/www/tasks/main.yml
Normal file
4
ansible/roles/www/tasks/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- name: Install Apache 2
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "apache2"
|
||||
Reference in New Issue
Block a user