-
Notifications
You must be signed in to change notification settings - Fork 0
feat(#407): HAProxy 설정 추가 #408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| [Definition] | ||
|
|
||
| # 로그 형식: 2026-02-15T17:06:02.613Z IP:PORT [haproxy_date] frontend backend/server timers status ... | ||
| # docker logs --timestamps 가 ISO8601 타임스탬프를 줄 시작에 추가 | ||
| # fail2ban이 타임스탬프 제거 후 공백이 남으므로 ^\s* 사용 | ||
|
|
||
| # 403 거부 (블랙리스트, ACL 거부) | ||
| # 429 Rate Limit 초과 | ||
| # 취약점 스캔 패턴 (.php, cgi-bin, .env, wp-admin, .git, shell, passwd 등) | ||
| failregex = ^\s*<HOST>:\d+\s+\[.*\]\s+\S+\s+\S+\s+\S+\s+403\s | ||
| ^\s*<HOST>:\d+\s+\[.*\]\s+\S+\s+\S+\s+\S+\s+429\s | ||
| ^\s*<HOST>:\d+\s+\[.*\]\s+\S+\s+\S+\s+\S+\s+\d+\s.*"(GET|POST|PUT|DELETE|HEAD|OPTIONS)\s+.*(\.php|cgi-bin|\.env|wp-admin|wp-login|\.git|shell|passwd|\.asp) | ||
|
Comment on lines
+10
to
+12
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 취약점 스캔을 위한 정규식이 너무 광범위하여 정상적인 요청을 차단할 오탐(false positive)의 가능성이 있습니다. 예를 들어, URL 파라미터에 |
||
|
|
||
| ignoreregex = | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| [Unit] | ||
| Description=Stream HAProxy Docker logs to file | ||
| After=docker.service | ||
|
|
||
| [Service] | ||
| Type=simple | ||
| ExecStart=/bin/bash -c '/usr/bin/docker logs -f --timestamps --tail=0 haproxy 2>&1 | sed -u "s/\([0-9]\{3\}\)[0-9]*Z/\1Z/" >> /var/log/haproxy/access.log' | ||
| Restart=always | ||
| RestartSec=10 | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,26 +3,79 @@ global | |
| maxconn 4096 | ||
| daemon | ||
|
|
||
| # 서버 정보 숨기기 | ||
| tune.h2.max-concurrent-streams 128 | ||
|
|
||
| defaults | ||
| log global | ||
| mode http | ||
| option httplog | ||
| option dontlognull | ||
| option forwardfor | ||
| timeout connect 5000ms | ||
| timeout client 50000ms | ||
| timeout server 50000ms | ||
| timeout http-request 10s | ||
| timeout http-keep-alive 2s | ||
|
|
||
| # 기본 에러 페이지에서 HAProxy 버전 숨기기 | ||
| errorfile 403 /usr/local/etc/haproxy/errors/403.http | ||
|
|
||
| frontend http_in | ||
| bind *:80 | ||
| # HTTP를 HTTPS로 리다이렉트 | ||
|
|
||
| acl blacklisted src -f /usr/local/etc/haproxy/blacklist.lst | ||
| http-request deny if blacklisted | ||
|
|
||
| stick-table type ip size 100k expire 30s store http_req_rate(10s) | ||
| http-request track-sc0 src | ||
| http-request deny deny_status 429 if { sc_http_req_rate(0) gt 50 } | ||
|
|
||
| http-request redirect scheme https unless { ssl_fc } | ||
|
|
||
| frontend https_in | ||
| bind *:443 ssl crt /etc/ssl/certs/realmatch.pem | ||
| bind *:443 ssl crt /etc/ssl/certs/realmatch.pem alpn h2,http/1.1 ssl-min-ver TLSv1.2 ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 | ||
|
|
||
| acl blacklisted src -f /usr/local/etc/haproxy/blacklist.lst | ||
| http-request deny if blacklisted | ||
|
|
||
| stick-table type ip size 100k expire 30s store http_req_rate(10s) | ||
| http-request track-sc0 src | ||
| http-request deny deny_status 429 if { sc_http_req_rate(0) gt 50 } | ||
|
|
||
| acl valid_host hdr(host) -i api.realmatch.co.kr | ||
| http-request deny deny_status 403 unless valid_host | ||
|
|
||
| http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" | ||
| http-response set-header X-Frame-Options "SAMEORIGIN" | ||
| http-response set-header X-Content-Type-Options "nosniff" | ||
| http-response set-header X-XSS-Protection "1; mode=block" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| http-response set-header Referrer-Policy "strict-origin-when-cross-origin" | ||
| http-response set-header Permissions-Policy "camera=(), microphone=(), geolocation=()" | ||
|
|
||
| http-response del-header Server | ||
| http-response del-header X-Powered-By | ||
|
|
||
| http-request deny if { req.hdr_cnt(content-length) gt 1 } | ||
|
|
||
| default_backend spring_servers | ||
|
|
||
| listen stats | ||
| bind *:8404 | ||
| stats enable | ||
| stats uri /stats | ||
| stats refresh 5s | ||
| stats show-legends | ||
| stats show-node | ||
| stats auth admin:realmatch2026! | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The HAProxy statistics page is configured with a hardcoded username and password ( |
||
| stats admin if TRUE | ||
|
|
||
| frontend prometheus | ||
| bind *:8405 | ||
| mode http | ||
| http-request use-service prometheus-exporter if { path /metrics } | ||
| no log | ||
|
|
||
| backend spring_servers | ||
| balance roundrobin | ||
| option httpchk GET /actuator/health | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Fail2ban action for Docker (uses DOCKER-USER chain) | ||
| [Definition] | ||
|
|
||
| actionstart = iptables -N f2b-<name> 2>/dev/null | ||
| iptables -A f2b-<name> -j RETURN | ||
| iptables -I DOCKER-USER -j f2b-<name> | ||
|
|
||
| actionstop = iptables -D DOCKER-USER -j f2b-<name> | ||
| iptables -F f2b-<name> | ||
| iptables -X f2b-<name> | ||
|
|
||
| actioncheck = iptables -n -L DOCKER-USER | grep -q 'f2b-<name>' | ||
|
|
||
| actionban = iptables -I f2b-<name> 1 -s <ip> -j DROP | ||
|
|
||
| actionunban = iptables -D f2b-<name> -s <ip> -j DROP |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [haproxy-attack] | ||
| enabled = true | ||
| filter = haproxy-attack | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| logpath = /var/log/haproxy/access.log | ||
| action = iptables-docker[name=haproxy] | ||
| maxretry = 3 | ||
| findtime = 300 | ||
| bantime = 3600 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| /var/log/haproxy/access.log { | ||
| daily | ||
| rotate 14 | ||
| compress | ||
| delaycompress | ||
| missingok | ||
| notifempty | ||
| copytruncate | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'협엽'은 '협업'의 오타로 보입니다. 수정하는 것이 좋겠습니다.