Security requirements for RustBalance deployment.
- Master key = identity: Protect it like your life depends on it (
chmod 600) - Cluster token: Shared secret authenticating nodes - never expose it
- WireGuard: Encrypts all inter-node traffic - use unique keys per node
- No inbound needed: Management nodes only make outbound connections
- NTP required: Clock skew >5s causes message rejection
- Compromised node ≠ game over: Other nodes continue, only that node's traffic exposed
- Master Identity Key - Permanent onion address identity
- Backend Locations - Physical/network location of backends
- User Anonymity - Client IP addresses
- Service Availability - Ability to reach the service
| Adversary | Capability | Goal |
|---|---|---|
| Network observer | See traffic patterns | Deanonymize users/operators |
| Active attacker | Inject/drop packets | Disrupt service |
| Compromised backend | Full backend access | Pivot to master key |
| Compromised node | Full node access | Steal keys, disrupt |
Location: Only on management nodes
NEVER:
- Store on backends
- Transmit over network
- Include in backups without encryption
- Log or print
Protection:
# File permissions
chmod 600 /etc/rustbalance/master_ed25519.key
chown rustbalance:rustbalance /etc/rustbalance/master_ed25519.key
# Directory permissions
chmod 700 /etc/rustbalance/Future: HSM support for key storage
Backend keys are disposable. If compromised:
- Generate new backend key
- Update configuration
- Restart backend Tor
- Remove old backend from config
No impact on master address.
┌─────────────────────────────────────────────────────┐
│ MANAGEMENT ZONE │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ RustBalance │◀──WireGuard──│ RustBalance │ │
│ │ Node A │ │ Node B │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ └──────────┬─────────────────┘ │
│ │ Tor (outbound only) │
└────────────────────┼────────────────────────────────┘
│
┌──────┴──────┐
│ Tor Network │
└──────┬──────┘
│
┌────────────────────┼────────────────────────────────┐
│ │ BACKEND ZONE │
│ ┌──────────┴──────────┐ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ Backend 1 │ │ Backend 2 │ │
│ │ (disposable │ │ (disposable │ │
│ │ key) │ │ key) │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────┘
# Default deny inbound
iptables -P INPUT DROP
# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
# Allow WireGuard from known peers only
iptables -A INPUT -p udp --dport 51820 -s 10.0.0.0/24 -j ACCEPT
# Allow SSH from management network (optional)
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# Deny everything else
iptables -A INPUT -j DROPKey point: Management nodes need NO inbound connections from the internet.
The cluster token is a shared secret that authenticates nodes joining the mesh.
Protection:
# Store securely
chmod 600 /etc/rustbalance/cluster_token.txt
# Never include in logs
# Never transmit over unencrypted channels
# Rotate if suspected compromiseGeneration (on first node):
openssl rand -hex 32Compromise impact: Attacker with token + network access could join mesh as a node.
[Interface]
PrivateKey = <MANAGEMENT_NODE_PRIVATE_KEY>
Address = 10.0.0.1/24
ListenPort = 51820
[Peer]
PublicKey = <OTHER_NODE_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
Endpoint = <OTHER_NODE_IP>:51820
PersistentKeepalive = 25Critical:
- Use unique keys per node
- Restrict
AllowedIPsto specific peers - Keep WireGuard keys separate from RustBalance keys
Even with WireGuard, messages are validated:
- Node ID check - Ignore unknown senders
- Timestamp check - Reject stale/future messages
- No commands - Messages only signal state
// Messages cannot:
msg.execute_command() // ❌ No execution
msg.modify_config() // ❌ No config changes
msg.access_key() // ❌ No key access
msg.override_health() // ❌ No bypassing local checksTor uses timestamps for:
- Descriptor versioning
- Replay prevention
- Freshness checks
Attack: Manipulate NTP → publish stale descriptors → denial of service
# Use authenticated NTP
apt install chrony
# Configure multiple sources
# /etc/chrony/chrony.conf
server time1.google.com iburst
server time2.google.com iburst
server time.cloudflare.com iburst
# Monitor drift
chronyc trackingCheck drift before deployment:
# All nodes should be within 1 second
for node in node-a node-b node-c; do
ssh $node "date +%s"
done✅ Heartbeat received from node-b
✅ Publisher election triggered
✅ Descriptor published (revision 42)
✅ Backend backend-1 marked unhealthy
❌ Master key loaded: 0x7f3a...
❌ Backend address: backend1xyz.onion
❌ WireGuard private key
❌ User connection details
# /etc/logrotate.d/rustbalance
/var/log/rustbalance/*.log {
daily
rotate 7
compress
delaycompress
notifempty
create 640 rustbalance adm
sharedscripts
postrotate
systemctl reload rustbalance
endscript
}This is catastrophic. The onion address is permanently compromised.
- Stop all nodes immediately
- Generate new master key
- New onion address (unavoidable)
- Notify users of address change
- Forensic investigation
- Remove backend from configuration
- Restart RustBalance nodes
- Generate new backend key
- Re-add backend with new address
- Investigate how compromise occurred
- Isolate compromised node
- Revoke WireGuard peer
- Check if master key accessed
- Rebuild node from scratch
- Update WireGuard configs on other nodes
- Master key permissions:
600 - Config permissions:
600 - Config directory permissions:
700 - WireGuard configured and tested
- Firewall rules applied
- NTP synchronized and monitored
- Log rotation configured
- No sensitive data in logs
- Monitor clock drift
- Review logs weekly
- Test failover monthly
- Rotate WireGuard keys quarterly
- Audit access logs
- Know where master key is stored
- Have new address announcement plan
- Document node rebuild procedure
- Test backup restoration