feat(satellite): RVS_SNI — wie beim Host-Agent (interne IP + Cert-Hostname)

Gleiche Faehigkeit wie beim host-agent: ein Satellit im selben Netz wie der RVS
kann direkt auf die interne IP verbinden und trotzdem den Cert-Namen im TLS-SNI
praesentieren (Caddy findet sonst kein Zertifikat -> tlsv1 alert internal error).
Nuetzlich z.B. fuer einen RZ-internen Satelliten, nur um Credentials zu hinterlegen.
RVS_HOST=<ip> + RVS_SNI=<name>; leer = Verhalten wie bisher.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 17:19:59 +02:00
co-authored by Claude Opus 4.8
parent 855cc0333e
commit 39f7947da9
2 changed files with 21 additions and 3 deletions
+6
View File
@@ -7,6 +7,12 @@ RVS_HOST=rvs.example.de
RVS_PORT=443
RVS_TLS=true
RVS_TOKEN=
# RVS_SNI: nur noetig, wenn RVS_HOST eine IP ist (Satellit im selben Netz wie der
# RVS, direkt auf die interne IP). Dann hier den Zertifikats-/Hostnamen angeben,
# damit der TLS-Handshake (SNI) passt. Sonst leer lassen.
# RVS_HOST=10.0.0.2
# RVS_SNI=example.com
RVS_SNI=
# ─── Identitaet / Adresse dieses Satelliten ────────────────────────
# SATELLITE_ID = technisch eindeutig (a-z0-9-_), Default = Hostname-Slug.
+15 -3
View File
@@ -107,6 +107,10 @@ RVS_HOST = os.environ.get("RVS_HOST", "")
RVS_PORT = int(os.environ.get("RVS_PORT", "443") or "443")
RVS_TLS = _env_bool("RVS_TLS", True)
RVS_TOKEN = os.environ.get("RVS_TOKEN", "")
# TLS-Hostname (SNI + Zertifikatspruefung), falls RVS_HOST eine IP ist — z.B. ein
# Satellit im selben Netz wie der RVS, der direkt auf die interne IP verbindet
# (das Caddy-Zertifikat gilt aber fuer den Namen). Leer = SNI = RVS_HOST.
RVS_SNI = os.environ.get("RVS_SNI", "").strip()
SATELLITE_ID = (os.environ.get("SATELLITE_ID") or _default_id()).strip()
SATELLITE_LOCATION = (os.environ.get("SATELLITE_LOCATION") or SATELLITE_ID).strip()
@@ -1316,13 +1320,21 @@ class Satellite:
_creds_load()
asyncio.create_task(self._periodic_scan())
backoff = 1
# SNI-/Cert-Override: auf eine IP verbinden, aber den Namen im TLS-
# Handshake praesentieren (Caddy-Cert gilt fuer den Namen).
connect_kwargs = {"max_size": 8 * 1024 * 1024,
"ping_interval": 20, "ping_timeout": 20}
if RVS_TLS and RVS_SNI:
import ssl
connect_kwargs["ssl"] = ssl.create_default_context()
connect_kwargs["server_hostname"] = RVS_SNI
while True:
proto = "wss" if RVS_TLS else "ws"
url = f"{proto}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
try:
logger.info("Verbinde mit RVS %s://%s:%s …", proto, RVS_HOST, RVS_PORT)
async with websockets.connect(url, max_size=8 * 1024 * 1024,
ping_interval=20, ping_timeout=20) as ws:
logger.info("Verbinde mit RVS %s://%s:%s%s …", proto, RVS_HOST, RVS_PORT,
f" (SNI {RVS_SNI})" if RVS_SNI else "")
async with websockets.connect(url, **connect_kwargs) as ws:
self.ws = ws
backoff = 1
await self._hello(log=True)