80 lines
4.7 KiB
Markdown
80 lines
4.7 KiB
Markdown
# RackNerd VPN Hub
|
|
|
|
Client VPN entry point + DNS forwarder for the AtlasHorizon AD environment.
|
|
Roaming clients terminate here (OpenVPN + Duo MFA) and are routed over
|
|
WireGuard to the two sites. Inter-site traffic stays on the existing direct
|
|
Oswald↔Trochalakis tunnel — this box never carries it.
|
|
|
|
```
|
|
┌────────────── RackNerd VPS ──────────────┐
|
|
roaming client ══ovpn══▶ │ tun0 172.31.8.1 │
|
|
(172.31.8.x) │ openvpn ─▶ duo-authproxy ─▶ Duo cloud │
|
|
DNS/routes pushed │ (127.0.0.1:1812) └──LDAPS 636──┐ │
|
|
│ unbound 127.0.0.1 / .8.1 / .255.1 │ │
|
|
│ wg0 172.31.255.1 ─────────────────────┼──┤
|
|
└──────────┬──────────────────┬─────────┘ │
|
|
wg .255.2 wg .255.3 (via wg0)
|
|
Trochalakis 192.168.20/24 Oswald 192.168.7/24
|
|
AHDC01, AHDC03 ◀━━ direct s2s ━━▶ AH-OSWLDC
|
|
```
|
|
|
|
## Address plan
|
|
|
|
| Net | Subnet | Notes |
|
|
|----------------------|-------------------|----------------------------------|
|
|
| Trochalakis LAN | `192.168.20.0/24` | AHDC01, AHDC03 |
|
|
| Oswald LAN | `192.168.7.0/24` | AH-OSWLDC |
|
|
| WG transfer | `172.31.255.0/24` | hub .1, Troch .2, Oswald .3 |
|
|
| OpenVPN clients | `172.31.8.0/24` | routed (not NATed) to both sites |
|
|
|
|
Public endpoint: `vpn.atlashorizon.net` — only 22/tcp (SSH), 51820/udp
|
|
(WireGuard) and 1194/udp (OpenVPN) are open; DNS/RADIUS/mgmt bind to
|
|
loopback and tunnel IPs only.
|
|
|
|
## Layout
|
|
|
|
- [docker-compose.yml](docker-compose.yml) — openvpn, duo-authproxy, unbound (all `network_mode: host`)
|
|
- [openvpn/](openvpn/) — server.conf, PAM→RADIUS glue, offline-CA workflow in [pki/README.md](openvpn/pki/README.md)
|
|
- [duo-authproxy/](duo-authproxy/) — built from Duo's source tarball; cfg rendered from `.env`
|
|
- [unbound/](unbound/) — conditional forwarder: AD zones → DCs over wg0, everything else public recursion
|
|
- [host/](host/) — `setup.sh` (sysctl, iptables, wg keygen), `wg0.conf.example`, firewall template
|
|
- [client/](client/) — `.ovpn` template for end users
|
|
- [docs/](docs/) — [SITE-SIDE.md](docs/SITE-SIDE.md) (DC/firewall work at the sites), [TESTPLAN.md](docs/TESTPLAN.md)
|
|
|
|
## Deploy order
|
|
|
|
1. **Host**: `sudo host/setup.sh` — installs wireguard + iptables rules,
|
|
generates the WG key, prints the public key for the sites.
|
|
2. **Sites**: do [docs/SITE-SIDE.md](docs/SITE-SIDE.md) (WG peers, return
|
|
routes, DC firewall, Duo app, LDAPS CA export). Paste site pubkeys into
|
|
`/etc/wireguard/wg0.conf`, then `systemctl enable --now wg-quick@wg0`.
|
|
3. **Secrets**: `cp .env.example .env && chmod 600 .env`, fill in DC IPs,
|
|
Duo keys, service account, `RADIUS_SECRET`.
|
|
4. **PKI**: offline CA per [openvpn/pki/README.md](openvpn/pki/README.md);
|
|
copy server cert/key + `ta.key` into `openvpn/pki/`. Drop the AD CA
|
|
chain in `duo-authproxy/certs/ad-ldaps-ca.pem`.
|
|
5. **Stack**: `docker compose up -d --build`.
|
|
6. **Verify**: [docs/TESTPLAN.md](docs/TESTPLAN.md), stages 0→6.
|
|
|
|
## Design notes / gotchas
|
|
|
|
- **WireGuard is host-level** (`wg-quick@wg0`), not containerized — tun0
|
|
and wg0 share the host netns so the kernel routes between them with no
|
|
Docker bridge/NAT tricks, and the tunnel survives Docker restarts.
|
|
- **Routed, not NATed**: DCs see real `172.31.8.x` client IPs. Requires the
|
|
site-side return routes in SITE-SIDE.md. Fallback masquerade snippet is
|
|
commented at the bottom of [host/rules.v4.template](host/rules.v4.template).
|
|
- **No hairpin**: RackNerd's peer AllowedIPs only carry each site's own
|
|
LAN; the sites' RackNerd peer only carries `172.31.8.0/24` + the hub IP.
|
|
- **MTU**: OpenVPN `tun-mtu 1400` / `mssfix 1360` keeps client packets
|
|
inside wg0's 1420 so nothing fragments on the middle leg.
|
|
- **Duo flow**: password → push; `password,passcode` → offline fallback
|
|
(`allow_concat=true`). `reneg-sec 0` + `auth-gen-token` prevent surprise
|
|
re-prompts mid-session. `failmode=safe` fails *open* if Duo cloud is
|
|
down — flip to `secure` in the template if you'd rather fail closed.
|
|
- **TCP/443 fallback**: if client networks block 1194/udp, add a second
|
|
server instance (`proto tcp4`, `port 443`, separate `dev tun1` +
|
|
firewall rule). Not enabled by default.
|
|
- **Firewall reloads**: `netfilter-persistent reload` flushes Docker's
|
|
chains — restart docker afterwards (setup.sh does this).
|