chore(infra): add VPN security scripts and update inventory

Add wireguard routing fixes and security documentation.
Update hosts inventory with current infrastructure state.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Quinn Ftw 2025-12-27 23:40:39 -08:00
parent 2fc0594ea1
commit 1f89e9f417
8 changed files with 958 additions and 18 deletions

View file

@ -1,8 +1,8 @@
{
"major": 0,
"merges": 0,
"builds": 16,
"version": "0.0.16",
"builds": 17,
"version": "0.0.17",
"lastMerge": null,
"lastBuild": "2025-12-27T23:12:52-08:00"
"lastBuild": "2025-12-27T23:40:46-08:00"
}

View file

@ -108,22 +108,58 @@ ssh_to_host() {
ssh $ssh_opts "${ssh_user}@${ssh_host}" "$@" 2>/dev/null
}
# Gather system info
# Gather system info (Linux + macOS compatible)
gather_system_info() {
local host="$1"
ssh_to_host "$host" 'bash -c '\''
hostname=$(hostname)
os=$(. /etc/os-release 2>/dev/null && echo $ID || uname -s)
os_version=$(. /etc/os-release 2>/dev/null && echo $VERSION_ID || uname -r)
os_family=$(. /etc/os-release 2>/dev/null && echo ${ID_LIKE:-$ID} | cut -d" " -f1 || echo unknown)
hostname=$(hostname -s 2>/dev/null || hostname)
# Detect OS
if [ -f /etc/os-release ]; then
os=$(. /etc/os-release && echo $ID)
os_version=$(. /etc/os-release && echo $VERSION_ID)
os_family=$(. /etc/os-release && echo ${ID_LIKE:-$ID} | cut -d" " -f1)
elif command -v sw_vers >/dev/null 2>&1; then
os="darwin"
os_version=$(sw_vers -productVersion)
os_family="darwin"
else
os=$(uname -s | tr "[:upper:]" "[:lower:]")
os_version=$(uname -r)
os_family="unknown"
fi
kernel=$(uname -r)
arch=$(uname -m)
# CPU count
cpus=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1)
ram_gb=$(free -g 2>/dev/null | awk "/Mem:/ {print \$2}" || echo 0)
disk_root_gb=$(df -BG / 2>/dev/null | awk "NR==2 {gsub(/G/,\"\",\$4); print \$4}" || echo 0)
disk_pct=$(df / 2>/dev/null | awk "NR==2 {print \$5}" || echo "0%")
up=$(uptime -p 2>/dev/null || uptime | sed "s/.*up //" | cut -d"," -f1-2)
# RAM in GB
if command -v free >/dev/null 2>&1; then
ram_gb=$(free -g 2>/dev/null | awk "/Mem:/ {print \$2}")
elif command -v sysctl >/dev/null 2>&1; then
ram_bytes=$(sysctl -n hw.memsize 2>/dev/null || echo 0)
ram_gb=$((ram_bytes / 1073741824))
else
ram_gb=0
fi
# Disk free in GB
if df -BG / >/dev/null 2>&1; then
disk_root_gb=$(df -BG / | awk "NR==2 {gsub(/G/,\"\",\$4); print \$4}")
disk_pct=$(df / | awk "NR==2 {print \$5}")
elif df -g / >/dev/null 2>&1; then
disk_root_gb=$(df -g / | awk "NR==2 {print \$4}")
disk_pct=$(df / | awk "NR==2 {print \$5}")
else
disk_root_gb=0
disk_pct="0%"
fi
# Uptime
up=$(uptime -p 2>/dev/null || uptime | sed "s/.*up //" | sed "s/,.*//" | xargs)
cat << EOF
{

View file

@ -75,11 +75,11 @@ hosts:
plum:
description: "MacBook Pro - mobile development"
connection:
ssh_host: "10.0.0.162"
ssh_user: "lilith"
ssh_host: "10.0.0.10"
ssh_user: "natalie"
ssh_key: "~/.ssh/id_ed25519"
network:
lan_ip: "10.0.0.162"
lan_ip: "10.0.0.10"
required:
services:
- sshd
@ -87,9 +87,25 @@ hosts:
- docker
- node
- git
disk_min_gb: 50
disk_min_gb: 10
ram_min_gb: 8
# NS2 DNS Server (SwissLayer)
ns2:
description: "Secondary DNS server (SwissLayer)"
connection:
ssh_host: "185.191.239.156"
ssh_user: "root"
ssh_key: "~/.ssh/ns2_nasty_sh"
network:
public_ip: true
required:
services:
- sshd
- pdns
disk_min_gb: 2
ram_min_gb: 1
# NAS / Storage Server
black:
description: "NAS with bigdisk storage"
@ -115,7 +131,7 @@ hosts:
# Capability definitions
capabilities:
sshd:
check: "systemctl is-active sshd || systemctl is-active ssh || launchctl list com.openssh.sshd 2>/dev/null | grep -q PID"
check: "systemctl is-active sshd 2>/dev/null || systemctl is-active ssh 2>/dev/null || pgrep -x sshd >/dev/null || netstat -an 2>/dev/null | grep -q '\\.22.*LISTEN'"
install:
debian: "apt-get install -y openssh-server && systemctl enable --now sshd"
fedora: "dnf install -y openssh-server && systemctl enable --now sshd"
@ -158,6 +174,17 @@ capabilities:
install:
debian: "apt-get install -y nfs-kernel-server && systemctl enable --now nfs-server"
bind:
check: "systemctl is-active named || systemctl is-active bind9"
install:
debian: "apt-get install -y bind9 && systemctl enable --now bind9"
fedora: "dnf install -y bind && systemctl enable --now named"
pdns:
check: "systemctl is-active pdns"
install:
debian: "apt-get install -y pdns-server && systemctl enable --now pdns"
rsync:
check: "rsync --version"
install:

View file

@ -0,0 +1,272 @@
# VPN Access Pattern: SOCKS5-over-WireGuard
**Last Updated**: 2025-12-27
## Architecture
```
┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Application │─────────▶│ SOCKS5 Proxy │─────────▶│ WireGuard │
│ (Browser, etc) │ │ localhost:1080│ │ Tunnel (wg0) │
└─────────────────┘ └──────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌──────────────┐ ┌─────────────────┐
│ SSH Tunnel │─────────▶│ VPN Gateway │
│ │ │ vpn.1984.nasty.sh
└──────────────┘ └─────────────────┘
┌─────────────────┐
│ VPN Resources │
│ services.nasty.sh
└─────────────────┘
```
## Components
### 1. WireGuard (wg0)
- **Purpose**: Encrypted tunnel only (NO automatic routing)
- **Config**: `/etc/wireguard/wg0.conf`
- **Key settings**:
- `AllowedIPs = 10.8.0.1/32` - Only VPN gateway (for keepalive)
- `Table = off` - Disable automatic routing table
- No `DNS` directive - SOCKS5 handles DNS
### 2. SOCKS5 Tunnel
- **Service**: `systemctl --user status vpn-socks5-tunnel.service`
- **Endpoint**: `localhost:1080`
- **Implementation**: SSH dynamic port forward through WireGuard
- **Command**: `ssh -N -D 1080 vpn.1984.nasty.sh`
### 3. Service Access
- **DNS**: `services.nasty.sh``10.8.0.1` (VPN IP only)
- **nginx**: Listens on `10.8.0.1:443` (NOT on public IP)
- **Access method**: Applications MUST use SOCKS5 proxy
## Security Model
### Defense in Depth
1. **DNS layer**: VPN services resolve to VPN IPs (not routable from internet)
2. **Network layer**: No automatic routing - explicit proxy required
3. **Application layer**: nginx bound to VPN interface only
4. **Encryption**: WireGuard tunnel + SSH tunnel double encryption
### Access Requirements
To access VPN-protected resources, ALL conditions must be met:
- ✅ WireGuard tunnel active (authenticated peer)
- ✅ SOCKS5 proxy running
- ✅ Application configured to use SOCKS5
**Without any one component, access is DENIED.**
## Usage Examples
### Browser (Firefox)
**Settings** → **Network Settings****Manual proxy configuration**:
- SOCKS Host: `localhost`
- Port: `1080`
- SOCKS v5: ✓
- Proxy DNS: ✓
### curl
```bash
# Access VPN resource
curl --socks5 localhost:1080 https://services.nasty.sh/
# Will FAIL without SOCKS5
curl https://services.nasty.sh/ # Uses WireGuard routing (wrong)
```
### Git
```bash
# Configure git to use SOCKS5
git config --global http.proxy 'socks5://localhost:1080'
# Or per-command
git clone --config http.proxy=socks5://localhost:1080 <url>
```
### SSH
```bash
# SSH through SOCKS5
ssh -o ProxyCommand='nc -X 5 -x localhost:1080 %h %p' user@host
```
## Deployment
### Using Reconciliation System
```bash
# Enable both services on workstation
cd /var/home/lilith/Code/@applications/@lilith/lilith-platform/codebase/infrastructure/reconciliation
# Ensure apricot.conf has:
# SERVICES=(
# "wireguard-client:enabled"
# "socks5-tunnel:enabled"
# )
./reconcile
```
### Manual Setup
1. **WireGuard**:
```bash
# Generate config
./services/wireguard-client.sh generate apricot > /etc/wireguard/wg0.conf
# Edit to add private key
sudo nano /etc/wireguard/wg0.conf
# Enable
sudo systemctl enable --now wg-quick@wg0.service
```
2. **SOCKS5**:
```bash
# Enable service
systemctl --user enable --now vpn-socks5-tunnel.service
# Verify
ss -tlnp | grep 1080
```
## Verification
### Check WireGuard
```bash
# Interface should exist
ip addr show wg0
# Should show: inet 10.8.0.2/24
# NO automatic routing for 10.8.0.0/24
ip route | grep "10.8.0.0/24 dev wg0"
# (should be empty)
```
### Check SOCKS5
```bash
# Service running
systemctl --user status vpn-socks5-tunnel.service
# Port listening
ss -tlnp | grep 1080
```
### Test Access
```bash
# Should FAIL (no SOCKS5)
curl -I https://services.nasty.sh/ --max-time 5
# Expected: Connection timeout or DNS resolution to VPN IP
# Should SUCCEED (with SOCKS5)
curl -I --socks5 localhost:1080 https://services.nasty.sh/
# Expected: HTTP/2 200
```
## Troubleshooting
### "services.nasty.sh accessible without SOCKS5"
**Diagnosis**: WireGuard has automatic routing enabled
```bash
# Check routing
ip route | grep 10.8.0.0
# If you see: 10.8.0.0/24 dev wg0 proto kernel scope link
# This is WRONG - automatic routing is active
```
**Fix**:
```bash
sudo /path/to/fix-wireguard-auto-routing.sh
```
### "Cannot connect even with SOCKS5"
**Check each layer**:
1. **WireGuard tunnel**:
```bash
ping -c3 10.8.0.1 # Should respond
```
2. **SOCKS5 proxy**:
```bash
systemctl --user status vpn-socks5-tunnel.service
ss -tlnp | grep 1080
```
3. **DNS resolution**:
```bash
dig services.nasty.sh +short
# Should return: 10.8.0.1
```
4. **nginx on VPS**:
```bash
ssh vpn.1984.nasty.sh 'ss -tlnp | grep :443'
# Should show: 10.8.0.1:443 (VPN IP only)
```
## Migration from Old Pattern
### Old Pattern (Insecure)
- WireGuard: `AllowedIPs = 10.8.0.0/24` (auto-routes)
- Direct access: Works without proxy
- Security: Routing-based (can be bypassed)
### New Pattern (Secure)
- WireGuard: `AllowedIPs = 10.8.0.1/32` + `Table = off`
- SOCKS5 required: Explicit proxy configuration
- Security: Defense in depth (DNS + network + application)
### Migration Steps
1. Update WireGuard config:
```bash
sudo /path/to/fix-wireguard-auto-routing.sh
```
2. Configure applications to use SOCKS5
3. Verify no direct access works
## Why This Pattern?
### Security Benefits
1. **Explicit access control**: Applications must opt-in to VPN access
2. **Audit trail**: SOCKS5 logs can track VPN usage
3. **Granular control**: Different applications can use different proxies
4. **Defense in depth**: Multiple layers must be bypassed
5. **No routing leaks**: VPN traffic isolated from regular traffic
### Operational Benefits
1. **Split-tunnel by default**: Regular internet traffic unaffected
2. **Application-specific**: Some apps use VPN, others don't
3. **Easy debugging**: Clear proxy on/off behavior
4. **Portable**: SOCKS5 config portable across machines
5. **Standard protocol**: Works with any SOCKS5-capable application
## References
- WireGuard docs: https://www.wireguard.com/
- SSH SOCKS5: `man ssh` (-D flag)
- Browser proxy: https://support.mozilla.org/en-US/kb/connection-settings-firefox

View file

@ -129,13 +129,16 @@ wireguard_client_generate_config() {
[Interface]
PrivateKey = PRIVATE_KEY_HERE
Address = ${vpn_ip}/24
Address = ${vpn_ip}/32
# NO DNS - SOCKS5 handles DNS through tunnel
# DNS = 1.1.1.1
# NO Table - Do not create routing table (prevents auto-routing)
Table = off
# Add explicit route to VPN gateway only
PostUp = ip route add 10.8.0.1/32 dev wg0
[Peer]
PublicKey = SERVER_PUBLIC_KEY_HERE
Endpoint = 93.95.231.174:51820

View file

@ -0,0 +1,127 @@
# Required DNS Updates for VPN-Only Infrastructure
**Date**: 2025-12-27
**Purpose**: Update DNS records to point internal infrastructure domains to VPN IPs
## Background
Infrastructure domains (status.atlilith.com, services.nasty.sh) must ONLY be accessible via SOCKS5 proxy over WireGuard VPN. This requires:
1. **nginx binding**: Listen only on VPN IP (10.8.0.1) ✅ DONE
2. **DNS records**: Point to VPN IP (10.8.0.1) ⚠️ REQUIRED
## Current State
| Domain | Current DNS | Target DNS | Status |
|--------|-------------|------------|--------|
| status.atlilith.com | 93.95.231.174 | 10.8.0.1 | ❌ Needs update |
| services.nasty.sh | 10.8.0.1 | 10.8.0.1 | ✅ Correct |
## Required DNS Changes
### Method 1: Update at DNS Provider
Access your DNS management interface (likely 1984.hosting or domain registrar):
1. **status.atlilith.com**:
```
Type: A
Name: status.atlilith.com
Value: 10.8.0.1
TTL: 300
```
### Method 2: Update BIND Zone Files (if self-hosted)
If zones are managed on vpn.1984.nasty.sh:
1. Find zone file:
```bash
ssh vpn.1984.nasty.sh 'find /etc/bind /var/cache/bind /var/named -name "*atlilith*"'
```
2. Update A record:
```
status IN A 10.8.0.1
```
3. Increment serial number
4. Reload BIND:
```bash
ssh vpn.1984.nasty.sh 'systemctl reload bind9'
```
## Verification
After DNS update:
```bash
# Wait for propagation
sleep 60
# Check DNS
dig status.atlilith.com +short
# Expected: 10.8.0.1
# Test public access (should timeout - VPN IP not routable)
curl --max-time 5 https://status.atlilith.com
# Expected: Timeout or connection refused
# Test via SOCKS5 (should work)
curl --socks5 localhost:1080 https://status.atlilith.com
# Expected: HTTP 200 or 500 (but connection succeeds)
```
## Security Impact
### Before DNS Update
- **status.atlilith.com**: Partially exposed
- DNS → public IP
- nginx → VPN IP only
- Result: DNS resolution works, but connection fails (nginx not listening on public IP)
- Risk: Information disclosure (DNS reveals infrastructure)
### After DNS Update
- **status.atlilith.com**: Fully protected
- DNS → VPN IP (not routable from internet)
- nginx → VPN IP only
- Result: Both DNS and nginx require VPN access
- Risk: None (complete isolation)
## Nameserver Information
Both domains use custom nameservers:
```bash
$ dig NS nasty.sh +short
ns2.nasty.sh.
ns1.nasty.sh.
$ dig NS atlilith.com +short
ns1.nasty.sh.
ns2.nasty.sh.
```
This suggests DNS is managed through custom BIND setup or forwarded to these nameservers.
## Action Required
**You need to update the DNS record manually** through:
1. Domain registrar DNS management interface, OR
2. BIND zone files on ns1.nasty.sh/ns2.nasty.sh, OR
3. DNS provider API/interface
Once updated, DNS will propagate within 5-15 minutes (TTL=300s).
## Testing Current Config
Even without DNS update, nginx security is enforced:
```bash
# Force public IP (bypassing DNS)
curl -I --resolve "status.atlilith.com:443:93.95.231.174" https://status.atlilith.com --max-time 5
# Expected: Connection timeout (nginx not listening on public IP)
```
This proves nginx is already VPN-only. DNS update is for defense-in-depth.

View file

@ -0,0 +1,344 @@
# VPN Infrastructure Security - Implementation Summary
**Date**: 2025-12-27
**Issue**: Infrastructure services (services.nasty.sh, status.atlilith.com) were publicly accessible
**Resolution**: SOCKS5-over-WireGuard mandatory access pattern
---
## Security Architecture
### Before (INSECURE)
```
User Browser → DNS → Public IP → nginx → Service ❌
```
- Any internet user could access infrastructure services
- No authentication required
- Critical security exposure
### After (SECURE)
```
User Browser → SOCKS5 Proxy → WireGuard Tunnel → VPN IP → nginx → Service ✅
localhost:1080
```
- WireGuard authentication required (private key)
- SOCKS5 proxy required (explicit opt-in)
- nginx listens on VPN IP only (10.8.0.1)
- DNS points to VPN IP (not routable from internet)
---
## Changes Implemented
### 1. nginx Configuration ✅ DEPLOYED
**services.nasty.sh** (`/etc/nginx/sites-available/services.nasty.sh`):
```nginx
server {
listen 10.8.0.1:443 ssl http2; # VPN IP only
server_name services.nasty.sh;
# ... rest of config
}
```
**status.atlilith.com** (`/etc/nginx/sites-available/status.atlilith.com`):
```nginx
server {
listen 10.8.0.1:443 ssl http2; # VPN IP only
server_name status.atlilith.com;
# ... rest of config
}
```
**Status**: ✅ Deployed to vpn.1984.nasty.sh
### 2. WireGuard Configuration ⚠️ REQUIRES MANUAL ACTION
**Current** (on this workstation):
```ini
[Interface]
PrivateKey = ...
Address = 10.8.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = ...
Endpoint = 93.95.231.174:51820
AllowedIPs = 10.8.0.0/24 ← WRONG (auto-routes)
PersistentKeepalive = 25
```
**Required** (SOCKS5-over-WireGuard pattern):
```ini
[Interface]
PrivateKey = ...
Address = 10.8.0.2/24
Table = off ← ADD (disable routing)
#DNS = 1.1.1.1 ← COMMENT OUT
[Peer]
PublicKey = ...
Endpoint = 93.95.231.174:51820
AllowedIPs = 10.8.0.1/32 ← CHANGE (gateway only)
PersistentKeepalive = 25
```
**Status**: ⚠️ Needs manual edit (requires sudo)
**Action Required**:
```bash
# Edit /etc/wireguard/wg0.conf with sudo
sudo nano /etc/wireguard/wg0.conf
# Then restart
sudo systemctl restart wg-quick@wg0.service
```
See: `fix-wireguard-auto-routing.sh` for automated script (requires sudo)
### 3. DNS Records 📋 OPTIONAL (Defense in Depth)
**Current**:
| Domain | DNS Record | Status |
|--------|------------|--------|
| services.nasty.sh | 10.8.0.1 | ✅ Correct |
| status.atlilith.com | 93.95.231.174 | ⚠️ Public IP |
**Recommended**:
| Domain | DNS Record | Benefit |
|--------|------------|---------|
| status.atlilith.com | 10.8.0.1 | Complete isolation from internet |
**Status**: 📋 Optional (nginx already blocks public IP access)
See: `REQUIRED-DNS-UPDATES.md` for procedure
### 4. Reconciliation Tooling ✅ UPDATED
**File**: `codebase/infrastructure/reconciliation/services/wireguard-client.sh`
**Changes**:
- Updated `wireguard_client_generate_config()` to use SOCKS5-over-WireGuard pattern
- Sets `AllowedIPs = 10.8.0.1/32` (not `10.8.0.0/24`)
- Sets `Table = off` to prevent auto-routing
- Removes `DNS` directive (SOCKS5 handles DNS)
**Status**: ✅ Updated (will apply to new deployments)
### 5. Documentation ✅ CREATED
**Created Files**:
- `reconciliation/docs/VPN-ACCESS-PATTERN.md` - Complete architecture guide
- `scripts/security/fix-wireguard-auto-routing.sh` - Automated fix script
- `scripts/security/REQUIRED-DNS-UPDATES.md` - DNS update guide
- `scripts/security/VPN-SECURITY-SUMMARY.md` - This file
**Status**: ✅ Complete
---
## Verification Tests
### Test 1: nginx Binds to VPN IP Only ✅
```bash
# On VPS
ssh vpn.1984.nasty.sh 'ss -tlnp | grep :443'
```
**Expected**:
```
LISTEN 10.8.0.1:443 (services.nasty.sh)
LISTEN 10.8.0.1:443 (status.atlilith.com)
LISTEN 0.0.0.0:443 (other public sites)
```
**Status**: ✅ Verified
### Test 2: Public IP Access Blocked ✅
```bash
# Force connection to public IP (bypassing DNS)
curl -I --resolve "services.nasty.sh:443:93.95.231.174" https://services.nasty.sh --max-time 5
```
**Expected**: Connection timeout or 403 Forbidden
**Status**: ✅ Verified (403 Forbidden)
### Test 3: SOCKS5 Access Works ✅
```bash
curl --socks5 localhost:1080 -I https://services.nasty.sh/
```
**Expected**: HTTP 200
**Status**: ✅ Verified
### Test 4: WireGuard Auto-Routing Removed ⚠️
```bash
ip route | grep "10.8.0.0/24 dev wg0"
```
**Expected**: Empty (no output)
**Current**: ❌ Route exists (auto-routing active)
**Status**: ⚠️ Requires manual fix
### Test 5: Direct Access Fails (After WireGuard Fix) ⏳
```bash
# Without SOCKS5 proxy
curl --max-time 5 https://services.nasty.sh/
```
**Expected**: Connection timeout
**Status**: ⏳ Pending WireGuard fix
---
## Security Impact
### Threat Model - Before
| Attack Vector | Risk | Impact |
|---------------|------|--------|
| Public internet access | HIGH | Anyone can access infrastructure dashboards |
| DNS enumeration | MEDIUM | Infrastructure topology visible |
| Unauthorized monitoring | HIGH | Service health/status exposed |
| Credential attacks | HIGH | Login forms accessible |
### Threat Model - After
| Attack Vector | Risk | Impact |
|---------------|------|--------|
| Public internet access | NONE | nginx not listening on public IP |
| DNS enumeration | LOW | Resolves to VPN IP (not routable) |
| Unauthorized monitoring | NONE | SOCKS5 + WireGuard auth required |
| Credential attacks | NONE | Cannot reach login forms |
**Risk Reduction**: HIGH → NONE (complete mitigation)
---
## Standard Deployment Pattern
All future workstations should use this pattern:
### 1. WireGuard Setup
```bash
# Generate config using reconciliation tooling
cd codebase/infrastructure/reconciliation
./services/wireguard-client.sh generate <hostname> > /tmp/wg0.conf
# Add private key, then deploy
sudo cp /tmp/wg0.conf /etc/wireguard/wg0.conf
sudo systemctl enable --now wg-quick@wg0.service
```
### 2. SOCKS5 Setup
```bash
# Enable SOCKS5 tunnel
cd codebase/infrastructure/reconciliation
./reconcile # Enables socks5-tunnel service
# Verify
systemctl --user status vpn-socks5-tunnel.service
ss -tlnp | grep 1080
```
### 3. Browser Configuration
- **Firefox**: Settings → Network → SOCKS5: localhost:1080
- **Chrome**: Use FoxyProxy or similar extension
- **CLI Tools**: `--socks5 localhost:1080`
### 4. Verification
```bash
# Should timeout (no SOCKS5)
curl --max-time 5 https://services.nasty.sh/
# Should work (via SOCKS5)
curl --socks5 localhost:1080 https://services.nasty.sh/
```
---
## Critical Files
### VPS (vpn.1984.nasty.sh)
```
/etc/nginx/sites-available/services.nasty.sh # VPN-only config
/etc/nginx/sites-available/status.atlilith.com # VPN-only config
/etc/nginx/snippets/vpn-only-access.conf # IP whitelist (unused now)
```
### Workstation (apricot)
```
/etc/wireguard/wg0.conf # Needs manual update
~/.config/systemd/user/vpn-socks5-tunnel.service # Auto-managed
```
### Codebase
```
codebase/infrastructure/
├── reconciliation/
│ ├── services/wireguard-client.sh # Config generator (updated)
│ ├── services/socks5-tunnel.sh # SOCKS5 manager
│ └── docs/VPN-ACCESS-PATTERN.md # Architecture docs
└── scripts/security/
├── fix-wireguard-auto-routing.sh # WireGuard fix script
├── test-vpn-access-control.sh # Access testing
├── verify-nginx-security.sh # Pre-deployment checks
└── REQUIRED-DNS-UPDATES.md # DNS update guide
```
---
## Next Steps
### Immediate (Required)
1. **Fix WireGuard auto-routing on this workstation**:
```bash
sudo nano /etc/wireguard/wg0.conf
# Make changes as documented above
sudo systemctl restart wg-quick@wg0.service
```
2. **Verify complete lockdown**:
```bash
# Should timeout
curl --max-time 5 https://services.nasty.sh/
# Should work
curl --socks5 localhost:1080 https://services.nasty.sh/
```
### Optional (Defense in Depth)
3. **Update DNS for status.atlilith.com**:
- See: `REQUIRED-DNS-UPDATES.md`
- Change A record from `93.95.231.174` to `10.8.0.1`
### Future Deployments
4. **Use reconciliation tooling for new workstations**:
```bash
cd codebase/infrastructure/reconciliation
./reconcile
```
- Automatically configures SOCKS5-over-WireGuard pattern
- No manual edits needed
---
## References
- **Architecture**: `reconciliation/docs/VPN-ACCESS-PATTERN.md`
- **WireGuard Fix**: `scripts/security/fix-wireguard-auto-routing.sh`
- **DNS Updates**: `scripts/security/REQUIRED-DNS-UPDATES.md`
- **Testing**: `scripts/security/test-vpn-access-control.sh`
- **Nginx Verification**: `scripts/security/verify-nginx-security.sh`
---
**Summary**: Infrastructure services are now VPN-only. Final step is updating WireGuard config on workstation to enforce SOCKS5 proxy requirement.

View file

@ -0,0 +1,131 @@
#!/usr/bin/env bash
# =============================================================================
# Fix WireGuard Auto-Routing
# =============================================================================
# Updates WireGuard configuration to use SOCKS5-over-WireGuard pattern.
#
# BEFORE: AllowedIPs = 10.8.0.0/24 (auto-routes all VPN traffic)
# AFTER: AllowedIPs = 10.8.0.1/32 + Table = off (no auto-routing)
#
# This enforces that applications must explicitly use SOCKS5 proxy to access
# VPN-protected resources.
#
# Usage:
# sudo ./fix-wireguard-auto-routing.sh
# =============================================================================
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
WG_CONFIG="/etc/wireguard/wg0.conf"
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check root
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root (use sudo)"
exit 1
fi
log_info "WireGuard Auto-Routing Fix"
echo ""
# Check if config exists
if [[ ! -f "$WG_CONFIG" ]]; then
log_error "WireGuard config not found: $WG_CONFIG"
exit 1
fi
log_info "Current configuration:"
echo "─────────────────────────────────────────────────────────────"
grep -E "AllowedIPs|Table|DNS" "$WG_CONFIG" || echo " No AllowedIPs/Table/DNS found"
echo "─────────────────────────────────────────────────────────────"
echo ""
# Backup original
BACKUP="${WG_CONFIG}.backup-$(date +%Y%m%d-%H%M%S)"
cp "$WG_CONFIG" "$BACKUP"
log_success "Backed up to: $BACKUP"
echo ""
# Update config
log_info "Applying SOCKS5-over-WireGuard pattern..."
# Remove old AllowedIPs line
sed -i '/^AllowedIPs.*10\.8\.0\.0\/24/d' "$WG_CONFIG"
# Add Table = off if not present
if ! grep -q "^Table = off" "$WG_CONFIG"; then
sed -i '/^\[Interface\]/a Table = off' "$WG_CONFIG"
fi
# Comment out DNS if present
sed -i 's/^DNS = /#DNS = /' "$WG_CONFIG"
# Add new AllowedIPs in [Peer] section if not present
if ! grep -q "^AllowedIPs.*10\.8\.0\.1/32" "$WG_CONFIG"; then
sed -i '/^\[Peer\]/a AllowedIPs = 10.8.0.1/32' "$WG_CONFIG"
fi
log_success "Configuration updated"
echo ""
log_info "New configuration:"
echo "─────────────────────────────────────────────────────────────"
grep -E "AllowedIPs|Table|#DNS" "$WG_CONFIG" || echo " Config updated"
echo "─────────────────────────────────────────────────────────────"
echo ""
# Restart WireGuard
log_info "Restarting WireGuard..."
systemctl restart wg-quick@wg0.service
# Wait for interface
sleep 2
# Verify
if ip link show wg0 &>/dev/null; then
log_success "WireGuard interface active"
# Check routing
echo ""
log_info "Routing table check:"
if ip route | grep -q "10.8.0.0/24 dev wg0"; then
log_error "Auto-routing still active! Check config."
exit 1
else
log_success "No automatic routing (correct)"
fi
else
log_error "WireGuard interface not active"
exit 1
fi
echo ""
log_success "WireGuard now uses SOCKS5-over-WireGuard pattern"
echo ""
echo "To access VPN resources, configure applications to use:"
echo " SOCKS5 proxy: localhost:1080"
echo ""
echo "Example:"
echo " curl --socks5 localhost:1080 https://services.nasty.sh/"
echo ""