Zum Inhalt

TLS / Zertifikat

Fünf Wege — der zweite ist für die meisten der richtige.

Weg Wann
1 — Selbstsigniert Standard nach der Installation, für Tests
2 — Zertifikat aus Vesana Let's Encrypt oder Firmen-CA, Vesana erneuert selbst
3 — Eigenes Zertifikat hochladen gekauftes Zertifikat, Firmen-CA ohne ACME
4 — Von Hand (certbot o. ä.) bestehende Abläufe auf dem Host
5 — Reverse-Proxy davor TLS endet schon vor Vesana

Weg 1 — Selbstsigniert (Standard)

Ohne eigenes Zertifikat erzeugt der nginx-Container beim ersten Start ein selbstsigniertes Paar (10 Jahre, CN = Host aus BASE_URL) im Volume ssl. HTTPS funktioniert damit sofort, der Browser warnt aber, und Agents verbinden sich nur mit einem Zertifikats-Pin (den der Installationsbefehl mitbringt).

Weg 2 — Zertifikat direkt aus Vesana

Admin → System → Zertifikat. Vesana holt das Zertifikat selbst per ACME (das Protokoll von Let's Encrypt), setzt es ein und erneuert es rechtzeitig — ohne certbot, ohne Cronjob, ohne Handarbeit auf dem Host. Die Compose-Datei bleibt, wie sie ist.

1. Namen

Alle Namen, unter denen Vesana erreichbar ist: Browser-Adresse, die Server-URL der Agents, beim Split-Container-Modus der Admin-Host. Wildcards (*.firma.it) gehen nur mit der DNS-Prüfung; ein Wildcard deckt genau eine Ebene (a.firma.it), nicht firma.it selbst und nicht a.b.firma.it.

2. Prüfung und CA

Prüfung Voraussetzung
DNS-Anbieter (empfohlen) Vesana legt kurz einen TXT-Eintrag _acme-challenge.<name> über die API Ihres DNS-Anbieters an. Kein Port von außen nötig, Wildcards möglich.
HTTP über Port 80 Der Name muss aus dem Internet auf Port 80 bis zu diesem Server reichen. Vesana leitet dann nur /.well-known/acme-challenge/ an sich selbst weiter, alles andere bleibt die Umleitung auf HTTPS. Hat der Name einen AAAA-Eintrag, prüft Let's Encrypt zuerst über IPv6.

CA: Let's Encrypt, Let's Encrypt (Test) (Staging — Zertifikate, denen niemand vertraut; zum Ausprobieren) oder eine eigene ACME-CA (z. B. step-ca, Smallstep, Sectigo/HARICA mit EAB). Bei einer eigenen CA tragen Sie die Verzeichnis-Adresse ein, bei Bedarf EAB-Kennung und -Schlüssel und — wenn die CA selbst ein Firmen-Zertifikat nutzt — deren Wurzel.

3. DNS-Anbieter

Vesana kennt alle DNS-Anbieter von lego (über 200, darunter OVH, Cloudflare, IONOS, Hetzner, Route 53, Azure DNS, Google Cloud DNS, Gandi, INWX, Netcup, Infomaniak, deSEC, PowerDNS, RFC2136 und acme-dns). Die Felder je Anbieter erscheinen von selbst; „Anleitung für …" führt zur Seite des Anbieters mit den Rechten, die das Konto braucht.

Beispiel OVH: OVH kennt drei Anmeldearten — Application-Key + Secret + Consumer-Key, OAuth2 (Client-ID + Secret) oder ein Access-Token, jeweils mit OVH_ENDPOINT (z. B. ovh-eu). Es reicht EINE davon. Für den Consumer-Key genügen die Rechte POST und DELETE auf /domain/zone/*.

Zugang prüfen legt einen Test-Eintrag an, wartet, bis er sichtbar ist, und entfernt ihn wieder — ohne die CA zu fragen. So sehen Sie sofort, ob Zugangsdaten und Rechte stimmen.

Zugangsdaten liegen verschlüsselt in der Datenbank (AES-256-GCM) und kommen in keiner Antwort, keinem Protokoll und keinem Support-Bundle im Klartext vor. Geben Sie dem Konto nur Rechte auf die eine Zone.

Windows-DNS / DNS ohne API

Zwei Wege:

  • CNAME-Delegation: In Ihrer Zone einmalig je Name einen CNAME anlegen, der auf eine Zone mit API zeigt, und dort den Anbieter wählen:
    _acme-challenge.vesana.firma.it.  CNAME  _acme-challenge.vesana.firma.it.acme.firma-acme.de.
    
    Vesana folgt dem CNAME und schreibt den TXT-Eintrag in die delegierte Zone.
  • RFC2136 (Anbieter „RFC2136"/dnsupdate): dynamisches Update direkt an den DNS-Server — mit TSIG-Schlüssel oder, für Active Directory, mit Kerberos (GSS-TSIG: DNSUPDATE_TSIG_GSS_REALM, …_USERNAME, …_PASSWORD).

Firmennetz ohne Weg nach außen

Ob der Prüf-Eintrag angekommen ist, fragt Vesana bei den autoritativen Nameservern der Zone nach — dort sieht auch die CA nach. Die Antworten der Resolver im eigenen Netz stehen nur zur Information daneben: ein Resolver, der zu früh gefragt wurde, merkt sich „gibt es nicht“ für die Negativ-Zwischenspeicherzeit der Zone (oft 10–60 Minuten).

Blockt das Netz DNS-Anfragen nach außen (Port 53), unter „Resolver und Propagation" eigene Resolver eintragen und „Nur über die Resolver prüfen" wählen — oder „Nur warten" mit einer festen Wartezeit. Erreicht der Server die CA gar nicht, nennt die Fehlermeldung das; dann bleiben eine eigene CA im Firmennetz oder Weg 3.

4. Ausstellen und einsetzen

  1. Nutzungsbedingungen der CA anzeigen und bestätigen (einmal je CA).
  2. Probelauf: stellt bei Let's Encrypt ein Test-Zertifikat in Staging aus (zählt nicht gegen die Grenzen) und setzt nichts ein.
  3. Ausstellen: das Zertifikat liegt danach „bereit". Lief kurz vorher ein Probelauf (oder eine andere Ausstellung) für dieselben Namen, wartet Vesana zuerst die Lebensdauer (TTL) des Prüf-Eintrags ab — meist 2 bis 5 Minuten, angezeigt mit Uhrzeit: die Resolver der CA merken sich den alten Eintrag so lange, und eine Prüfung davor würde abgelehnt.
  4. Vorprüfung: Vesana nennt jedes Gerät (Agent, Collector), dessen Server-URL das neue Zertifikat nicht abdeckt — z. B. weil es Vesana über eine IP-Adresse erreicht. Solche Geräte vorher über Admin → Agents & Collectors → Agent-Verbindung auf einen gedeckten Namen umziehen. Mit Befund geht Einsetzen nur mit ausdrücklicher Bestätigung.
  5. Einsetzen: der Updater prüft das Paar noch einmal, schreibt es atomar, testet die nginx-Konfiguration, lädt alle nginx-Rollen neu (Weboberfläche, Agent-Gateway, Admin-Port) und prüft per TLS-Verbindung, dass das neue Zertifikat ausgeliefert wird. Scheitert ein Schritt, ist sofort die vorige Fassung wieder da.
  6. Kontrollphase (30 Minuten): Vesana beobachtet, ob Agents/Collectors, die vorher Kontakt hatten, weiter melden, und nennt jedes, das schweigt.

Erneuern

Vesana erneuert von selbst: im Erneuerungsfenster, das die CA nennt (ARI), sonst wenn noch ein Drittel der Laufzeit übrig ist (90 Tage ⇒ nach 60 Tagen). Scheitert eine Erneuerung, versucht Vesana es nach 1 h, 6 h und dann täglich wieder — nie in enger Schleife. Der Grund steht auf der Seite, in der Instanz-Gesundheit und im Diagnose-Log (Kategorie „Zertifikat"); dauert es länger als 48 Stunden, warnt der Check „TLS Certificate" am Host „Vesana Server" über die normalen Alarm-Regeln — Wochen vor dem Ablauf.

Rückweg, Ausschalten

  • Rückweg setzt die vorige Fassung wieder ein — gibt es keine, das Zertifikat, das vor dem ersten Einsetzen ausgeliefert wurde (meist das selbstsignierte).
  • ⚠️ HSTS: Vesana sendet Strict-Transport-Security. Sobald Browser Vesana einmal mit einem gültigen Zertifikat gesehen haben, blockieren sie den Namen bis zu einem Jahr, wenn wieder ein selbstsigniertes kommt — ohne „trotzdem fortfahren". Der Rückweg auf ein selbstsigniertes Zertifikat verlangt deshalb eine ausdrückliche Bestätigung.
  • ACME ausschalten behält das aktive Zertifikat bis zum Ablauf (mit Ablaufwarnung), erneuert aber nicht mehr.

Agents und Collectors

Ein öffentlich vertrautes Zertifikat (Let's Encrypt), das den Namen der Server-URL deckt, akzeptieren Agents und Collectors ohne Pin — auch solche, die bisher mit Pin auf das selbstsignierte verbunden waren. Ein ACME-Zertifikat pinnt Vesana nie (es wechselt bei jeder Erneuerung). Stammt das Zertifikat von einer Firmen-CA, muss deren Wurzel auf den Geräten im Vertrauensspeicher liegen. Der lokale Aktive Collector verbindet sich über localhost und ist nicht betroffen.

Backup und Umzug

Zertifikat, Schlüssel, ACME-Konto und Zugangsdaten liegen in der Datenbank. Nach einem Restore auf einer frischen Maschine setzt Vesana das Zertifikat innerhalb von 15 Minuten von selbst wieder ein.

Weg 3 — Eigenes Zertifikat hochladen

Admin → System → Zertifikat → Eigenes Zertifikat hochladen. Kette (Server-Zertifikat zuerst, dann die Zwischenzertifikate) und unverschlüsselten Schlüssel als PEM einfügen oder als Datei wählen. Vesana prüft, ob der Schlüssel passt, die Kette zusammenhängt und das Zertifikat gilt; eingesetzt wird über dieselbe Vorprüfung wie bei Weg 2. Die Ablaufwarnung gilt genauso.

Weg 4 — Von Hand (certbot o. ä.)

Der Stack-nginx liest genau EIN Paar aus dem Volume ssl: /etc/nginx/ssl/fullchain.pem + privkey.pem. Es gilt für alle Hostnamen, die dieser nginx bedient — bei aktivem Split-Container-Modus also auch für den Admin-Namen.

cd /opt/vesana   # dein Vesana-Verzeichnis
docker compose -f docker-compose.prod.yml cp /etc/letsencrypt/live/vesana.example.com/fullchain.pem nginx:/etc/nginx/ssl/fullchain.pem
docker compose -f docker-compose.prod.yml cp /etc/letsencrypt/live/vesana.example.com/privkey.pem  nginx:/etc/nginx/ssl/privkey.pem
docker compose -f docker-compose.prod.yml exec nginx nginx -s reload

Läuft das Agent-Gateway oder ein eigener Admin-Container, lesen diese dasselbe Paar — dort ebenfalls neu laden (… exec agent-gateway nginx -s reload bzw. … exec nginx-admin nginx -s reload).

Vesana erkennt ein so eingespieltes Zertifikat („von Hand eingespielt"), überschreibt es nie still und überwacht seinen Ablauf (Check „TLS Certificate").

Weg 5 — Reverse-Proxy davor

Wenn schon ein nginx / Traefik / HAProxy / Caddy vor dem Server steht und TLS dort terminiert wird.

Der Vesana-Stack spricht selbst immer HTTPS (mindestens mit dem selbstsignierten Zertifikat); sein HTTP-Port leitet nur auf HTTPS um. Der Reverse-Proxy reicht deshalb per HTTPS an den HTTPS-Port des Stacks weiter. Belegt der Proxy 80/443, bekommt Vesana in der .env andere Ports:

HTTPS_PORT=9443
HTTP_PORT=9080

(Nicht 8443 — das ist der Standard-Port des Agent-Gateways.) Danach den Stack neu anlegen.

Im externen Reverse-Proxy (nginx-Beispiel):

server {
  listen 443 ssl http2;
  server_name vesana.example.com;

  ssl_certificate     /etc/letsencrypt/live/vesana.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/vesana.example.com/privkey.pem;

  location / {
    proxy_pass https://127.0.0.1:9443;
    proxy_ssl_verify off;          # Stack-Zertifikat ist selbstsigniert; Verbindung bleibt auf 127.0.0.1
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";

    # Antwort-Header der Anmeldung sind größer als der nginx-Standardpuffer
    # (4 KB). Ohne diese Zeilen: „upstream sent too big header" → 502 beim Login.
    proxy_buffer_size       32k;
    proxy_buffers           8 32k;
    proxy_busy_buffers_size 64k;

    proxy_request_buffering off;
    proxy_read_timeout      1800s;
    client_max_body_size    20g;   # Backup-Upload und Offline-Update
  }
}

Danach drei Punkte:

  1. Echte Client-Adressen: Die Adresse bzw. das Netz des Proxys unter Admin → Anmeldung & Sicherheit → Admin-Zugriff → Erweitert als vertrauenswürdigen Proxy eintragen. Sonst sehen Sitzungsliste, Audit-Log und Admin-Allowlist alle Nutzer mit der Adresse des Proxys. Eine Umgebungsvariable dafür gibt es nicht.
  2. Agent-Gateway nicht entschlüsseln: Ist das Agent-Gateway aktiv, den Gateway-Port als reinen TCP-Stream durchleiten oder direkt erreichbar lassen — Agents und Collectors prüfen dort das Zertifikat des Stacks.
  3. Agents hinter dem Proxy: Der Installationsbefehl prüft, was unter der Agent-Server-URL wirklich antwortet: ein öffentlich vertrautes Zertifikat des Proxys braucht keinen Pin, ein anderes bekommt seinen eigenen.

Ein Zertifikat aus Vesana (Weg 2) per HTTP-Prüfung funktioniert hinter einem Proxy nur, wenn dieser /.well-known/acme-challenge/ an den HTTP-Port des Stacks weiterreicht; einfacher ist die DNS-Prüfung — oder das Zertifikat bleibt Sache des Proxys.

CSP

Der eingebaute nginx sendet eine strenge Content-Security-Policy und setzt sie durch: Skripte, Stile, Bilder, Verbindungen und Schriften sind nur von der Instanz selbst erlaubt (dazu die Kartenkacheln von OpenStreetMap und OpenFreeMap sowie Google Fonts). Das frame-ancestors 'none' der Richtlinie und X-Frame-Options: SAMEORIGIN verhindern das Einbetten von Vesana in fremde Seiten; nur ein Freigabe-Link eines Dashboards darf für die dort eingetragenen Ursprünge eingebettet werden. Die Browser melden Verstöße an die Instanz; sie erscheinen im Diagnose-Log (Kategorie „Sicherheit“). Ein Reverse-Proxy davor darf die Header nicht entfernen und sollte keine eigenen Skripte in die Seite einfügen, sie würden blockiert.

Header-Hygiene

Der eingebaute nginx setzt:

  • Strict-Transport-Security: max-age=31536000; includeSubDomains
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin
  • Permissions-Policy: geolocation=(), microphone=(), camera=()
  • Content-Security-Policy: …

Hinter einem eigenen Reverse-Proxy kommen diese Header vom Stack bereits mit; der Proxy muss sie nur durchlassen.

TLS-Test

curl -I https://vesana.example.com
# Sollte den HSTS-Header und 200 zurückgeben

Externe Werkzeuge:

  • SSL Labs Test für Cert-Chain und Cipher-Suite-Bewertung
  • testssl.sh für lokale Validierung

Anschluss