Sister to s8n/production-deb. Edge-box config + provision script for
running the OpenBSD-edge role per s8n/production-setup-audit Topology 02.
v0.1 = stock OpenBSD install ISO (interactive, 5 min) + scripted provision
from onyx. Autoinstall ISO build deferred to v0.2.
Layout:
README.md workflow + service mapping (Debian → OpenBSD)
flash.sh burn stock install76.iso to USB
etc/ pf / relayd / acme-client / unbound /
hostname.wg0.example / sshd_config / doas.conf
scripts/
provision.sh from onyx: SSH+git clone+run install.sh
install.sh on edge: copy /etc/*, validate, restart, cron
cert-renew-check.sh weekly LE renewal
read-logs.sh pull /var/log/* for offline diagnostics
docs/
setup-checklist.md 7-phase first-time install walkthrough
Hardware target: Dell Precision T5600 per
s8n/production-setup-audit/hardware/dell-t5600.md
WG mesh: 10.10.10.0/29 between edge (.1) and nullstone (.2). UDP 51820.
Keys generated per-host (NEVER committed to repo).
Public traffic flow after migration:
Internet → router → edge T5600 (relayd TLS term) → wg0 →
nullstone Traefik (10.10.10.2:8443, private only)
CVE delta vs single-host Debian: regreSSHion + xz backdoor mitigated;
public IP runs OpenBSD base only — no systemd, no glibc, no Docker.
68 lines
2.3 KiB
Text
68 lines
2.3 KiB
Text
# /etc/pf.conf — edge box default-deny + nat + WG passthrough
|
|
#
|
|
# Layout:
|
|
# egress = WAN-side NIC (public IP from ISP/router)
|
|
# lan = LAN-side NIC (192.168.0.0/24, internal LAN)
|
|
# wg0 = WireGuard tunnel to nullstone (private /29 subnet, e.g. 10.10.10.0/29)
|
|
#
|
|
# Adjust interface names per `ifconfig` output on the T5600 (likely em0+em1).
|
|
|
|
# === Macros ===
|
|
ext_if = "em0" # WAN-side
|
|
int_if = "em1" # LAN-side
|
|
wg_if = "wg0"
|
|
nullstone = "10.10.10.2" # nullstone over WG; edge is 10.10.10.1
|
|
|
|
# === Tables ===
|
|
# Bogus / non-routable; martians; tor-exit if you want to block (left empty)
|
|
table <bogons> persist file "/etc/pf-bogons"
|
|
table <bruteforce> persist
|
|
|
|
# === Options ===
|
|
set skip on lo
|
|
set block-policy drop
|
|
set loginterface egress
|
|
set syncookies adaptive (start 25%, end 12%)
|
|
|
|
# === Normalisation ===
|
|
match in all scrub (no-df random-id max-mss 1440)
|
|
|
|
# === Default deny ===
|
|
block in log all
|
|
block out log all
|
|
pass out quick on $ext_if from ($ext_if:0) keep state
|
|
|
|
# === Anti-spoof / bogon drop on WAN ===
|
|
antispoof quick for { $ext_if $int_if }
|
|
block in quick on $ext_if from <bogons> to any
|
|
block in quick on $ext_if from any to <bogons>
|
|
|
|
# === Inbound: 80/443 ports → relayd → backend over wg0 ===
|
|
# relayd binds to ($ext_if) on these ports; pass traffic to it explicitly.
|
|
pass in on $ext_if proto tcp to ($ext_if) port { 80 443 } \
|
|
flags S/SA modulate state \
|
|
(max-src-conn 100, max-src-conn-rate 60/10, \
|
|
overload <bruteforce> flush global)
|
|
|
|
# === Inbound SSH: rate-limit + bruteforce trap ===
|
|
pass in on $ext_if proto tcp to ($ext_if) port 22 \
|
|
flags S/SA modulate state \
|
|
(max-src-conn 5, max-src-conn-rate 3/30, \
|
|
overload <bruteforce> flush global)
|
|
block in quick from <bruteforce>
|
|
|
|
# === WireGuard: allow UDP 51820 from anywhere (handshake) ===
|
|
pass in on $ext_if proto udp to ($ext_if) port 51820 keep state
|
|
|
|
# === Tunnel traffic: pass freely between edge and nullstone ===
|
|
pass on $wg_if all keep state
|
|
pass quick proto { tcp udp icmp } from $nullstone to ($wg_if) keep state
|
|
|
|
# === LAN side: trust LAN, allow outbound + DNS to unbound ===
|
|
pass on $int_if all keep state
|
|
|
|
# === ICMP for path-MTU + diagnostics ===
|
|
pass inet proto icmp icmp-type { echoreq unreach timex } keep state
|
|
|
|
# === Logging ===
|
|
# `pflog0` interface captures matched-`log` rules. tcpdump -ni pflog0 to watch.
|