· IoT· netværkssikkerhed· VLAN· firewall· Cloudflare Tunnel· SSH· Raspberry Pi· sikkerhed· gateway
IoT netværkssikkerhed til gateway — VLAN, firewall og Cloudflare
Netværkssikkerhed til IoT gateway: VLAN-isolering, firewall-regler, Cloudflare Tunnel vs VPN, SSH-sikring og defense-in-depth for Raspberry Pi i kælderrum.
Af M-Bus Gateway
En IoT-gateway i kælderrummet er et potentielt angrebspunkt. Her er den defense-in-depth arkitektur M-Bus Gateway bruger til at beskytte gateways i felten.
Trusselsbillede: Gateway i kælderrum
Trusler mod en IoT-gateway:
Fysisk adgang:
→ Uautoriseret SD-kort-udtræk
→ USB-enhed med malware
→ Password reset via fysisk konsol
Netværksangreb:
→ Scanning af åbne porte (Shodan/Censys)
→ Brute force SSH
→ MQTT-afsnifning
→ Man-in-the-middle (usikker WiFi)
Supply chain:
→ Kompromitteret firmware (verificeres med GPG/SHA256)
→ Python-pakkeer med bagdøre
Mitigering:
→ Ingen åbne indgående porte
→ Cloudflare Tunnel (on-demand, max 30 min)
→ Mutual TLS på MQTT
→ SD-kort kryptering (luks2)
→ Minimal OS + automatiske sikkerhedsopdateringer
VLAN-isolering
Anbefalet netværksarkitektur (Unifi/pfSense):
VLAN 10 — IoT-netværk (gateway):
→ IP: 10.0.10.0/24
→ Gateway: 10.0.10.1 (router)
→ Tillader: Udgående MQTT 8883, NTP 123, DNS 53
→ Blokerer: Al trafik til LAN/WLAN
→ Blokerer: Indgående fra internet (ingen port forward)
VLAN 1 — Ejendomsnet (normal WiFi):
→ Ingen adgang til VLAN 10
Fordel:
→ Kompromitteret gateway har IKKE adgang til
lejernes netværk, NAS, routeren etc.
→ Kan kun kommunikere med Hetzner MQTT-broker
# Firewall-regler på gateway (ufw):
ufw default deny incoming
ufw default deny outgoing
# Tillad kun nødvendig udgående trafik:
ufw allow out to 178.105.90.8 port 8883 proto tcp # MQTT
ufw allow out to any port 53 proto udp # DNS
ufw allow out to any port 123 proto udp # NTP
ufw allow out to any port 443 proto tcp # Cloudflare Tunnel + OTA
ufw allow out to any port 80 proto tcp # HTTP (redirect til 443)
# Ingen indgående porte åbne
ufw enable
SSH-sikring
# /etc/ssh/sshd_config — sikkerhedshærdning:
# Deaktivér password-login (kun SSH-nøgle):
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile /home/mbus/.ssh/authorized_keys
# Ingen root-login:
PermitRootLogin no
# Kun mbus-brugeren:
AllowUsers mbus
# Tidsout inaktive sessioner (5 min):
ClientAliveInterval 300
ClientAliveCountMax 0
# Deaktivér X11 og port forwarding (unødvendigt):
X11Forwarding no
AllowTcpForwarding no
# Port → non-standard (mindsker scanner-noise):
# Port 2222 ← Kun hvis ejendomsnet ikke er VLAN-isoleret
# Genstart sshd:
systemctl restart ssh
# Fail2ban mod SSH brute force:
apt install fail2ban
# /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = ssh
maxretry = 3
bantime = 1h
findtime = 10m
Cloudflare Tunnel: Sikker fjernadgang
Cloudflare Tunnel eliminerer behovet for åbne indgående porte:
Uden tunnel (USIKKER):
Router: Port 22 → 10.0.10.5 (gateway)
Problem: SSH eksponeret på internet
Med Cloudflare Tunnel:
Gateway initierer udgående forbindelse til Cloudflare
Tekniker tilgår via cloudflared-klient (authed)
Ingen indgående porte nødvendige
M-Bus Gateway politik:
→ Tunnel KUN aktiveres on-demand (max 30 min)
→ Aktiveres via platform API: POST /api/v1/gateways/{id}/tunnel/start
→ Auto-stopper efter 30 min via systemd timer
→ Al tunnel-aktivitet logges i audit_log
Cloudflare Access:
→ Kræver godkendelse fra Cloudflare Access policy
→ Email-OTP eller SSO inden tunnel-adgang gives
# gateway/src/connectivity/tunnel.py
import subprocess
import asyncio
from pathlib import Path
TUNNEL_TIMEOUT = 30 * 60 # 30 minutter
async def start_tunnel_session(token: str) -> asyncio.subprocess.Process:
"""
Start Cloudflare Tunnel session.
Stoppes automatisk efter TUNNEL_TIMEOUT sekunder.
"""
proc = await asyncio.create_subprocess_exec(
"cloudflared", "tunnel", "--no-autoupdate", "run",
"--token", token,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
# Auto-stop efter 30 min:
asyncio.create_task(_auto_stop(proc, TUNNEL_TIMEOUT))
return proc
async def _auto_stop(proc: asyncio.subprocess.Process, timeout: int):
await asyncio.sleep(timeout)
if proc.returncode is None:
proc.terminate()
await asyncio.sleep(5)
if proc.returncode is None:
proc.kill()
Firmware-verifikation
# gateway/src/ota.py — Verificer firmware inden installation:
import hashlib
import subprocess
from pathlib import Path
def verify_firmware(firmware_path: Path, expected_sha256: str) -> bool:
"""SHA256-verificér firmware inden installation."""
sha256 = hashlib.sha256(firmware_path.read_bytes()).hexdigest()
if sha256 != expected_sha256:
return False # Afvis — korrupt eller manipuleret
return True
# OTA-kommando fra MQTT indeholder:
# {"url": "...", "sha256": "abc123...", "version": "1.2.3"}
# Gateway downloader ALDRIG og installerer ALDRIG uden SHA256-match
SD-kort og fysisk sikkerhed
# Read-only root filesystem (forhindrer persistens ved kompromittering):
# /etc/fstab:
/dev/mmcblk0p2 / ext4 ro,noatime 0 1
# Writable overmounts for nødvendige writes:
tmpfs /tmp tmpfs defaults,size=64M 0 0
tmpfs /var/log tmpfs defaults,size=32M 0 0
tmpfs /run tmpfs defaults 0 0
# Data-partition (SQLite + config) — separat, krypteret:
/dev/mmcblk0p3 /data ext4 rw,noatime 0 2
Konklusion
Defense-in-depth for IoT-gateway: VLAN-isolering begrænser blast radius ved kompromittering, ufw-firewall begrænser udgående trafik til kun MQTT/NTP/DNS/HTTPS, Cloudflare Tunnel eliminerer indgående porte, SSH-hærdning med kun nøgle-auth og Fail2ban. Det vigtigste enkelt-tiltag: Ingen åbne indgående porte — aldrig.