⚠️ IMPORTANT: All features are experimental, under active development. Use at your own risk. Customization to your workflow required. © 2026 GLG, a.s. | ← Back to Index
12. Network Security & Hardening
12.1 Principle: Minimize Attack Surface
UAML runs locally by default — no ports open, no external access. When you need remote access (dashboard, MCP, coordination), follow these hardening steps.
12.2 Restrict Services to Authorized IPs
# Firewall: only allow dashboard access from specific IPs
sudo ufw default deny incoming
sudo ufw allow from 192.168.1.0/24 to any port 8780 # Dashboard — LAN only
sudo ufw allow from 192.168.1.0/24 to any port 8770 # MCP — LAN only
sudo ufw allow from 10.0.0.5 to any port 8791 # Coordination — VPS only
sudo ufw enable
# Or with iptables:
iptables -A INPUT -p tcp --dport 8780 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 8780 -j DROP
12.3 Only Run What You Need
# Check what's running:
ss -tlnp | grep -E "878[0-9]|8770|8791"
# Disable services you don't need:
systemctl disable uaml-dashboard.service # if no web UI needed
systemctl disable uaml-mcp.service # if no MCP needed
# In config.yaml:
dashboard:
enabled: false # don't start web dashboard
mcp:
enabled: false # don't start MCP server
12.4 SSH Tunneling for Remote Access
Instead of opening ports, use SSH tunnels:
# Access dashboard from remote machine securely:
ssh -L 8780:127.0.0.1:8780 user@uaml-server
# Now open http://localhost:8780 in browser — encrypted, no port exposed
# Access MCP from remote agent:
ssh -L 8770:127.0.0.1:8770 user@uaml-server
# Persistent tunnel with autossh:
autossh -M 0 -f -N -L 8780:127.0.0.1:8780 user@uaml-server
12.5 Mobile Client IP Whitelisting via Signal
For mobile users who need access from changing IP addresses:
# Agent receives Signal message: "My IP is 85.123.45.67"
# Agent verifies sender is authorized, then:
import subprocess
def whitelist_ip(ip_address, port=8780, duration_hours=12):
"""Temporarily whitelist an IP for dashboard access."""
# Add firewall rule
subprocess.run([
"ufw", "allow", "from", ip_address,
"to", "any", "port", str(port),
"comment", f"mobile-{ip_address}-temp"
])
# Schedule removal (security: don't leave permanent holes)
subprocess.run([
"at", f"now + {duration_hours} hours",
"-c", f"ufw delete allow from {ip_address} to any port {port}"
])
return f"✅ {ip_address} whitelisted for port {port} for {duration_hours}h"
# Usage flow:
# 1. User sends IP via Signal (encrypted, verified sender)
# 2. Agent validates IP format
# 3. Agent adds temporary firewall rule
# 4. Rule auto-expires after 12 hours
# 5. User accesses dashboard from mobile
12.6 API Authentication
# For REST API — Bearer token authentication:
# In config.yaml:
api:
auth:
enabled: true
token: "your-secret-token-here"
# Client usage:
curl -H "Authorization: Bearer your-secret-token-here" \
http://localhost:8780/api/stats
# For coordination server — token auth:
coordination:
auth:
token: "coord-secret-token"
# All requests must include:
requests.get(f"{COORD}/agents",
headers={"Authorization": "Bearer coord-secret-token"})
12.7 TLS/HTTPS for Production
# Generate self-signed certificate (internal use):
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 365 -nodes -subj "/CN=uaml-server"
# Or use Let's Encrypt (if exposed):
certbot certonly --standalone -d uaml.yourdomain.com
# In config.yaml:
dashboard:
tls:
cert: /path/to/cert.pem
key: /path/to/key.pem
12.8 Security Checklist
| ✅ Check | Command |
|---|---|
| No unnecessary ports open | ss -tlnp |
| Firewall active | ufw status |
| Dashboard not on 0.0.0.0 | Check bind in config |
| SSH key-only auth | grep PasswordAuthentication /etc/ssh/sshd_config |
| Automatic updates | apt list --upgradable |
| UAML audit trail active | uaml health |
| PII detection enabled | Check Focus Engine config |
| Telemetry opt-out (if desired) | uaml config set telemetry false |
| File permissions | ls -la ~/.uaml/memory.db (should be 600) |
| Backups scheduled | crontab -l \| grep backup |