chore: add ansible backend docker frontend-prep

This commit is contained in:
2026-01-21 13:05:13 +01:00
parent 5a280b6b01
commit 943fe4de7d
14930 changed files with 2341433 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
# =========================================================
# Stage 1: Build Frontend
# =========================================================
FROM node:20-alpine AS builder
WORKDIR /build
# Copier package files depuis frontend-prep
COPY frontend/frontend-prep/package*.json ./
# Installer les dépendances
RUN npm ci
# Copier le code source
COPY frontend/frontend-prep/ .
# Build
RUN npm run build
# =========================================================
# Stage 2: Nginx + ModSecurity
# =========================================================
FROM owasp/modsecurity-crs:nginx-alpine
USER root
# Copier build frontend
COPY --from=builder /build/dist /usr/share/nginx/html
#COPY docker/frontend/cert/cert.pem /etc/nginx/certs/cert.pem
#COPY docker/frontend/cert/key.pem /etc/nginx/certs/key.pem
#RUN chown root:nginx /etc/nginx/certs/cert.pem /etc/nginx/certs/key.pem && \
# chmod 644 /etc/nginx/certs/cert.pem && \
# chmod 640 /etc/nginx/certs/key.pem
# Logs ModSecurity
RUN mkdir -p /var/log/modsec && chown -R nginx:nginx /var/log/modsec
COPY docker/docker/frontend/nginx.conf /etc/nginx/conf.d/app.conf
COPY docker/docker/frontend/custom-rules.conf /etc/nginx/modsec/custom-rules.conf
RUN echo "Include /etc/nginx/modsec/custom-rules.conf" > /etc/nginx/modsec/custom-includes.conf
RUN rm -f /etc/nginx/templates/conf.d/default.conf.template || true
RUN chown -R nginx:nginx /usr/share/nginx/html
USER nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
+49
View File
@@ -0,0 +1,49 @@
# =========================================================
# Stage 1: Build Frontend
# =========================================================
FROM node:20-alpine AS builder
WORKDIR /build
COPY frontend-prep/package*.json ./
RUN npm ci --only=production
COPY frontend-prep .
RUN npm run build && ls -la dist/
# =========================================================
# Stage 2: Nginx + ModSecurity
# =========================================================
FROM owasp/modsecurity-crs:nginx-alpine
USER root
# Copier le frontend build
COPY --from=builder /build/dist /usr/share/nginx/html
# Configs Nginx / ModSecurity
COPY docker/frontend/nginx.conf.prod /etc/nginx/conf.d/app.conf
COPY docker/frontend/main.conf /etc/nginx/modsec/main.conf
COPY docker/frontend/ban-on-crs-scores-delivery-api.conf /etc/nginx/modsec/ban-on-crs-scores-delivery-api.conf
COPY docker/frontend/crs-setup.conf /etc/nginx/modsec/crs-setup.conf
# Supprimer template par défaut
RUN rm -f /etc/nginx/templates/conf.d/default.conf.template || true
# Variables ModSecurity
ENV MODSEC_ENGINE=On \
PARANOIA=2 \
ANOMALY_INBOUND=5 \
ANOMALY_OUTBOUND=4
# Permissions
RUN chown -R nginx:nginx /usr/share/nginx/html \
&& mkdir -p /etc/letsencrypt \
&& chown -R nginx:nginx /etc/letsencrypt
USER nginx
EXPOSE 80 443
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]
+24
View File
@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIECjCCAnKgAwIBAgIQQesYDZxq7zMlKT1zztYmUDANBgkqhkiG9w0BAQsFADBh
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExGzAZBgNVBAsMEnhvcl9m
YWtlcnNAQXN1c1hvcjEiMCAGA1UEAwwZbWtjZXJ0IHhvcl9mYWtlcnNAQXN1c1hv
cjAeFw0yNjAxMjAwODQxNDhaFw0yODA0MjAwNzQxNDhaMEYxJzAlBgNVBAoTHm1r
Y2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEbMBkGA1UECwwSeG9yX2Zha2Vy
c0BBc3VzWG9yMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4gjHuXBb
eRVHf29Lsn1JlFSHpSTsImMrjLHnUh0jCR+1i2xQ3GQVFJY8YLWvwJv64SnsDZBE
JBbSdsocfmJJl8mnW8INYgLqFBe/Cr/DFZqJcAcANVuxzjVpmWBqvLA3fYPKJHB3
66Lot6QZoObbvuOJpar+PubAiNVH6F/0ehy4O5daegfUlGxdZOTRsVhV8uwjH9+H
V8wL9ZyK8h6kl9VjQifP/FTdpaGhtkSoVHod/uynmVzF/PscTcUVwh+uQcqWj3fd
Itzcinj8K46xZLiFp/QHoz1kX/mDLtwbxbDAD9kGxf28J366VqyxJQzDjdvv/VYZ
QoEThibA34msTQIDAQABo1kwVzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI
KwYBBQUHAwEwHwYDVR0jBBgwFoAUyPQyLZZ7Al7A1Dvf/5xLRLY9aDYwDwYDVR0R
BAgwBocErBSn7TANBgkqhkiG9w0BAQsFAAOCAYEAWVgf0e/30255rHo8Z3/35YBE
Hrauwf8ef+aGVB+cLk2p1+UiYOgzvXKOeRP+9AVaASPg/mB7yA17DVrClWW7QjpU
iBkVCP6AsOlMVTPfKrKUucrWtac337TTleAMgtSjeApfdHbd3D4imilc16GLzVOG
9CKuvx6hJam4Bo4BfsO8TWh6F2hWxJL1dtY0d65ceBC40FXfowdJARgD85XCbJnY
4i/Twu80Hgrhok+CVDdH49DgMvUifckdsFCKqigZpJPRhGfbzfT61ysVcCXXsmj/
yFPo71zE5bq4T2ig+zGDbt64C+tP6a0P643SEnzyfEiUVTCWfIcrE17bSapzl5oa
PYSDkbC/OKoXsvvfVwDljNY0qXHTVjoTw6/8cXSAomZAaTAWZGkAWYBZEFpyEYu/
aBRDw5T/qo2N2xOt3NrmmWmkU8cFF8oESk5GJDoFFO/yp9MEvANWq6OQ4PZVEsdN
VtqzP07AD88B7kkD6qn8pSp8yZBYoL+Qk4d93HPg
-----END CERTIFICATE-----
+28
View File
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDiCMe5cFt5FUd/
b0uyfUmUVIelJOwiYyuMsedSHSMJH7WLbFDcZBUUljxgta/Am/rhKewNkEQkFtJ2
yhx+YkmXyadbwg1iAuoUF78Kv8MVmolwBwA1W7HONWmZYGq8sDd9g8okcHfroui3
pBmg5tu+44mlqv4+5sCI1UfoX/R6HLg7l1p6B9SUbF1k5NGxWFXy7CMf34dXzAv1
nIryHqSX1WNCJ8/8VN2loaG2RKhUeh3+7KeZXMX8+xxNxRXCH65BypaPd90i3NyK
ePwrjrFkuIWn9AejPWRf+YMu3BvFsMAP2QbF/bwnfrpWrLElDMON2+/9VhlCgROG
JsDfiaxNAgMBAAECggEAB2kzyTH0odPvh+9Ze0Tt1mnuF51OC7OWMDL+C1xus2Qh
gux+ezdh1I63dJFIbad/koXaGji+bzN7W481X3RwBsTDErhaUXoYfCeqKRtP9WOf
eXeVS2qR+hmYuIFnhn+9lgUt6cNxPx3UhP7hozumfUv/DZo9Y0kUC3h4ttb8kEtU
ePfv0RledHKOEM35zvhvVTpyF4LfvnMyu/E+hJp2kIptPZ5DEsvXT3CsLCNGOWmt
HZlvVihQ0dtUp1FjDQsiwB8zSErQkZDTv8L0OvBvVyFqhhP/KReZi2pCTsBSYcYU
MGmZanqg1mLCqVDVPnaquCcuo39DCfETXNS4OFK4qQKBgQD8tsmwXtU0ai4ryVne
SOOJiCQFsGfZgxuSJ7XPWj8BnLSs0pi3ddEdJQvkj7z43iZ4AaW2VX9abQkZhlNv
v1Y80+MBTwCSM6CZLzCYWMnzRNY1hUR6bwQa/x5JyXU0sbx3B/GCH9hvhjWn9Dit
uphoPgC8ryKy26de7E5FKIfzFQKBgQDk+S7oUoQFXZ7YAIIXXVjp4nQVdU8zb7nW
B+yxyE5L+q6afgi2w9Jmm7DrQAg5GuY+3xlhICol/oxLb6nWkX5C2FTYTFaqSi5B
rZVqD6D/WGosNzwbcgai4TjmiJ81ssVwMuizQLksOPexuVYDUikofaWsF1G/E5af
rGRJbuACWQKBgQCwMNCVgsiq7oyaQpvBepgJPz2+Kat93wbN85myo3ziJttg0sNe
xWmyJC4SgJSD/n5blOpwIVPVO8foX9q0QnZhmmjedLI1PIFvy5LZ5K2ISin+zpdb
tSLrn4sCbs6kmnaHlqYuzv0bZDrsij0qArpXk0L4SjKq+LHMYHyBgyylsQKBgBHI
kK4Wio5oIQghsfjilR9FKULpY4dZLBPFdcqxBfO8uobhNwgK2XKCsRD0Xi8hObS0
WyJB/0QIKxlIyOYTUr0aVCygcTK0pDcRpkMgh56NXWGlwJNZHc7Uszikb8kZ41+9
dHlHk5otqn8xJ88GOJAeghmFjiHLAa3RE9DoPZmxAoGAC2sRi0M7pr6TV7Pz1f8S
DUy+iout42FNKCt00J2C7TxoTsKsWH4UKL0mqqanOr7vb0Wkow6nH7xT8u4DUGsA
oXfJqcGShNaG/XYFo5TaVC4k7rZY87+P12429J42uXVtGgjCR3lE53CdS3bY0tl5
OG0lgtOwXaXbU53BuLCbndU=
-----END PRIVATE KEY-----
+59
View File
@@ -0,0 +1,59 @@
SecRule IP:BANNED "@eq 1" \
"id:100000,phase:1,deny,status:403,log,\
msg:'IP is banned'"
SecRule IP:REPUTATION_SCORE "@ge 100" \
"id:100099,phase:1,deny,status:403,log,\
msg:'Critical reputation score',\
setvar:'ip.blocked=1',expirevar:'ip.blocked=86400'"
SecRule TX:SQL_INJECTION_SCORE "@ge 5" \
"id:100001,phase:2,deny,status:403,log,\
msg:'SQL Injection detected',\
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
SecRule TX:XSS_SCORE "@ge 5" \
"id:100010,phase:2,deny,status:403,log,\
msg:'XSS detected',\
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
SecRule TX:RCE_SCORE "@ge 5" \
"id:100020,phase:2,deny,status:403,log,\
msg:'RCE detected',\
setvar:'ip.banned=1',expirevar:'ip.banned=259200'"
SecRule TX:LFI_SCORE "@ge 5" \
"id:100030,phase:2,deny,status:403,log,\
msg:'LFI detected',\
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
SecRule TX:INBOUND_ANOMALY_SCORE "@ge 20" \
"id:100060,phase:2,deny,status:403,log,\
msg:'Critical anomaly score',\
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
SecRule REQUEST_URI "@streq /api/v1/panier/remove" \
"id:399010,phase:1,nolog,pass,\
ctl:ruleRemoveById=911100,ctl:ruleRemoveById=920350"
SecRule REQUEST_URI "@streq /api/v1/panier/clear" \
"id:399011,phase:1,nolog,pass,\
ctl:ruleRemoveById=911100,ctl:ruleRemoveById=920350"
SecRule REQUEST_URI "@streq /api/v2/admin/protected/products" \
"id:399001,phase:2,nolog,pass,\
ctl:ruleRemoveById=932235"
SecAction \
"id:400161,phase:1,nolog,pass,\
setvar:'ip.request_window_1sec=+1',\
expirevar:'ip.request_window_1sec=1'"
SecRule IP:REQUEST_WINDOW_1SEC "@gt 20" \
"id:400160,phase:1,deny,status:429,log,\
msg:'Too many requests'"
SecRule IP:REPUTATION_SCORE "@ge 100" \
"id:409999,phase:1,deny,status:403,log,\
msg:'Critical reputation score',\
setvar:'ip.blocked=1',expirevar:'ip.blocked=86400'"
File diff suppressed because it is too large Load Diff
+101
View File
@@ -0,0 +1,101 @@
# =========================================================
# Request ID for correlation
# =========================================================
map $http_x_request_id $req_id {
default $http_x_request_id;
"" $request_id;
}
# =========================================================
# Upstream backend
# =========================================================
upstream backend {
server backend:8080 max_fails=3 fail_timeout=30s;
keepalive 32;
keepalive_requests 100;
keepalive_timeout 60s;
}
# =========================================================
# HTTP Server (MAIN)
# =========================================================
# Supprime le premier server block et garde seulement :
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
index index.html;
client_max_body_size 10M;
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/custom-rules.conf;
location /api/ {
limit_except GET POST PUT PATCH DELETE OPTIONS { deny all; }
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Request-ID' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Max-Age' 86400 always;
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
return 204;
}
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; # ✅ Changé
proxy_set_header X-Request-ID $req_id;
proxy_set_header Connection "";
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
}
location ~* \.(css|js|jpg|jpeg|png|gif|svg|ico|woff2?|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https://api.tomtom.com;
" always;
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~* (\.env|\.git|package\.json|package-lock\.json|yarn\.lock|Dockerfile|docker-compose\.yml)$ {
deny all;
access_log off;
log_not_found off;
}
}