Knowledge base of ~80+ markdown files across 14 domains (00-13), Logseq graph, hardware design files (KiCAD), infrastructure configs, and talas-wiki static site. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
268 lines
10 KiB
Text
268 lines
10 KiB
Text
HAProxy SPOE doc:
|
||
https://www.haproxy.com/blog/extending-haproxy-with-the-stream-processing-offload-engine
|
||
https://github.com/haproxy/haproxy/blob/master/doc/SPOE.txt
|
||
|
||
Coraza tutorial :
|
||
https://coraza.io/connectors/coraza-spoa/
|
||
|
||
External Documentation (unreliable) :
|
||
https://www.alldiscoveries.com/installation-and-configuration-haproxy-v2-4-22-with-waf-coraza-spoa-on-ubuntu-server-22-04-lts/
|
||
|
||
Structure implémenté :
|
||
- srv1 (10.184.116.168) : host HAProxy & Coraza SPOA
|
||
- srv2 (10.184.116.20) : le serveur à protéger (ici apache2, config par défault)
|
||
|
||
Fichiers de configurations importants :
|
||
- /etc/haproxy/haproxy.cfg - HAProxy Main Configuration
|
||
- /etc/haproxy/coraza.cfg - HAProxy SPOE Configuration
|
||
- /etc/coraza-spoa/config.yml - Coraza SPOA Main Configuration
|
||
- /etc/coraza-spoa/coraza.conf - Coraza Engine Configuration
|
||
|
||
On srv1 side :
|
||
apt update && apt install -y haproxy git wget
|
||
git clone https://github.com/corazawaf/coraza-spoa.git
|
||
|
||
# install go to build coraza-spoa
|
||
wget https://go.dev/dl/go1.24.0.linux-amd64.tar.gz
|
||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.24.0.linux-amd64.tar.gz
|
||
sudo echo "export PATH=$PATH:/usr/local/go/bin" >> /root/.profile
|
||
source /root/.profile
|
||
|
||
# build coraza-spoa
|
||
cd coraza-spoa/
|
||
go run mage.go build
|
||
|
||
# create coraza user and group
|
||
addgroup --quiet --system coraza-spoa
|
||
adduser --quiet --system --ingroup coraza-spoa --no-create-home --home /nonexistent --disabled-password coraza-spoa
|
||
|
||
mkdir -p /etc/coraza-spoa
|
||
cp build/coraza-spoa /usr/bin/coraza-spoa
|
||
chmod 755 /usr/bin/coraza-spoa
|
||
cp example/coraza-spoa.yaml /etc/coraza-spoa/config.yaml
|
||
vim /etc/coraza-spoa/config.yaml
|
||
change : bind: 0.0.0.0:9000
|
||
for : bind: 127.0.0.1:9000
|
||
|
||
change : - name: sample_app
|
||
for : - name: haporxy_waf
|
||
wget https://raw.githubusercontent.com/corazawaf/coraza/main/coraza.conf-recommended -O /etc/coraza-spoa/coraza.conf
|
||
vim /etc/coraza-spoa/coraza.conf
|
||
change : SecRuleEngine DetectionOnly
|
||
for : SecRuleEngine On
|
||
mkdir coraza-crs
|
||
cd coraza-crs
|
||
git clone https://github.com/coreruleset/coreruleset
|
||
cp coreruleset/crs-setup.conf.example /etc/coraza-spoa/crs-setup.conf
|
||
cp -R coreruleset/rules /etc/coraza-spoa
|
||
cp -R coreruleset/plugins /etc/coraza-spoa
|
||
|
||
# update files permissions
|
||
chown -R coraza-spoa:coraza-spoa /etc/coraza-spoa/
|
||
chmod 755 /etc/coraza-spoa
|
||
chmod -R 600 /etc/coraza-spoa/*
|
||
chmod 700 /etc/coraza-spoa/rules
|
||
chmod 700 /etc/coraza-spoa/plugins
|
||
|
||
cd ..
|
||
cp contrib/coraza-spoa.service /lib/systemd/system/coraza-spoa.service
|
||
systemctl daemon-reload
|
||
systemctl enable coraza-spoa.service
|
||
|
||
cp example/haproxy/coraza.cfg /etc/haproxy/coraza.cfg
|
||
cp example/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg
|
||
vim /etc/haproxy/haproxy.cfg
|
||
change : http-request set-var(txn.coraza.app) str(sample_app)
|
||
for : http-request set-var(txn.coraza.app) str(haproxy_waf)
|
||
|
||
change : filter spoe engine coraza config /usr/local/etc/haproxy/coraza.cfg
|
||
for : filter spoe engine coraza config /etc/haproxy/coraza.cfg
|
||
|
||
change : server backend $BACKEND_HOST
|
||
for : server backend 10.184.116.20:80 check
|
||
|
||
chnage : server coraza_spoa coraza-spoa:9000
|
||
for : server coraza_spoa 127.0.0.1:9000
|
||
|
||
systemctl restart haproxy
|
||
systemctl restart coraza-spoa
|
||
|
||
On srv2 side :
|
||
apt update && apt install -y apache2
|
||
systemctl status apache2
|
||
|
||
Check installation :
|
||
curl -I http://10.184.116.168/index.php?f=/etc/passwd
|
||
should return :
|
||
HTTP/1.1 403 Forbidden
|
||
waf-block: request
|
||
content-length: 0
|
||
|
||
((========================================================================================================================================================================================))
|
||
((=========================================================================================LARSEN=========================================================================================))
|
||
((========================================================================================================================================================================================))
|
||
|
||
|
||
Optimisations possibles:*
|
||
|
||
Regarder quelle règles sont utilisé souvent :
|
||
journalctl -u coraza-spoa --no-pager | grep "id"
|
||
dans /etc/coraza-spoa/coraza.conf enlver les regle non essentielles:
|
||
par exemple SecRuleRemoveById 920350
|
||
Ou si incertain mettre la règle en mode DetectionOnly:
|
||
SecRuleUpdateActionById 920350 "phase:2,log,pass"
|
||
|
||
|
||
appliquer coraza uniquement sur les requêtes critiques:
|
||
acl is_sensitive path_beg /admin /api /login /cart
|
||
filter spoe engine coraza config /etc/haproxy/coraza.cfg if is_sensitive
|
||
|
||
|
||
utiliser le mode détection pour les pages non sensibles:
|
||
dans /etc/coraza-spoa/coraza.conf :
|
||
SecRuleEngine On
|
||
SecRule REQUEST_URI "@beginsWith /public" "id:1000,phase:1,pass"
|
||
|
||
|
||
|
||
|
||
dans /etc/coraza-spoa/config.yaml on peut gerer l'allocation de ram et cpu:
|
||
memory_limit: 256m
|
||
worker_threads: 4
|
||
|
||
|
||
dans /etc/coraza-spoa/coraza.conf on peut limiter les logs aux req bloquées :
|
||
SecAuditEngine RelevantOnly
|
||
ou exclure les log tr
|
||
|
||
|
||
On peut égallementy utiliser la directive SecAuditLogParts pour définir le logging de coraza (internez à modsecurity) :
|
||
A: Audit log header (mandatory).
|
||
B: Request headers.
|
||
C: Request body (present only if the request body exists and Coraza is configured to intercept it. This would require SecRequestBodyAccess to be set to on).
|
||
D: Reserved for intermediary response headers; not implemented yet.
|
||
E: Intermediary response body (present only if Coraza is configured to intercept response bodies, and if the audit log engine is configured to record it. Intercepting response bodies requires SecResponseBodyAccess to be enabled). Intermediary response body is the same as the actual response body unless Coraza intercepts the intermediary response body, in which case the actual response body will contain the error message.
|
||
F: Final response headers.
|
||
G: Reserved for the actual response body; not implemented yet.
|
||
H: Audit log trailer.
|
||
I: This part is a replacement for part C. It will log the same data as C in all cases except when multipart/form-data encoding in used. In this case, it will log a fake application/x-www-form-urlencoded body that contains the information about parameters but not about the files. This is handy if you don’t want to have (often large) files stored in your audit logs.
|
||
J: This part contains information about the files uploaded using multipart/form-data encoding.
|
||
K: This part contains a full list of every rule that matched (one per line) in the order they were matched. The rules are fully qualified and will thus show inherited actions and default operators.
|
||
Z: Final boundary, signifies the end of the entry (mandatory).
|
||
|
||
|
||
|
||
|
||
frontend https_front
|
||
bind *:443 ssl crt /etc/haproxy/certs/z-ciso.pem
|
||
mode http
|
||
option httplog
|
||
acl api_path path_beg /api/
|
||
use_backend backend_ciso if api_path
|
||
|
||
acl waf_trigger rand(100) lt 10
|
||
|
||
http-request set-var(txn.coraza.app) str(haproxy_waf)
|
||
|
||
filter spoe engine coraza config /etc/haproxy/coraza.cfg
|
||
http-request send-spoe-group coraza coraza-req if waf_trigger
|
||
|
||
http-request redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
|
||
http-response redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
|
||
|
||
http-request deny deny_status 403 hdr waf-block "request" if { var(txn.coraza.action) -m str deny }
|
||
http-response deny deny_status 403 hdr waf-block "response" if { var(txn.coraza.action) -m str deny }
|
||
|
||
http-request silent-drop if { var(txn.coraza.action) -m str drop }
|
||
http-response silent-drop if { var(txn.coraza.action) -m str drop }
|
||
|
||
http-request deny deny_status 500 if { var(txn.coraza.error) -m int gt 0 }
|
||
http-response deny deny_status 500 if { var(txn.coraza.error) -m int gt 0 }
|
||
|
||
use_backend frontend_ciso
|
||
#default_backend frontend_ciso
|
||
|
||
|
||
backend coraza-spoa
|
||
mode tcp
|
||
server coraza_spoa 127.0.0.1:9000
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
acl skip_openvas_ipv4 src 10.184.116.20
|
||
acl skip_openvas_ipv6 src fd42:4cb:ac26:e6e1:216:3eff:fef6:99a8
|
||
http-request deny if skip_openvas_ipv4
|
||
http-request deny if skip_openvas_ipv6
|
||
|
||
|
||
185.14.128.171
|
||
2a03:a240:0:1dea::a2
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# ansible local config
|
||
# documentation: https://docs.ansible.com/ansible/latest/reference_appendices/config.html#ansible-configuration-settings
|
||
[defaults]
|
||
retry_files_enabled = False
|
||
# this deactivate the network gather process to speed up the fact gathering process
|
||
gather_subset = hardware,!network,virtual,ohai,facter
|
||
remote_user = adm-nmilovanovic
|
||
roles_path = ~/git/cosium/IT/ansible/roles
|
||
host_key_checking = False
|
||
forks = 10
|
||
# use for playbook 'virtual_ip_proxy.yml' with host 'center_proxy_gen_3'
|
||
# default value: 104448
|
||
max_diff_size = 4177920000
|
||
display_args_to_stdout = True
|
||
# enable timestamps when I run a playbook : profile_tasks
|
||
# https://docs.ansible.com/ansible/latest/collections/ansible/posix/profile_tasks_callback.html
|
||
callbacks_enabled = ansible.posix.profile_tasks,ansible.posix.timer,ansible.posix.profile_roles,community.general.counter_enabled
|
||
stdout_callback=yaml
|
||
# Callback settings
|
||
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/default_callback.html
|
||
show_task_path_on_failure = True # When a task fails, display the path to the file containing the failed task and the line number.
|
||
check_mode_markers = True # Toggle to control displaying markers when running in check mode.
|
||
show_custom_stats = True # This adds the custom stats set via the set_stats plugin to the play recap
|
||
display_failed_stderr = True # Toggle to control whether failed and unreachable tasks are displayed to STDERR (vs. STDOUT)
|
||
#result_format = yaml
|
||
#pretty_results = true
|
||
[ssh_connection]
|
||
pipelining = True
|
||
[privilege_escalation]
|
||
become = True
|
||
[inventory]
|
||
enable_plugins = constructed,ini
|
||
[persistent_connection]
|
||
connect_timeout = 100
|
||
command_timeout = 100
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
TASK [zabbix_agent : zabbix_agentd.conf src=zabbix_agentd.conf, dest={{ zabbix_path_config }}, backup=True] ********************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||
Wednesday 21 May 2025 17:47:41 +0200 (0:00:00.034) 0:00:03.419 *********
|
||
Wednesday 21 May 2025 17:47:41 +0200 (0:00:00.034) 0:00:03.419 *********
|
||
ok: [pad-rp-1]
|
||
|