WIP
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.DS_Store
|
|
||||||
.ansible/
|
.ansible/
|
||||||
|
__pycache__/
|
||||||
|
.DS_Store
|
||||||
|
|||||||
95
README.md
95
README.md
@@ -67,58 +67,26 @@ Voir: https://github.com/coreruleset/plugin-registry
|
|||||||
|
|
||||||
Fonctionnalités déjà implémentées:
|
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
|
- OWASP CRS
|
||||||
- Multisite (cavec configuration des CRS par site)
|
- Multisite (avec configuration complète des CRS par site)
|
||||||
- Redirection vers nom canonique
|
- Alias avec redirection optionnelle vers nom canonique
|
||||||
- Rediction HTTP vers HTTPS
|
- Redirection HTTP vers HTTPS
|
||||||
- Certificats SSL (automatiques via Let's Encrypt et customs)
|
- Certificats SSL (personnalisés automatiques via Let's Encrypt)
|
||||||
- Redirect (SSL et www et autres)
|
|
||||||
- Filtrage par:
|
- Filtrage par:
|
||||||
- adresses IP
|
- adresses IP
|
||||||
- réseaux IP
|
- réseaux IP
|
||||||
- Antibot par:
|
- Antibot par:
|
||||||
- défi JavaScript
|
- défi JavaScript
|
||||||
- Passive backend checks
|
- Passive backend checks
|
||||||
- Compression Gzip et zstd
|
- Compression Gzip et zstd
|
||||||
- Mieux tester le configuration des CRS
|
|
||||||
- Mode détection sans blocage
|
- Mode détection sans blocage
|
||||||
- Filtrage par:
|
- Filtrage par:
|
||||||
- méthode HTTP
|
- méthode HTTP
|
||||||
|
|
||||||
Urgemment:
|
|
||||||
|
|
||||||
- Connexion à consul
|
|
||||||
- ACL consul
|
|
||||||
- Changement de format de configuration: Caddyfile -> JSON
|
|
||||||
- Lire doc. config JSON de Caddy
|
|
||||||
- Renommer tous les répertoires/utilisateurs caddy -> byow
|
|
||||||
- Collection Ansible
|
|
||||||
|
|
||||||
Fomctionnalités à ajouter:
|
|
||||||
|
|
||||||
- Active backend checks
|
|
||||||
- Antibot par:
|
|
||||||
- Cookie
|
|
||||||
- Captcha
|
|
||||||
- reCAPTCHA
|
|
||||||
- hCaptcha
|
|
||||||
- Turnstile
|
|
||||||
- mCaptcha
|
|
||||||
- Mise en œuvre d'un cluster Redis (ou Consul) pour le partage de informations entre les WAF d'un cluster
|
|
||||||
- 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)
|
|
||||||
- Gestion CORS
|
|
||||||
- Client cache
|
|
||||||
- Proxy cache
|
|
||||||
- Filtrage par pays
|
|
||||||
- Compression Brotli
|
|
||||||
- En-têtes de sécurité:
|
- En-têtes de sécurité:
|
||||||
- HSTS
|
- HSTS
|
||||||
- CSP
|
- CSP
|
||||||
@@ -129,17 +97,54 @@ Fomctionnalités à ajouter:
|
|||||||
- Keep Headers
|
- Keep Headers
|
||||||
- Cookie Flags
|
- Cookie Flags
|
||||||
- Custom headers
|
- Custom headers
|
||||||
|
- suppression d'en-têtes
|
||||||
|
- Collecte des logs via OVH LDP
|
||||||
|
|
||||||
|
Urgemment:
|
||||||
|
|
||||||
|
- Connexion à consul, ACL consul
|
||||||
|
- Collection Ansible
|
||||||
|
- 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
|
||||||
|
- Filtrage par pays
|
||||||
|
- Compression Brotli
|
||||||
- Reverse scan
|
- Reverse scan
|
||||||
- Robots.txt (DarkVisitors API/Community Lists/Custom URLs/Manual Rules)
|
- Robots.txt (DarkVisitors API/Community Lists/Custom URLs/Manual Rules)
|
||||||
- Sessions
|
- Gestion des sessions
|
||||||
- Whitelist
|
- Whitelist
|
||||||
- Bad behavior
|
- Bad behavior
|
||||||
- Auth
|
- Authentification
|
||||||
- Anti DDoS
|
- Anti DDoS
|
||||||
- Greylist
|
- Greylist
|
||||||
- HTML injection
|
- HTML injection
|
||||||
- Metrics (Elasticsearch + Metabase)
|
- Metrics (Elasticsearch + Metabase)
|
||||||
- Static files et FastCGI pour PHP
|
- Static files et FastCGI pour PHP (est-ce une bonne idée ?!)
|
||||||
|
- Lire doc. config JSON de Caddy
|
||||||
|
- Crowdsec
|
||||||
|
- https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list
|
||||||
|
|
||||||
|
|
||||||
## Ressources
|
## Ressources
|
||||||
|
|||||||
21
ansible/filter_plugins/filters.py
Normal file
21
ansible/filter_plugins/filters.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'dict2str': self.dict2str
|
||||||
|
}
|
||||||
|
|
||||||
|
def dict2str(self, d, sep1='=', sep2=';', sep3=''):
|
||||||
|
return sep2.join(
|
||||||
|
[ str(k) + (sep1+str(v) if v!=None and v!='' else '') for k, v in d.items() ]
|
||||||
|
) + sep3
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Tests
|
||||||
|
filters = FilterModule()
|
||||||
|
print(filters.filters())
|
||||||
|
print(filters.dict2str(
|
||||||
|
{"un": 1, "deux": 2, "str": "a string", "rien": None, "bool": True}
|
||||||
|
))
|
||||||
@@ -16,9 +16,10 @@
|
|||||||
- "DNS:{{ ansible_fqdn }}"
|
- "DNS:{{ ansible_fqdn }}"
|
||||||
- "DNS:{{ ansible_hostname }}"
|
- "DNS:{{ ansible_hostname }}"
|
||||||
- "IP:{{ ansible_default_ipv4.address }}"
|
- "IP:{{ ansible_default_ipv4.address }}"
|
||||||
waf_config_sites: "{{ common.sites }}"
|
caddy_config_only: true
|
||||||
|
caddy_sites: "{{ common.sites }}"
|
||||||
roles:
|
roles:
|
||||||
- "local_ca_certs"
|
- "local_ca_certs"
|
||||||
- "waf_config"
|
- "caddy"
|
||||||
tags:
|
tags:
|
||||||
- "waf"
|
- "waf"
|
||||||
|
|||||||
@@ -98,15 +98,14 @@
|
|||||||
unbound_stub_zones:
|
unbound_stub_zones:
|
||||||
- name: "{{ common.consul.datacenter }}.{{ common.consul.domain }}"
|
- name: "{{ common.consul.datacenter }}.{{ common.consul.domain }}"
|
||||||
stub_to: "127.0.0.1@8600"
|
stub_to: "127.0.0.1@8600"
|
||||||
waf_config_sites: "{{ common.sites }}"
|
caddy_sites: "{{ common.sites }}"
|
||||||
ovh_ldp_cluster: "gra2.logs.ovh.com"
|
ovh_ldp_cluster: "gra2.logs.ovh.com"
|
||||||
ovh_ldp_token: ¨{{ secrets.ovh_ldp.token }}
|
ovh_ldp_token: ¨{{ secrets.ovh_ldp.token }}
|
||||||
roles:
|
roles:
|
||||||
- "local_ca_certs"
|
- "local_ca_certs"
|
||||||
- "consul"
|
- "consul"
|
||||||
- "waf_install"
|
- "caddy"
|
||||||
# - "keepalived"
|
# - "keepalived"
|
||||||
- "waf_config"
|
|
||||||
- "unbound"
|
- "unbound"
|
||||||
- "ovh_ldp"
|
- "ovh_ldp"
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
407
ansible/roles/caddy/defaults/main.yml
Normal file
407
ansible/roles/caddy/defaults/main.yml
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
# Defaults
|
||||||
|
caddy_config_only: false
|
||||||
|
caddy_go_version: "1.25.5"
|
||||||
|
caddy_xcaddy_version: "0.4.5"
|
||||||
|
caddy_caddy_version: "2.10.2"
|
||||||
|
caddy_coraza_caddy_version: "2.1.0" # Coraza v3.3.3
|
||||||
|
caddy_owasp_crs_version: "4.22.0"
|
||||||
|
caddy_system_user: "byow"
|
||||||
|
caddy_system_group: "byow"
|
||||||
|
caddy_home_dir: "/opt/{{ caddy_system_user }}"
|
||||||
|
caddy_config_dir: "/etc/{{ caddy_system_user }}"
|
||||||
|
caddy_log_dir: "/var/log/{{ caddy_system_user }}"
|
||||||
|
|
||||||
|
# Cf.: https://github.com/coreruleset/plugin-registry
|
||||||
|
caddy_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"
|
||||||
|
has_after_config: true
|
||||||
|
- name: "roundcube-rule-exclusions"
|
||||||
|
version: "1.0.4"
|
||||||
|
provider: "EsadCetiner"
|
||||||
|
- name: "sogo-rule-exclusions"
|
||||||
|
version: "1.0.4"
|
||||||
|
provider: "EsadCetiner"
|
||||||
|
|
||||||
|
# Required unless not site.custom_cert
|
||||||
|
caddy_email: null
|
||||||
|
|
||||||
|
# Required if site.bot_barrier
|
||||||
|
caddy_bot_barrier_secret: null
|
||||||
|
|
||||||
|
# Optionnal
|
||||||
|
caddy_local_ca_name: null
|
||||||
|
caddy_ca_root: null
|
||||||
|
|
||||||
|
caddy_sites: []
|
||||||
|
# - name: ""
|
||||||
|
# site: ""
|
||||||
|
# paths:
|
||||||
|
# - path: "*"
|
||||||
|
# addrs:
|
||||||
|
# - ""
|
||||||
|
# blacklist:
|
||||||
|
# - ""
|
||||||
|
# aliases:
|
||||||
|
# - ""
|
||||||
|
# crs_exceptions:
|
||||||
|
# before_request:
|
||||||
|
# - ""
|
||||||
|
# after_response:
|
||||||
|
# - ""
|
||||||
|
|
||||||
|
caddy_waf_defaults:
|
||||||
|
redirect_from_aliases: true
|
||||||
|
custom_cert: false
|
||||||
|
custom_cert_file: ""
|
||||||
|
custom_key_file: ""
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header_content_security_policy:
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html#detailed-csp-directives
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy#directives
|
||||||
|
## Fetch directives
|
||||||
|
child-src: "'self'"
|
||||||
|
connect-src: "'self'"
|
||||||
|
font-src: "'self'"
|
||||||
|
img-src: "'self'"
|
||||||
|
manifest-src: "'self'"
|
||||||
|
media-src: "'self'"
|
||||||
|
# Deprecated: prefetch-src: "'self'"
|
||||||
|
object-src: "'none'"
|
||||||
|
script-src: "'none'"
|
||||||
|
script-src-attr: "'none'"
|
||||||
|
script-src-elem: "'none'"
|
||||||
|
style-src: "'self'"
|
||||||
|
style-src-attr: "'self'"
|
||||||
|
style-src-elem: "'self'"
|
||||||
|
default-src: "'self'"
|
||||||
|
## Document directives
|
||||||
|
# base-uri
|
||||||
|
# plugin-types
|
||||||
|
# sandbox
|
||||||
|
## Navigation directives
|
||||||
|
form-action: "'self'"
|
||||||
|
frame-ancestors: "'self'"
|
||||||
|
# https://developer.mozilla.org/fr/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-src
|
||||||
|
frame-src: "'self'"
|
||||||
|
# https://developer.mozilla.org/fr/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/worker-src
|
||||||
|
worker-src: "'self'"
|
||||||
|
# https://developer.mozilla.org/fr/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/block-all-mixed-content
|
||||||
|
block-all-mixed-content:
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/fenced-frame-src
|
||||||
|
fenced-frame-src: "'self'"
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/upgrade-insecure-requests
|
||||||
|
upgrade-insecure-requests:
|
||||||
|
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy
|
||||||
|
header_cross_origin_embedder_policy: "require-corp"
|
||||||
|
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Opener-Policy
|
||||||
|
header_cross_origin_opener_policy: "same-origin"
|
||||||
|
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Resource-Policy
|
||||||
|
header_cross_origin_resource_policy: "same-site"
|
||||||
|
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Permissions-Policy
|
||||||
|
header_permissions_policy:
|
||||||
|
accelerometer: "()"
|
||||||
|
ambient-light-sensor: "()"
|
||||||
|
aria-notify: "()"
|
||||||
|
attribution-reporting: "()"
|
||||||
|
autoplay: "()"
|
||||||
|
bluetooth: "()"
|
||||||
|
browsing-topics: "()"
|
||||||
|
camera: "()"
|
||||||
|
captured-surface-control: "()"
|
||||||
|
compute-pressure: "()"
|
||||||
|
cross-origin-isolated: "()"
|
||||||
|
deferred-fetch: "()"
|
||||||
|
deferred-fetch-minimal: "()"
|
||||||
|
display-capture: "()"
|
||||||
|
encrypted-media: "()"
|
||||||
|
fullscreen: "()"
|
||||||
|
gamepad: "()"
|
||||||
|
geolocation: "()"
|
||||||
|
gyroscope: "()"
|
||||||
|
hid: "()"
|
||||||
|
identity-credentials-get: "()"
|
||||||
|
idle-detection: "()"
|
||||||
|
language-detector: "()"
|
||||||
|
local-fonts: "()"
|
||||||
|
magnetometer: "()"
|
||||||
|
microphone: "()"
|
||||||
|
midi: "()"
|
||||||
|
on-device-speech-recognition: "()"
|
||||||
|
otp-credentials: "()"
|
||||||
|
payment: "()"
|
||||||
|
picture-in-picture: "()"
|
||||||
|
private-state-token-issuance: "()"
|
||||||
|
private-state-token-redemption: "()"
|
||||||
|
publickey-credentials-create: "()"
|
||||||
|
publickey-credentials-get: "()"
|
||||||
|
screen-wake-lock: "()"
|
||||||
|
serial: "()"
|
||||||
|
speaker-selection: "()"
|
||||||
|
storage-access: "()"
|
||||||
|
translator: "()"
|
||||||
|
summarizer: "()"
|
||||||
|
usb: "()"
|
||||||
|
web-share: "()"
|
||||||
|
window-management: "()"
|
||||||
|
xr-spatial-tracking: "()"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#floc-federated-learning-of-cohorts
|
||||||
|
interest-cohort: "()"
|
||||||
|
|
||||||
|
# ???
|
||||||
|
battery: "()"
|
||||||
|
document-domain: "()"
|
||||||
|
execution-while-not-rendered: "()"
|
||||||
|
execution-while-out-of-viewport: "()"
|
||||||
|
navigation-override: "()"
|
||||||
|
|
||||||
|
# https://www.geeksforgeeks.org/computer-networks/http-headers-feature-policy/
|
||||||
|
header_feature_policy:
|
||||||
|
accelerometer: "'none'"
|
||||||
|
ambient-light-sensor: "'none'"
|
||||||
|
autoplay: "'none'"
|
||||||
|
battery: "'none'"
|
||||||
|
camera: "'none'"
|
||||||
|
display-capture: "'none'"
|
||||||
|
document-domain: "'none'"
|
||||||
|
encrypted-media: "'none'"
|
||||||
|
fullscreen: "'none'"
|
||||||
|
geolocation: "'none'"
|
||||||
|
gyroscope: "'none'"
|
||||||
|
layout-animation: "'none'"
|
||||||
|
legacy-image-formats: "'none'"
|
||||||
|
magnetometer: "'none'"
|
||||||
|
microphone: "'none'"
|
||||||
|
midi: "'none'"
|
||||||
|
oversized-images: "'none'"
|
||||||
|
payment: "'none'"
|
||||||
|
picture-in-picture: "'none'"
|
||||||
|
publickey-credentials-get: "'none'"
|
||||||
|
sync-xhr: "'none'"
|
||||||
|
usb: "'none'"
|
||||||
|
screen-wake-lock: "'none'"
|
||||||
|
xr-spatial-tracking: "'none'"
|
||||||
|
|
||||||
|
# ???
|
||||||
|
execution-while-not-rendered: "'none'"
|
||||||
|
execution-while-out-of-viewport: "'none'"
|
||||||
|
navigation-override: "'none'"
|
||||||
|
speaker-selection: "'none'"
|
||||||
|
unoptimized-images: "'none'"
|
||||||
|
unsized-media: "'none'"
|
||||||
|
web-share: "'none'"
|
||||||
|
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy
|
||||||
|
header_referrer_policy: "strict-origin-when-cross-origin"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.html
|
||||||
|
header_strict_transport_security: "max-age=2635200; includeSubDomains"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-content-type-options
|
||||||
|
header_x_content_type_options: "nosniff"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-frame-options
|
||||||
|
header_x_frame_options: "DENY"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-robots-tag
|
||||||
|
header_x_robots_tag: "noindex, nofollow"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#content-type
|
||||||
|
default_content_type: "text/html; charset=UTF-8"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#set-cookie
|
||||||
|
cookies_attributes: "SameSite=None; Secure;"
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-dns-prefetch-control
|
||||||
|
# FIXME
|
||||||
|
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#server
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-powered-by
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-aspnet-version
|
||||||
|
# https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-aspnetmvc-version
|
||||||
|
delete_headers:
|
||||||
|
- "Server"
|
||||||
|
- "X-Powered-By"
|
||||||
|
- "X-AspNet-Version"
|
||||||
|
- "X-AspNetMvc-Version"
|
||||||
|
- "Via"
|
||||||
|
|
||||||
|
custom_headers: {}
|
||||||
|
# - name: <string>
|
||||||
|
# value: <string>
|
||||||
|
|
||||||
|
# caddy-ratelimit
|
||||||
|
rate_events: 1000
|
||||||
|
rate_window: "1m"
|
||||||
|
|
||||||
|
# steffenbusch/caddy-bot-barrier
|
||||||
|
bot_barrier: false
|
||||||
|
|
||||||
|
# corazawaf/coraza-caddy
|
||||||
|
crs_plugins: []
|
||||||
|
log_only: false
|
||||||
|
paranoia_level: 1
|
||||||
|
detection_paranoia_level: null
|
||||||
|
enforce_bodyproc_urlencoded: 1
|
||||||
|
critical_anomaly_score: 5
|
||||||
|
error_anomaly_score: 4
|
||||||
|
warning_anomaly_score: 3
|
||||||
|
notice_anomaly_score: 2
|
||||||
|
inbound_anomaly_score_threshold: 5
|
||||||
|
outbound_anomaly_score_threshold: 4
|
||||||
|
reporting_level: 4
|
||||||
|
max_num_args: 255
|
||||||
|
arg_name_length: 100
|
||||||
|
arg_length: 1000
|
||||||
|
total_arg_length: 64000
|
||||||
|
max_file_size: 10485760 # 10 Mo
|
||||||
|
combined_file_sizes: 20970520 # 20 Mo
|
||||||
|
sampling_percentage: 100
|
||||||
|
allowed_methods:
|
||||||
|
- "GET"
|
||||||
|
- "HEAD"
|
||||||
|
- "POST"
|
||||||
|
- "OPTIONS"
|
||||||
|
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|"
|
||||||
|
restricted_extensions:
|
||||||
|
- ".ani/"
|
||||||
|
- ".asa/"
|
||||||
|
- ".asax/"
|
||||||
|
- ".ascx/"
|
||||||
|
- ".back/"
|
||||||
|
- ".backup/"
|
||||||
|
- ".bak/"
|
||||||
|
- ".bck/"
|
||||||
|
- ".bk/"
|
||||||
|
- ".bkp/"
|
||||||
|
- ".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/"
|
||||||
|
- ".sav/"
|
||||||
|
- ".save/"
|
||||||
|
- ".scr/"
|
||||||
|
- ".sct/"
|
||||||
|
- ".sh/"
|
||||||
|
- ".shs/"
|
||||||
|
- ".sql/"
|
||||||
|
- ".sqlite/"
|
||||||
|
- ".sqlite3/"
|
||||||
|
- ".swp/"
|
||||||
|
- ".sys/"
|
||||||
|
- ".temp/"
|
||||||
|
- ".tlb/"
|
||||||
|
- ".tmp/"
|
||||||
|
- ".vb/"
|
||||||
|
- ".vbe/"
|
||||||
|
- ".vbs/"
|
||||||
|
- ".vbproj/"
|
||||||
|
- ".vsdisco/"
|
||||||
|
- ".vxd/"
|
||||||
|
- ".webinfo/"
|
||||||
|
- ".ws/"
|
||||||
|
- ".wsc/"
|
||||||
|
- ".wsf/"
|
||||||
|
- ".wsh/"
|
||||||
|
- ".xsd/"
|
||||||
|
- ".xsx/"
|
||||||
|
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/"
|
||||||
|
restricted_headers_extended:
|
||||||
|
- "/accept-charset/"
|
||||||
|
allowed_http_versions:
|
||||||
|
- "HTTP/1.0"
|
||||||
|
- "HTTP/1.1"
|
||||||
|
- "HTTP/2"
|
||||||
|
- "HTTP/2.0"
|
||||||
|
- "HTTP/3"
|
||||||
|
- "HTTP/3.0"
|
||||||
|
allowed_request_content_type_charset:
|
||||||
|
- "|utf-8|"
|
||||||
|
- "|iso-8859-1|"
|
||||||
|
- "|iso-8859-15|"
|
||||||
|
- "|windows-1252|"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
- name: Restart Caddy
|
- name: Restart Caddy
|
||||||
ansible.builtin.service:
|
ansible.builtin.service:
|
||||||
name: "caddy"
|
name: "{{ caddy_system_user }}"
|
||||||
state: "restarted"
|
state: "restarted"
|
||||||
@@ -1,55 +1,55 @@
|
|||||||
- name: Create sites config directories
|
- name: Create sites config directories
|
||||||
loop: "{{ waf_config_sites }}"
|
loop: "{{ caddy_sites }}"
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/etc/caddy/sites/{{ item.name }}"
|
path: "{{ caddy_config_dir }}/sites/{{ item.name }}"
|
||||||
state: "directory"
|
state: "directory"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
|
||||||
- name: Generate sites coraza.conf config file
|
- name: Generate sites coraza.conf config file
|
||||||
loop: "{{ waf_config_sites }}"
|
loop: "{{ caddy_sites }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: "site"
|
loop_var: "site"
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: "templates/coraza.conf"
|
src: "templates/coraza.conf"
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/coraza.conf"
|
dest: "{{ caddy_config_dir }}/sites/{{ site.name }}/coraza.conf"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
|
|
||||||
- name: Generate sites crs-setup config file
|
- name: Generate sites crs-setup config file
|
||||||
loop: "{{ waf_config_sites }}"
|
loop: "{{ caddy_sites }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: "site"
|
loop_var: "site"
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: "templates/crs-setup.conf"
|
src: "templates/crs-setup.conf"
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/crs-setup.conf"
|
dest: "{{ caddy_config_dir }}/sites/{{ site.name }}/crs-setup.conf"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
|
|
||||||
- name: Generate sites exclusions before request file
|
- name: Generate sites exclusions before request file
|
||||||
loop: "{{ waf_config_sites }}"
|
loop: "{{ caddy_sites }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: "site"
|
loop_var: "site"
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: "templates/exclusions-request-before.conf"
|
src: "templates/exclusions-request-before.conf"
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
dest: "{{ caddy_config_dir }}/sites/{{ site.name }}/exclusions-request-before.conf"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
|
|
||||||
- name: Generate sites exclusions after response file
|
- name: Generate sites exclusions after response file
|
||||||
loop: "{{ waf_config_sites }}"
|
loop: "{{ caddy_sites }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: "site"
|
loop_var: "site"
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: "templates/exclusions-response-after.conf"
|
src: "templates/exclusions-response-after.conf"
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
dest: "{{ caddy_config_dir }}/sites/{{ site.name }}/exclusions-response-after.conf"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
@@ -57,8 +57,8 @@
|
|||||||
- name: Generate Caddyfile
|
- name: Generate Caddyfile
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: "templates/Caddyfile"
|
src: "templates/Caddyfile"
|
||||||
dest: "/etc/caddy/Caddyfile"
|
dest: "{{ caddy_config_dir }}/Caddyfile"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
@@ -66,8 +66,8 @@
|
|||||||
- name: Copy bot barrier template
|
- name: Copy bot barrier template
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
src: "files/bot_barrier_template.html"
|
src: "files/bot_barrier_template.html"
|
||||||
dest: "/etc/caddy/bot_barrier_template.html"
|
dest: "{{ caddy_config_dir }}/bot_barrier_template.html"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
@@ -11,49 +11,50 @@
|
|||||||
name:
|
name:
|
||||||
- "git"
|
- "git"
|
||||||
- "libnss3-tools"
|
- "libnss3-tools"
|
||||||
|
- "ssl-cert"
|
||||||
|
|
||||||
- name: Create Go directory
|
- name: Create Go directory
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/usr/local/go-{{ waf_install_go_version }}"
|
path: "/usr/local/go-{{ caddy_go_version }}"
|
||||||
state: "directory"
|
state: "directory"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
|
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
ansible.builtin.unarchive:
|
ansible.builtin.unarchive:
|
||||||
src: "https://go.dev/dl/go{{ waf_install_go_version }}.linux-amd64.tar.gz"
|
src: "https://go.dev/dl/go{{ caddy_go_version }}.linux-amd64.tar.gz"
|
||||||
dest: "/usr/local/go-{{ waf_install_go_version }}"
|
dest: "/usr/local/go-{{ caddy_go_version }}"
|
||||||
remote_src: true
|
remote_src: true
|
||||||
|
|
||||||
- name: Link Go
|
- name: Link Go
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
src: "/usr/local/go-{{ waf_install_go_version }}/go/bin/go"
|
src: "/usr/local/go-{{ caddy_go_version }}/go/bin/go"
|
||||||
dest: "/usr/local/bin/go"
|
dest: "/usr/local/bin/go"
|
||||||
state: "link"
|
state: "link"
|
||||||
|
|
||||||
- name: Create xcaddy directory
|
- name: Create xcaddy directory
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/usr/local/xcaddy-{{ waf_install_xcaddy_version }}"
|
path: "/usr/local/xcaddy-{{ caddy_xcaddy_version }}"
|
||||||
state: "directory"
|
state: "directory"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
|
|
||||||
- name: Install xcaddy
|
- name: Install xcaddy
|
||||||
ansible.builtin.unarchive:
|
ansible.builtin.unarchive:
|
||||||
src: "{{ waf_install_xcaddy_download }}/v{{ waf_install_xcaddy_version }}/xcaddy_{{ waf_install_xcaddy_version }}_linux_amd64.tar.gz"
|
src: "{{ caddy_xcaddy_download }}/v{{ caddy_xcaddy_version }}/xcaddy_{{ caddy_xcaddy_version }}_linux_amd64.tar.gz"
|
||||||
dest: "/usr/local/xcaddy-{{ waf_install_xcaddy_version }}"
|
dest: "/usr/local/xcaddy-{{ caddy_xcaddy_version }}"
|
||||||
remote_src: true
|
remote_src: true
|
||||||
|
|
||||||
- name: Link xcaddy
|
- name: Link xcaddy
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
src: "/usr/local/xcaddy-{{ waf_install_xcaddy_version }}/xcaddy"
|
src: "/usr/local/xcaddy-{{ caddy_xcaddy_version }}/xcaddy"
|
||||||
dest: "/usr/local/bin/xcaddy"
|
dest: "/usr/local/bin/xcaddy"
|
||||||
state: "link"
|
state: "link"
|
||||||
|
|
||||||
- name: Create Caddy build command
|
- name: Create Caddy build command
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
waf_install_build_command: >
|
caddy_build_command: >
|
||||||
xcaddy build v{{ waf_install_caddy_version }}
|
xcaddy build v{{ caddy_caddy_version }}
|
||||||
--with github.com/pteich/caddy-tlsconsul
|
--with github.com/pteich/caddy-tlsconsul
|
||||||
--with github.com/corazawaf/coraza-caddy/v2@v{{ waf_install_coraza_caddy_version }}
|
--with github.com/corazawaf/coraza-caddy/v2@v{{ caddy_coraza_caddy_version }}
|
||||||
--with github.com/mholt/caddy-ratelimit
|
--with github.com/mholt/caddy-ratelimit
|
||||||
--with github.com/steffenbusch/caddy-bot-barrier
|
--with github.com/steffenbusch/caddy-bot-barrier
|
||||||
--output /usr/local/bin/caddy
|
--output /usr/local/bin/caddy
|
||||||
@@ -61,74 +62,74 @@
|
|||||||
- name: Test Caddy version
|
- name: Test Caddy version
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
dest: "/usr/local/bin/.caddy.build"
|
dest: "/usr/local/bin/.caddy.build"
|
||||||
content: "{{ waf_install_build_command }}"
|
content: "{{ caddy_build_command }}"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
register: waf_install_test_caddy_version
|
register: caddy_test_caddy_version
|
||||||
|
|
||||||
- name: Build Caddy
|
- name: Build Caddy
|
||||||
# noqa: no-handler
|
# noqa: no-handler
|
||||||
when: "waf_install_test_caddy_version.changed"
|
when: "caddy_test_caddy_version.changed"
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
cmd: "{{ waf_install_build_command }}"
|
cmd: "{{ caddy_build_command }}"
|
||||||
creates: "/usr/local/bin/caddy"
|
creates: "/usr/local/bin/caddy"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
|
|
||||||
- name: Create caddy system group
|
- name: Create Caddy system group
|
||||||
ansible.builtin.group:
|
ansible.builtin.group:
|
||||||
name: "caddy"
|
name: "{{ caddy_system_group }}"
|
||||||
system: true
|
system: true
|
||||||
|
|
||||||
- name: Create caddy system user
|
- name: Create Caddy system user
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "caddy"
|
name: "{{ caddy_system_user }}"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
groups: ["ssl-cert"]
|
groups: ["ssl-cert"]
|
||||||
password: "!"
|
password: "!"
|
||||||
system: true
|
system: true
|
||||||
home: "/opt/caddy"
|
home: "{{ caddy_home_dir }}"
|
||||||
|
|
||||||
- name: Create caddy config directories
|
- name: Create Caddy config directories
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
state: "directory"
|
state: "directory"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
loop:
|
loop:
|
||||||
- "/etc/caddy"
|
- "{{ caddy_config_dir }}"
|
||||||
- "/etc/caddy/plugins"
|
- "{{ caddy_config_dir }}/crs-plugins"
|
||||||
- "/etc/caddy/sites"
|
- "{{ caddy_config_dir }}/sites"
|
||||||
|
|
||||||
- name: Create caddy log dir
|
- name: Create Caddy log dir
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/var/log/caddy"
|
path: "{{ caddy_log_dir }}"
|
||||||
state: "directory"
|
state: "directory"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0770"
|
mode: "0770"
|
||||||
|
|
||||||
- name: Install OWASP CRS
|
- name: Install OWASP CRS
|
||||||
ansible.builtin.unarchive:
|
ansible.builtin.unarchive:
|
||||||
src: "https://github.com/coreruleset/coreruleset/archive/refs/tags/v{{ waf_install_owasp_crs_version }}.tar.gz"
|
src: "https://github.com/coreruleset/coreruleset/archive/refs/tags/v{{ caddy_owasp_crs_version }}.tar.gz"
|
||||||
dest: "/etc/caddy"
|
dest: "{{ caddy_config_dir }}"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
remote_src: true
|
remote_src: true
|
||||||
|
|
||||||
- name: Install plugins
|
- name: Install plugins
|
||||||
loop: "{{ waf_install_crs_plugins }}"
|
loop: "{{ caddy_crs_plugins }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: "plugin"
|
loop_var: "plugin"
|
||||||
ansible.builtin.include_tasks: "install_plugin.yml"
|
ansible.builtin.include_tasks: "plugin_install.yml"
|
||||||
|
|
||||||
- name: Deploy caddy service file
|
- name: Deploy caddy service file
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: "templates/caddy.service"
|
src: "templates/caddy.service"
|
||||||
dest: "/etc/systemd/system/caddy.service"
|
dest: "/etc/systemd/system/{{ caddy_system_user }}.service"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
|
|
||||||
- name: Enable Caddy
|
- name: Enable Caddy
|
||||||
ansible.builtin.service:
|
ansible.builtin.service:
|
||||||
name: "caddy"
|
name: "{{ caddy_system_user }}"
|
||||||
enabled: true
|
enabled: true
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
6
ansible/roles/caddy/tasks/main.yml
Normal file
6
ansible/roles/caddy/tasks/main.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- name: Install Caddy
|
||||||
|
when: "not(caddy_config_only)"
|
||||||
|
ansible.builtin.include_tasks: "caddy_install.yml"
|
||||||
|
|
||||||
|
- name: Config Caddy
|
||||||
|
ansible.builtin.include_tasks: "caddy_config.yml"
|
||||||
@@ -3,31 +3,31 @@
|
|||||||
url: "https://github.com/{{ plugin.provider | default('coreruleset') }}/{{ plugin.name }}-plugin/archive/refs/tags/v{{ plugin.version }}.tar.gz"
|
url: "https://github.com/{{ plugin.provider | default('coreruleset') }}/{{ plugin.name }}-plugin/archive/refs/tags/v{{ plugin.version }}.tar.gz"
|
||||||
dest: "/usr/local/src/"
|
dest: "/usr/local/src/"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
register: "waf_install_plugin_downloaded"
|
register: "caddy_plugin_downloaded"
|
||||||
|
|
||||||
- name: Deploy plugin {{ plugin.name }}
|
- name: Deploy plugin {{ plugin.name }}
|
||||||
# noqa: no-handler
|
# noqa: no-handler
|
||||||
when: "waf_install_plugin_downloaded.changed"
|
when: "caddy_plugin_downloaded.changed"
|
||||||
block:
|
block:
|
||||||
|
|
||||||
- name: Get temp dir {{ plugin.name }}
|
- name: Get temp dir {{ plugin.name }}
|
||||||
ansible.builtin.tempfile:
|
ansible.builtin.tempfile:
|
||||||
state: "directory"
|
state: "directory"
|
||||||
register: "waf_install_temp_plugin_dir"
|
register: "caddy_temp_plugin_dir"
|
||||||
|
|
||||||
- name: Unarchive plugin {{ plugin.name }}
|
- name: Unarchive plugin {{ plugin.name }}
|
||||||
ansible.builtin.unarchive:
|
ansible.builtin.unarchive:
|
||||||
src: "/usr/local/src/{{ plugin.name }}-plugin-{{ plugin.version }}.tar.gz"
|
src: "/usr/local/src/{{ plugin.name }}-plugin-{{ plugin.version }}.tar.gz"
|
||||||
dest: "{{ waf_install_temp_plugin_dir.path }}"
|
dest: "{{ caddy_temp_plugin_dir.path }}"
|
||||||
remote_src: true
|
remote_src: true
|
||||||
|
|
||||||
- name: Copy plugin files {{ plugin.name }}
|
- name: Copy plugin files {{ plugin.name }}
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
src: "{{ waf_install_temp_plugin_dir.path }}/{{ plugin.name }}-plugin-{{ plugin.version }}/plugins/"
|
src: "{{ caddy_temp_plugin_dir.path }}/{{ plugin.name }}-plugin-{{ plugin.version }}/plugins/"
|
||||||
dest: "/etc/caddy/plugins/"
|
dest: "{{ caddy_config_dir }}/crs-plugins/"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
# directory_mode: "0750"
|
# directory_mode: "0750"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
remote_src: true
|
remote_src: true
|
||||||
notify:
|
notify:
|
||||||
- "Restart Caddy"
|
- "Restart Caddy"
|
||||||
@@ -36,20 +36,20 @@
|
|||||||
when: "not(plugin.has_after_config | default(false))"
|
when: "not(plugin.has_after_config | default(false))"
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
content: ""
|
content: ""
|
||||||
dest: "/etc/caddy/plugins/{{ plugin.name }}-after.conf"
|
dest: "{{ caddy_config_dir }}/crs-plugins/{{ plugin.name }}-after.conf"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
|
|
||||||
# FIXME: bad hack, why is it required?
|
# FIXME: bad hack, why is it required?
|
||||||
- name: Adjust /etc/caddy/plugins permissions
|
- name: Adjust plugins diretory permissions
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/etc/caddy/plugins"
|
path: "{{ caddy_config_dir }}/crs-plugins"
|
||||||
state: "directory"
|
state: "directory"
|
||||||
group: "caddy"
|
group: "{{ caddy_system_group }}"
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
|
||||||
- name: Delete temp dir {{ plugin.name }}
|
- name: Delete temp dir {{ plugin.name }}
|
||||||
when: "waf_install_temp_plugin_dir.path is defined"
|
when: "caddy_temp_plugin_dir.path is defined"
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ waf_install_temp_plugin_dir.path }}"
|
path: "{{ caddy_temp_plugin_dir.path }}"
|
||||||
state: "absent"
|
state: "absent"
|
||||||
152
ansible/roles/caddy/templates/Caddyfile
Normal file
152
ansible/roles/caddy/templates/Caddyfile
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
{
|
||||||
|
grace_period 10s
|
||||||
|
order coraza_waf first
|
||||||
|
{% if caddy_email | default(None) != None %}
|
||||||
|
email "{{ caddy_email }}"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if caddy_ca_root | default(None) != None %}
|
||||||
|
tls {
|
||||||
|
ca_root "{{ caddy_ca_root }}"
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
log waf {
|
||||||
|
format json
|
||||||
|
include "http.handlers.waf"
|
||||||
|
output stdout
|
||||||
|
}
|
||||||
|
{% if caddy_local_ca_name | default(None) != None %}
|
||||||
|
|
||||||
|
pki {
|
||||||
|
ca local {
|
||||||
|
name "{{ caddy_local_ca_name }}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
|
||||||
|
{% for site in caddy_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 {{ caddy_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 {{ caddy_config_dir }}/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 "{{ caddy_config_dir }}/sites/{{ site.name }}/coraza.conf"
|
||||||
|
Include "{{ caddy_config_dir }}/sites/{{ site.name }}/crs-setup.conf"
|
||||||
|
{% for plugin in site.crs_plugins | default(caddy_waf_defaults.crs_plugins) %}
|
||||||
|
Include "{{ caddy_config_dir }}/crs-plugins/{{ plugin }}-config.conf"
|
||||||
|
Include "{{ caddy_config_dir }}/crs-plugins/{{ plugin }}-before.conf"
|
||||||
|
{% endfor %}
|
||||||
|
Include "{{ caddy_config_dir }}/sites/{{ site.name }}/exclusions-request-before.conf"
|
||||||
|
Include "{{ caddy_config_dir }}/coreruleset-{{ caddy_owasp_crs_version }}/rules/*.conf"
|
||||||
|
Include "{{ caddy_config_dir }}/sites/{{ site.name }}/exclusions-response-after.conf"
|
||||||
|
{% for plugin in site.crs_plugins | default(caddy_waf_defaults.crs_plugins) %}
|
||||||
|
Include "{{ caddy_config_dir }}/crs-plugins/{{ plugin }}-after.conf"
|
||||||
|
{% endfor %}
|
||||||
|
SecRuleEngine On
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
Content-Security-Policy "{{ caddy_waf_defaults.header_content_security_policy | combine(site.header_content_security_policy | default({})) | dict2str(sep1=' ', sep2='; ', sep3=';') }}"
|
||||||
|
Cross-Origin-Embedder-Policy "{{ site.header_cross_origin_embedder_policy | default(caddy_waf_defaults.header_cross_origin_embedder_policy) }}"
|
||||||
|
Cross-Origin-Opener-Policy "{{ site.header_cross_origin_opener_policy | default(caddy_waf_defaults.header_cross_origin_opener_policy) }}"
|
||||||
|
Cross-Origin-Resource-Policy "{{ site.header_cross_origin_resource_policy | default(caddy_waf_defaults.header_cross_origin_resource_policy) }}"
|
||||||
|
Feature-Policy "{{ caddy_waf_defaults.header_feature_policy | combine(site.header_feature_policy | default({})) | dict2str(sep1=' ', sep2='; ', sep3=';') }}"
|
||||||
|
Permissions-Policy "{{ caddy_waf_defaults.header_permissions_policy | combine(site.header_permissions_policy | default({})) | dict2str(sep2=', ') }}"
|
||||||
|
Referrer-Policy "{{ site.header_referrer_policy | default(caddy_waf_defaults.header_referrer_policy) }}"
|
||||||
|
Strict-Transport-Security "{{ site.header_strict_transport_security | default(caddy_waf_defaults.header_strict_transport_security) }}"
|
||||||
|
X-Content-Type-Options "{{ site.header_x_content_type_options | default(caddy_waf_defaults.header_x_content_type_options) }}"
|
||||||
|
X-Frame-Options "{{ site.header_x_frame_options | default(caddy_waf_defaults.header_x_frame_options) }}"
|
||||||
|
X-Robots-Tag "{{ site.header_x_robots_tag | default(caddy_waf_defaults.header_x_robots_tag) }}"
|
||||||
|
?Content-Type "{{ site.default_content_type | default(caddy_waf_defaults.default_content_type) }}"
|
||||||
|
>Set-Cookie "(.*)" "$1; {{ site.cookies_attributes | default(caddy_waf_defaults.cookies_attributes) }}"
|
||||||
|
{% for header in site.delete_headers | default(caddy_waf_defaults.delete_headers) %}
|
||||||
|
-{{ header }}
|
||||||
|
{% endfor %}
|
||||||
|
{% for header in site.custom_headers | default(caddy_waf_defaults.custom_headers) %}
|
||||||
|
{{ header.name }} "{{ header.value }}"
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_errors 403 {
|
||||||
|
header X-Blocked "true"
|
||||||
|
respond "Your request was blocked."
|
||||||
|
}
|
||||||
|
|
||||||
|
log {
|
||||||
|
format json
|
||||||
|
output file {{ caddy_log_dir }}/site_{{ site.name }}.log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
@@ -6,10 +6,10 @@ Requires=network-online.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=notify
|
Type=notify
|
||||||
User=caddy
|
User={{ caddy_system_user }}
|
||||||
Group=caddy
|
Group={{ caddy_system_group }}
|
||||||
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
|
ExecStart=/usr/local/bin/caddy run --environ --config {{ caddy_config_dir }}/Caddyfile
|
||||||
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --force
|
ExecReload=/usr/local/bin/caddy reload --config {{ caddy_config_dir }}/Caddyfile --force
|
||||||
TimeoutStopSec=15s
|
TimeoutStopSec=15s
|
||||||
LimitNOFILE=1048576
|
LimitNOFILE=1048576
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
@@ -126,7 +126,7 @@ SecDataDir /tmp/
|
|||||||
# 3: Info
|
# 3: Info
|
||||||
# 4-8: Debug
|
# 4-8: Debug
|
||||||
# 9: Trace (most verbose)
|
# 9: Trace (most verbose)
|
||||||
SecDebugLog /var/log/caddy/coraza-debug.log
|
SecDebugLog {{ caddy_log_dir }}/coraza-debug.log
|
||||||
SecDebugLogLevel 4
|
SecDebugLogLevel 4
|
||||||
|
|
||||||
|
|
||||||
@@ -10,9 +10,9 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(waf_config_defaults.paranoia_level) }}"
|
setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(caddy_waf_defaults.paranoia_level) }}"
|
||||||
{% if site.detection_paranoia_level | default(waf_config_defaults.detection_paranoia_level) != None %}
|
{% if site.detection_paranoia_level | default(caddy_waf_defaults.detection_paranoia_level) != None %}
|
||||||
|
|
||||||
## Detection paranoia level
|
## Detection paranoia level
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -22,8 +22,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(waf_config_defaults.detection_paranoia_level) }}"
|
setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(caddy_waf_defaults.detection_paranoia_level) }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
## Enforce Body Processor URLENCODED
|
## Enforce Body Processor URLENCODED
|
||||||
@@ -34,8 +34,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(waf_config_defaults.enforce_bodyproc_urlencoded) }}"
|
setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(caddy_waf_defaults.enforce_bodyproc_urlencoded) }}"
|
||||||
|
|
||||||
## Anomaly Scoring Mode Severity Levels
|
## Anomaly Scoring Mode Severity Levels
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -45,11 +45,11 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.critical_anomaly_score={{ site.critical_anomaly_score | default(waf_config_defaults.critical_anomaly_score) }},\
|
setvar:tx.critical_anomaly_score={{ site.critical_anomaly_score | default(caddy_waf_defaults.critical_anomaly_score) }},\
|
||||||
setvar:tx.error_anomaly_score={{ site.error_anomaly_score | default(waf_config_defaults.error_anomaly_score) }},\
|
setvar:tx.error_anomaly_score={{ site.error_anomaly_score | default(caddy_waf_defaults.error_anomaly_score) }},\
|
||||||
setvar:tx.warning_anomaly_score={{ site.warning_anomaly_score | default(waf_config_defaults.warning_anomaly_score) }},\
|
setvar:tx.warning_anomaly_score={{ site.warning_anomaly_score | default(caddy_waf_defaults.warning_anomaly_score) }},\
|
||||||
setvar:tx.notice_anomaly_score={{ site.notice_anomaly_score | default(waf_config_defaults.notice_anomaly_score) }}"
|
setvar:tx.notice_anomaly_score={{ site.notice_anomaly_score | default(caddy_waf_defaults.notice_anomaly_score) }}"
|
||||||
|
|
||||||
## Anomaly Scoring Mode Blocking Threshold Levels
|
## Anomaly Scoring Mode Blocking Threshold Levels
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -59,9 +59,9 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.inbound_anomaly_score_threshold={% if site.log_only | default(waf_config_defaults.log_only) %}1000{% else %}{{ site.inbound_anomaly_score_threshold | default(waf_config_defaults.inbound_anomaly_score_threshold) }}{% endif %},\
|
setvar:tx.inbound_anomaly_score_threshold={% if site.log_only | default(caddy_waf_defaults.log_only) %}1000{% else %}{{ site.inbound_anomaly_score_threshold | default(caddy_waf_defaults.inbound_anomaly_score_threshold) }}{% endif %},\
|
||||||
setvar:tx.outbound_anomaly_score_threshold={% if site.log_only | default(waf_config_defaults.log_only) %}1000{% else %}{{ site.outbound_anomaly_score_threshold | default(waf_config_defaults.outbound_anomaly_score_threshold) }}{% endif %}"
|
setvar:tx.outbound_anomaly_score_threshold={% if site.log_only | default(caddy_waf_defaults.log_only) %}1000{% else %}{{ site.outbound_anomaly_score_threshold | default(caddy_waf_defaults.outbound_anomaly_score_threshold) }}{% endif %}"
|
||||||
|
|
||||||
## Application Specific Rule Exclusions
|
## Application Specific Rule Exclusions
|
||||||
# FIXME
|
# FIXME
|
||||||
@@ -87,8 +87,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.reporting_level={{ site.reporting_level | default(waf_config_defaults.reporting_level) }}"
|
setvar:tx.reporting_level={{ site.reporting_level | default(caddy_waf_defaults.reporting_level) }}"
|
||||||
|
|
||||||
## Early Anomaly Scoring Mode Blocking
|
## Early Anomaly Scoring Mode Blocking
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -98,7 +98,7 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.early_blocking=0"
|
setvar:tx.early_blocking=0"
|
||||||
|
|
||||||
## Initialize Default Collections
|
## Initialize Default Collections
|
||||||
@@ -109,7 +109,7 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.enable_default_collections=1"
|
setvar:tx.enable_default_collections=1"
|
||||||
|
|
||||||
## HTTP Policy Settings
|
## HTTP Policy Settings
|
||||||
@@ -120,8 +120,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_methods={{ site.allowed_methods | default(waf_config_defaults.allowed_methods) | join(" ") }}'"
|
setvar:'tx.allowed_methods={{ site.allowed_methods | default(caddy_waf_defaults.allowed_methods) | join(" ") }}'"
|
||||||
|
|
||||||
# Content-Types that a client is allowed to send in a request
|
# Content-Types that a client is allowed to send in a request
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -131,8 +131,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(waf_config_defaults.allowed_request_content_type) | join(" ") }}'"
|
setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(caddy_waf_defaults.allowed_request_content_type) | join(" ") }}'"
|
||||||
|
|
||||||
## Allowed HTTP versions
|
## Allowed HTTP versions
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -142,8 +142,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(waf_config_defaults.allowed_http_versions) | join(" ") }}'"
|
setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(caddy_waf_defaults.allowed_http_versions) | join(" ") }}'"
|
||||||
|
|
||||||
## Forbidden file extensions
|
## Forbidden file extensions
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -153,8 +153,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(waf_config_defaults.restricted_extensions) | join(" ") }}'"
|
setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(caddy_waf_defaults.restricted_extensions) | join(" ") }}'"
|
||||||
|
|
||||||
## Restricted request headers
|
## Restricted request headers
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -164,8 +164,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.restricted_headers_basic={{ site.restricted_headers_basic | default(waf_config_defaults.restricted_headers_basic) | join(" ") }}'"
|
setvar:'tx.restricted_headers_basic={{ site.restricted_headers_basic | default(caddy_waf_defaults.restricted_headers_basic) | join(" ") }}'"
|
||||||
|
|
||||||
## Extended restricted request headers (forbidden at a higher paranoia level)
|
## Extended restricted request headers (forbidden at a higher paranoia level)
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -175,8 +175,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.restricted_headers_extended={{ site.restricted_headers_extended | default(waf_config_defaults.restricted_headers_extended) | join(" ") }}'"
|
setvar:'tx.restricted_headers_extended={{ site.restricted_headers_extended | default(caddy_waf_defaults.restricted_headers_extended) | join(" ") }}'"
|
||||||
|
|
||||||
# Content-Types charsets that a client is allowed to send in a request
|
# Content-Types charsets that a client is allowed to send in a request
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -186,8 +186,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_request_content_type_charset={{ waf_config_defaults.allowed_request_content_type_charset | default(waf_config_defaults.allowed_request_content_type_charset) | join(" ") }}'"
|
setvar:'tx.allowed_request_content_type_charset={{ caddy_waf_defaults.allowed_request_content_type_charset | default(caddy_waf_defaults.allowed_request_content_type_charset) | join(" ") }}'"
|
||||||
|
|
||||||
# Block request if number of arguments is too high
|
# Block request if number of arguments is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -197,8 +197,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.max_num_args={{ site.max_num_args | default(waf_config_defaults.max_num_args) }}"
|
setvar:tx.max_num_args={{ site.max_num_args | default(caddy_waf_defaults.max_num_args) }}"
|
||||||
|
|
||||||
# Block request if the length of any argument name is too high
|
# Block request if the length of any argument name is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -208,8 +208,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.arg_name_length={{ site.arg_name_length | default(waf_config_defaults.arg_name_length) }}"
|
setvar:tx.arg_name_length={{ site.arg_name_length | default(caddy_waf_defaults.arg_name_length) }}"
|
||||||
|
|
||||||
# Block request if the length of any argument value is too high
|
# Block request if the length of any argument value is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -219,8 +219,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.arg_length={{ site.arg_length | default(waf_config_defaults.arg_length) }}"
|
setvar:tx.arg_length={{ site.arg_length | default(caddy_waf_defaults.arg_length) }}"
|
||||||
|
|
||||||
# Block request if the total length of all combined arguments is too high
|
# Block request if the total length of all combined arguments is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -230,8 +230,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.total_arg_length={{ site.total_arg_length | default(waf_config_defaults.total_arg_length) }}"
|
setvar:tx.total_arg_length={{ site.total_arg_length | default(caddy_waf_defaults.total_arg_length) }}"
|
||||||
|
|
||||||
# Block request if the file size of any individual uploaded file is too high
|
# Block request if the file size of any individual uploaded file is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -241,8 +241,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.max_file_size={{ site.max_file_size | default(waf_config_defaults.max_file_size) }}"
|
setvar:tx.max_file_size={{ site.max_file_size | default(caddy_waf_defaults.max_file_size) }}"
|
||||||
|
|
||||||
# Block request if the total size of all combined uploaded files is too high
|
# Block request if the total size of all combined uploaded files is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -252,8 +252,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(waf_config_defaults.combined_file_sizes) }}"
|
setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(caddy_waf_defaults.combined_file_sizes) }}"
|
||||||
|
|
||||||
## Easing In / Sampling Percentage
|
## Easing In / Sampling Percentage
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -262,8 +262,8 @@ SecAction \
|
|||||||
pass,\
|
pass,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.sampling_percentage={{ site.sampling_percentage | default(waf_config_defaults.sampling_percentage) }}"
|
setvar:tx.sampling_percentage={{ site.sampling_percentage | default(caddy_waf_defaults.sampling_percentage) }}"
|
||||||
|
|
||||||
## Check UTF-8 encoding
|
## Check UTF-8 encoding
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -273,7 +273,7 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.crs_validate_utf8_encoding=1"
|
setvar:tx.crs_validate_utf8_encoding=1"
|
||||||
|
|
||||||
## Skip Checking Responses
|
## Skip Checking Responses
|
||||||
@@ -290,7 +290,7 @@ SecAction \
|
|||||||
# t:none,\
|
# t:none,\
|
||||||
# nolog,\
|
# nolog,\
|
||||||
# tag:'OWASP_CRS',\
|
# tag:'OWASP_CRS',\
|
||||||
# ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
# ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
# setvar:tx.crs_skip_response_analysis=1"
|
# setvar:tx.crs_skip_response_analysis=1"
|
||||||
|
|
||||||
## End of setup
|
## End of setup
|
||||||
@@ -301,5 +301,5 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ caddy_owasp_crs_version }}',\
|
||||||
setvar:tx.crs_setup_version={{ waf_config_owasp_crs_version | regex_replace('\.', '') }}"
|
setvar:tx.crs_setup_version={{ caddy_owasp_crs_version | regex_replace('\.', '') }}"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{% for exclusion in site.crs_exceptions.before_request | default([]) %}
|
||||||
|
{{ exclusion }}
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{% for exclusion in site.crs_exceptions.after_response | default([]) %}
|
||||||
|
{{ exclusion }}
|
||||||
|
{% endfor %}
|
||||||
1
ansible/roles/caddy/vars/main.yml
Normal file
1
ansible/roles/caddy/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
caddy_xcaddy_download: "https://github.com/caddyserver/xcaddy/releases/download"
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
# Defaults
|
|
||||||
waf_config_owasp_crs_version: "4.22.0"
|
|
||||||
|
|
||||||
# Required unless not site.custom_cert
|
|
||||||
waf_config_email: null
|
|
||||||
|
|
||||||
# Required if site.bot_barrier
|
|
||||||
waf_config_bot_barrier_secret: null
|
|
||||||
|
|
||||||
# Optionnal
|
|
||||||
waf_config_local_ca_name: null
|
|
||||||
waf_config_ca_root: null
|
|
||||||
|
|
||||||
waf_config_sites: []
|
|
||||||
# - name: ""
|
|
||||||
# site: ""
|
|
||||||
# paths:
|
|
||||||
# - path: "*"
|
|
||||||
# addrs:
|
|
||||||
# - ""
|
|
||||||
# blacklist:
|
|
||||||
# - ""
|
|
||||||
# aliases:
|
|
||||||
# - ""
|
|
||||||
# exceptions:
|
|
||||||
# before_request:
|
|
||||||
# - ""
|
|
||||||
# after_response:
|
|
||||||
# - ""
|
|
||||||
|
|
||||||
waf_config_defaults:
|
|
||||||
redirect_from_aliases: true
|
|
||||||
custom_cert: true
|
|
||||||
custom_cert_file: ""
|
|
||||||
custom_key_file: ""
|
|
||||||
plugins: []
|
|
||||||
|
|
||||||
# caddy-ratelimit
|
|
||||||
rate_events: 1000
|
|
||||||
rate_window: "1m"
|
|
||||||
|
|
||||||
# steffenbusch/caddy-bot-barrier
|
|
||||||
bot_barrier: false
|
|
||||||
|
|
||||||
# corazawaf/coraza-caddy
|
|
||||||
log_only: false
|
|
||||||
paranoia_level: 1
|
|
||||||
detection_paranoia_level: null
|
|
||||||
enforce_bodyproc_urlencoded: 1
|
|
||||||
critical_anomaly_score: 5
|
|
||||||
error_anomaly_score: 4
|
|
||||||
warning_anomaly_score: 3
|
|
||||||
notice_anomaly_score: 2
|
|
||||||
inbound_anomaly_score_threshold: 5
|
|
||||||
outbound_anomaly_score_threshold: 4
|
|
||||||
reporting_level: 4
|
|
||||||
max_num_args: 255
|
|
||||||
arg_name_length: 100
|
|
||||||
arg_length: 1000
|
|
||||||
total_arg_length: 64000
|
|
||||||
max_file_size: 10485760 # 10 Mo
|
|
||||||
combined_file_sizes: 20970520 # 20 Mo
|
|
||||||
sampling_percentage: 100
|
|
||||||
allowed_methods:
|
|
||||||
- "GET"
|
|
||||||
- "HEAD"
|
|
||||||
- "POST"
|
|
||||||
- "OPTIONS"
|
|
||||||
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|"
|
|
||||||
restricted_extensions:
|
|
||||||
- ".ani/"
|
|
||||||
- ".asa/"
|
|
||||||
- ".asax/"
|
|
||||||
- ".ascx/"
|
|
||||||
- ".back/"
|
|
||||||
- ".backup/"
|
|
||||||
- ".bak/"
|
|
||||||
- ".bck/"
|
|
||||||
- ".bk/"
|
|
||||||
- ".bkp/"
|
|
||||||
- ".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/"
|
|
||||||
- ".sav/"
|
|
||||||
- ".save/"
|
|
||||||
- ".scr/"
|
|
||||||
- ".sct/"
|
|
||||||
- ".sh/"
|
|
||||||
- ".shs/"
|
|
||||||
- ".sql/"
|
|
||||||
- ".sqlite/"
|
|
||||||
- ".sqlite3/"
|
|
||||||
- ".swp/"
|
|
||||||
- ".sys/"
|
|
||||||
- ".temp/"
|
|
||||||
- ".tlb/"
|
|
||||||
- ".tmp/"
|
|
||||||
- ".vb/"
|
|
||||||
- ".vbe/"
|
|
||||||
- ".vbs/"
|
|
||||||
- ".vbproj/"
|
|
||||||
- ".vsdisco/"
|
|
||||||
- ".vxd/"
|
|
||||||
- ".webinfo/"
|
|
||||||
- ".ws/"
|
|
||||||
- ".wsc/"
|
|
||||||
- ".wsf/"
|
|
||||||
- ".wsh/"
|
|
||||||
- ".xsd/"
|
|
||||||
- ".xsx/"
|
|
||||||
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/"
|
|
||||||
restricted_headers_extended:
|
|
||||||
- "/accept-charset/"
|
|
||||||
allowed_http_versions:
|
|
||||||
- "HTTP/1.0"
|
|
||||||
- "HTTP/1.1"
|
|
||||||
- "HTTP/2"
|
|
||||||
- "HTTP/2.0"
|
|
||||||
- "HTTP/3"
|
|
||||||
- "HTTP/3.0"
|
|
||||||
allowed_request_content_type_charset:
|
|
||||||
- "|utf-8|"
|
|
||||||
- "|iso-8859-1|"
|
|
||||||
- "|iso-8859-15|"
|
|
||||||
- "|windows-1252|"
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
{
|
|
||||||
grace_period 10s
|
|
||||||
order coraza_waf first
|
|
||||||
{% if waf_config_email | default(None) != None %}
|
|
||||||
email "{{ waf_config_email }}"
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if waf_config_ca_root | default(None) != None %}
|
|
||||||
tls {
|
|
||||||
ca_root "{{ waf_config_ca_root }}"
|
|
||||||
}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
log waf {
|
|
||||||
format json
|
|
||||||
include "http.handlers.waf"
|
|
||||||
output stdout
|
|
||||||
}
|
|
||||||
{% if waf_config_local_ca_name | default(None) != None %}
|
|
||||||
|
|
||||||
pki {
|
|
||||||
ca local {
|
|
||||||
name "{{ waf_config_local_ca_name }}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
}
|
|
||||||
|
|
||||||
{% for site in waf_config_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 {{ waf_config_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"
|
|
||||||
{% for plugin in site.plugins | default(waf_config_defaults.plugins) %}
|
|
||||||
Include "/etc/caddy/plugins/{{ plugin }}-config.conf"
|
|
||||||
Include "/etc/caddy/plugins/{{ plugin }}-before.conf"
|
|
||||||
{% endfor %}
|
|
||||||
Include "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
|
||||||
Include "/etc/caddy/coreruleset-{{ waf_config_owasp_crs_version }}/rules/*.conf"
|
|
||||||
Include "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
|
||||||
{% for plugin in site.plugins | default(waf_config_defaults.plugins) %}
|
|
||||||
Include "/etc/caddy/plugins/{{ plugin }}-after.conf"
|
|
||||||
{% endfor %}
|
|
||||||
SecRuleEngine On
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
# Cf. https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html
|
|
||||||
header {
|
|
||||||
# Access-Control-Allow-Origin "https://secure.gravatar.com"
|
|
||||||
Content-Security-Policy "upgrade-insecure-requests; worker-src 'self' blob:; connect-src 'self'; media-src 'self'; img-src 'self' data: https://secure.gravatar.com/avatar/; font-src 'self' data:; style-src 'self' 'unsafe-inline'; object-src 'none'; frame-src 'self' blob:; child-src 'self'; form-action 'self'; frame-ancestors 'self'"
|
|
||||||
# Cross-Origin-Embedder-Policy "require-corp"
|
|
||||||
Cross-Origin-Opener-Policy "same-origin"
|
|
||||||
Cross-Origin-Resource-Policy "same-site"
|
|
||||||
Permissions-Policy "geolocation=(), camera=(), microphone=(), interest-cohort=()"
|
|
||||||
Referrer-Policy "strict-origin-when-cross-origin"
|
|
||||||
Strict-Transport-Security "max-age=2635200; includeSubDomains"
|
|
||||||
X-Content-Type-Options "nosniff"
|
|
||||||
X-Frame-Options "DENY"
|
|
||||||
X-Robots-Tag "noindex, nofollow"
|
|
||||||
?Content-Type "text/html; charset=UTF-8"
|
|
||||||
>Set-Cookie "(.*)" "$1; SameSite=None; Secure;"
|
|
||||||
-Server
|
|
||||||
-Via
|
|
||||||
-X-Powered-By
|
|
||||||
-X-AspNet-Version
|
|
||||||
-X-AspNetMvc-Version
|
|
||||||
}
|
|
||||||
|
|
||||||
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 %}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{% for exclusion in site.exceptions.before_request | default([]) %}
|
|
||||||
{{ exclusion }}
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{% for exclusion in site.exceptions.after_response | default([]) %}
|
|
||||||
{{ exclusion }}
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
waf_install_go_version: "1.25.5"
|
|
||||||
waf_install_xcaddy_version: "0.4.5"
|
|
||||||
waf_install_caddy_version: "2.10.2"
|
|
||||||
waf_install_coraza_caddy_version: "2.1.0" # Coraza v3.3.3
|
|
||||||
waf_install_owasp_crs_version: "4.22.0"
|
|
||||||
|
|
||||||
# Cf.: https://github.com/coreruleset/plugin-registry
|
|
||||||
waf_install_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"
|
|
||||||
has_after_config: true
|
|
||||||
- name: "roundcube-rule-exclusions"
|
|
||||||
version: "1.0.4"
|
|
||||||
provider: "EsadCetiner"
|
|
||||||
- name: "sogo-rule-exclusions"
|
|
||||||
version: "1.0.4"
|
|
||||||
provider: "EsadCetiner"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
- name: Restart Caddy
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: "caddy"
|
|
||||||
state: "restarted"
|
|
||||||
daemon_reload: true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
waf_install_xcaddy_download: "https://github.com/caddyserver/xcaddy/releases/download"
|
|
||||||
@@ -21,11 +21,21 @@ common:
|
|||||||
custom_cert: true
|
custom_cert: true
|
||||||
custom_cert_file: "/etc/ssl/certs/test.lab.crt"
|
custom_cert_file: "/etc/ssl/certs/test.lab.crt"
|
||||||
custom_key_file: "/etc/ssl/private/test.lab.key"
|
custom_key_file: "/etc/ssl/private/test.lab.key"
|
||||||
plugins:
|
crs_plugins:
|
||||||
- "wordpress-rule-exclusions"
|
- "wordpress-rule-exclusions"
|
||||||
exceptions:
|
crs_exceptions:
|
||||||
# Cf. https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x)
|
# Cf. https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x)
|
||||||
# before_request:
|
# before_request:
|
||||||
# - 'SecRule REQUEST_FILENAME "@endsWith /wp-admin/admin-ajax.php" "id:1,nolog,ctl:ruleRemoveById=932260"'
|
# - 'SecRule REQUEST_FILENAME "@endsWith /wp-admin/admin-ajax.php" "id:1,nolog,ctl:ruleRemoveById=932260"'
|
||||||
after_response:
|
after_response:
|
||||||
- 'SecRuleUpdateTargetById 932260 "!ARGS:tag-name"'
|
- 'SecRuleUpdateTargetById 932260 "!ARGS:tag-name"'
|
||||||
|
header_cross_origin_embedder_policy: "unsafe-none"
|
||||||
|
header_content_security_policy:
|
||||||
|
worker-src: "'self' blob:"
|
||||||
|
img-src: "'self' data: https://secure.gravatar.com/avatar/"
|
||||||
|
font-src: "'self' data:"
|
||||||
|
script-src: "'self' 'unsafe-eval'"
|
||||||
|
script-src-elem: "'self' 'unsafe-inline'"
|
||||||
|
style-src-attr: "'self' 'unsafe-inline'"
|
||||||
|
style-src-elem: "'self' 'unsafe-inline'"
|
||||||
|
frame-src: "'self' blob:"
|
||||||
|
|||||||
Reference in New Issue
Block a user