106 lines
3.4 KiB
Markdown
106 lines
3.4 KiB
Markdown
# Stealth Mode: HAProxy + Konduit
|
|
|
|
Konduit's stealth mode makes the VPN server indistinguishable from a normal HTTPS site. It implements a fake TLS handshake — embedding the client's ephemeral key inside the TLS `SessionID` field. For this to work, **konduit must see the raw TCP stream from the client**. Any proxy that terminates TLS before konduit breaks stealth mode.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Client
|
|
│ raw TCP (looks like TLS to observers)
|
|
▼
|
|
HAProxy :443 ── TCP passthrough ──► konduit-server :8443
|
|
│
|
|
valid handshake │ handshake fails (real browser)
|
|
│ ▼
|
|
│ HAProxy :4443 (SSL termination)
|
|
│ │
|
|
│ ▼
|
|
│ real HTTPS backend
|
|
VPN tunnel
|
|
```
|
|
|
|
## HAProxy Configuration
|
|
|
|
```haproxy
|
|
# VPN ingress — raw TCP passthrough, no SSL termination
|
|
frontend vpn-ingress
|
|
bind *:443
|
|
mode tcp
|
|
option tcplog
|
|
default_backend konduit-vpn
|
|
|
|
backend konduit-vpn
|
|
mode tcp
|
|
server konduit 127.0.0.1:8443
|
|
|
|
# Camouflage backend — receives failed handshakes from konduit via PROXY protocol
|
|
# SSL is terminated here, not on the ingress
|
|
frontend camouflage
|
|
bind *:4443 ssl crt /etc/haproxy/ssl/your-domain.pem accept-proxy
|
|
mode http
|
|
http-request set-header X-Real-IP %[src]
|
|
http-request set-header X-Forwarded-Proto https
|
|
default_backend web
|
|
|
|
backend web
|
|
mode http
|
|
server web1 127.0.0.1:80 check
|
|
```
|
|
|
|
## Konduit server.toml
|
|
|
|
```toml
|
|
[server]
|
|
listen_addr = "0.0.0.0"
|
|
listen_port = 8443
|
|
public_addr = "your-domain.com"
|
|
public_port = 443 # port clients connect to (HAProxy front)
|
|
|
|
[stealth]
|
|
enabled = true
|
|
camouflage = "127.0.0.1:4443" # where to proxy non-konduit connections
|
|
```
|
|
|
|
Bootstrap with `--public-port` so generated client configs reference port 443:
|
|
|
|
```bash
|
|
echo "your mantra" | ./konduit-ctl bootstrap -l your-domain.com:8443 --public-port 443 -p -
|
|
```
|
|
|
|
## How It Works
|
|
|
|
**Konduit client (stealth handshake):**
|
|
1. Client sends fake TLS ClientHello with identity proof embedded
|
|
2. HAProxy passes raw TCP to konduit on port 8443
|
|
3. Konduit verifies identity, completes handshake, establishes VPN tunnel
|
|
4. Traffic looks like TLS Application Data to any observer
|
|
|
|
**Real browser or censor probe:**
|
|
1. Browser sends a real TLS ClientHello
|
|
2. HAProxy passes it raw to konduit
|
|
3. Konduit cannot verify identity — proxies the connection to `127.0.0.1:4443` with a PROXY protocol header preserving the real client IP
|
|
4. HAProxy at 4443 terminates TLS and serves your website
|
|
5. Observer sees a normal HTTPS site
|
|
|
|
## Common Mistakes
|
|
|
|
```
|
|
# WRONG — TLS terminated by HAProxy before konduit, fake handshake never works
|
|
Client → HAProxy SSL termination → konduit
|
|
|
|
# CORRECT — raw TCP passed through, konduit handles the fake TLS
|
|
Client → HAProxy TCP passthrough → konduit → HAProxy SSL termination (on failure)
|
|
```
|
|
|
|
The camouflage frontend uses `accept-proxy` — do not use it as the VPN ingress.
|
|
|
|
## Verify
|
|
|
|
```bash
|
|
# Browser should see your real website, not an error
|
|
curl -sk https://your-domain.com/
|
|
|
|
# Check konduit logs for stealth handshakes
|
|
journalctl -u konduit-server -f | grep -E "Stealth|Authenticated|camouflage"
|
|
```
|