Release / verify (push) Canceled after 0s
CI / checks (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 0s
Release / test (push) Canceled after 0s
Release / publish (backend) (push) Canceled after 0s
Release / publish (frontend) (push) Canceled after 0s
Release / publish (proxy) (push) Canceled after 0s
Release / publish (updater) (push) Canceled after 0s
- **Management-Tunnel** (System › Management-Tunnel): Firewalls hinter NAT/CGNAT verwalten. Ein optionaler WireGuard-Hub auf dem OPNexus-Server (Compose-Profil `overlay`, Container `wg-hub` aus dem Backend-Image mit `NET_ADMIN`) nimmt die Firewalls entgegen, die sich nach außen einwählen; OPNexus erreicht deren API über einen kleinen CONNECT-Proxy des Hubs, der nur ins Tunnel-Netz verbindet. Je Firewall eine Tunnel-Adresse und ein eigener Pre-Shared Key, Anleitung mit kopierbaren Werten, Live-Status (Handshake, Datenmenge). Der Hub nimmt keine neuen Verbindungen aus dem Tunnel an. Ende-zu-Ende gegen eine echte OPNsense 26.7 geprüft (Handshake, API, Zertifikat festsetzen). Neue Tabellen `overlay_settings`, `overlay_peers` (Migration `0015`); das Backend-Image enthält jetzt `wireguard-tools`, `iproute2`, `iptables`.
40 lines
1.8 KiB
Python
40 lines
1.8 KiB
Python
"""Management overlay: a WireGuard hub so OPNexus can reach firewalls behind NAT/CGNAT.
|
|
|
|
The firewall dials OUT to the hub; OPNexus then talks to its API at the firewall's overlay address. Keys live
|
|
on disk (services/overlay_service.py), never in the database.
|
|
"""
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, func
|
|
from sqlalchemy.dialects.postgresql import UUID as PGUUID
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class OverlaySettings(Base):
|
|
__tablename__ = "overlay_settings"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
# host or host:port that firewalls dial (public name/IP of this server and the published UDP port)
|
|
endpoint: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
|
subnet: Mapped[str] = mapped_column(String(18), nullable=False, default="10.99.0.0/24")
|
|
listen_port: Mapped[int] = mapped_column(Integer, nullable=False, default=51820)
|
|
|
|
|
|
class OverlayPeer(Base):
|
|
__tablename__ = "overlay_peers"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
name: Mapped[str] = mapped_column(String(80), nullable=False, unique=True)
|
|
ip: Mapped[str] = mapped_column(String(15), nullable=False, unique=True)
|
|
# the firewall's WireGuard public key, entered once the firewall side exists
|
|
public_key: Mapped[Optional[str]] = mapped_column(String(44), nullable=True, unique=True)
|
|
host_id: Mapped[Optional[uuid.UUID]] = mapped_column(
|
|
PGUUID(as_uuid=True), ForeignKey("opnsense_hosts.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|