-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhaproxy.example.cfg
More file actions
131 lines (107 loc) · 5.48 KB
/
haproxy.example.cfg
File metadata and controls
131 lines (107 loc) · 5.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# HAProxy example configuration for rustguac
#
# This config terminates TLS at HAProxy and proxies to rustguac on localhost.
# rustguac listens on 127.0.0.1:8089 with its own TLS (double encryption on
# loopback — belt and suspenders). Adjust "verify none" to "verify required
# ca-file /path/to/ca.pem" if using a real CA-signed cert for rustguac.
#
# WebSocket support requires tunnel timeout for long-lived connections.
#
# Knocknoc integration (https://knocknoc.io):
# knocknoc-agent dynamically adds/removes client IPs to HAProxy ACLs via
# the admin socket, providing zero-trust network access. Only users who
# have authenticated through Knocknoc can reach the login page.
# All other paths (OIDC flow, API, WebSocket, share links) pass through
# to rustguac which has its own auth layer.
global
log /dev/log local0
log /dev/log local1 notice
# Admin socket — knocknoc-agent uses this to manage dynamic ACLs.
# Ensure knocknoc-agent user is in the haproxy group:
# adduser knocknoc-agent haproxy
stats socket /run/haproxy/admin.sock mode 0660 level admin user haproxy group haproxy
user haproxy
group haproxy
daemon
# Modern TLS defaults
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-server-options ssl-min-ver TLSv1.2
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5s
timeout client 30s
timeout server 30s
# WebSocket/tunnel connections need a long timeout — sessions can last hours.
# This should be >= rustguac's session_max_duration_secs (default 8h).
timeout tunnel 8h
# Abort slow client sends (protects against slowloris)
timeout http-request 10s
timeout http-keep-alive 5s
frontend https
bind *:443 ssl crt /etc/ssl/private/rustguac.pem alpn h2,http/1.1
bind *:80
mode http
# Redirect HTTP → HTTPS
http-request redirect scheme https unless { ssl_fc }
# Forward client IP to rustguac (used by rate limiting and audit logging).
# Delete any incoming X-Forwarded-For first to prevent spoofing, then let
# HAProxy add the real client IP as a fresh single-valued header.
http-request del-header X-Forwarded-For
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
#
# rustguac must trust HAProxy's source IP to honour X-Forwarded-For.
# Add this to your rustguac config.toml:
# trusted_proxies = ["127.0.0.1/32"]
# HSTS header (HAProxy layer — rustguac also sets this when TLS is enabled)
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains" if { ssl_fc }
# ── Knocknoc dynamic IP allowlist ────────────────────────────────────
#
# knocknoc-agent populates this ACL via the admin socket. The ACL ID (600)
# must match what you configure in Knocknoc admin (Knocs > Identity Aware
# Proxy > ACL ID). Pick any unused ID.
#
# Verify currently allowed IPs:
# echo "show acl #600" | socat stdio /run/haproxy/admin.sock
acl knoc_rustguac src -u 600
# ── Route classification ─────────────────────────────────────────────
# Match requests to this rustguac instance by hostname
acl is_rustguac hdr(host) -i console.example.com
# Internal/server IPs that always bypass Knocknoc.
# IMPORTANT: Include the server's own public IP if hairpin NAT is possible,
# and 127.0.0.0/8 for local health checks.
acl is_internal src 127.0.0.0/8
# Front page — gate behind Knocknoc to hide the login UI from scanners.
# Note: only gate `/` (the login page). Don't gate the API, OIDC flow,
# WebSocket, or share links — rustguac has its own auth for those, and
# gating them at HAProxy breaks OIDC callbacks and share link access.
acl is_root path /
# ── Routing rules ────────────────────────────────────────────────────
# Front page: require Knocknoc or internal IP
use_backend rustguac if is_rustguac is_root knoc_rustguac
use_backend rustguac if is_rustguac is_root is_internal
use_backend denied if is_rustguac is_root
# All other paths pass through to rustguac (has its own auth)
use_backend rustguac if is_rustguac
default_backend denied
backend rustguac
mode http
balance roundrobin
# Health check against the unauthenticated /api/health endpoint.
option httpchk GET /api/health
http-check expect status 200
# rustguac on loopback with TLS. Use "verify none" for self-signed certs,
# or "verify required ca-file /opt/rustguac/tls/cert.pem" for strict checking.
server rustguac 127.0.0.1:8089 ssl verify none check inter 30s
backend denied
mode http
# Custom 403 page. The .http file includes full HTTP headers + HTML body.
errorfile 403 /etc/haproxy/errors/403.http
http-request deny deny_status 403