Sichere Verteilung privater SSL-Schlüssel mit NGINX

NGINX | 02. April 2019

Dieser Blogbeitrag beschreibt verschiedene Methoden zur sicheren Verteilung der privaten SSL-Schlüssel, die NGINX beim Hosting SSL-verschlüsselter Websites verwendet. Er erläutert:

Für viele Bereitstellungen ist der Standardansatz ausreichend. Die beiden in diesem Beitrag erläuterten, ausgefeilteren Ansätze verhindern weitere Möglichkeiten, über die ein Angreifer an private SSL-Schlüssel gelangen kann. In weiteren Beiträgen werden wir außerdem noch einige andere Techniken betrachten:

  • Verwendung von Drittanbieter-Geheimnisspeichern wie HashiCorp Vault zur sicheren Verteilung von Passwörtern
  • Automatisierung der Bereitstellung von Zertifikaten aus Vault für den Schlüssel-Wert-Speicher von NGINX Plus, sodass privates Schlüsselmaterial niemals auf der Festplatte gespeichert wird

Die in diesem Beitrag vorgestellten Ansätze richten sich an Benutzer, die ihre eigenen Schlüssel verwalten und eine eigene Strategie zur sicheren Schlüsselverteilung entwickeln müssen. Sie sind nicht erforderlich, wenn NGINX in Umgebungen ausgeführt wird, die bereits einen Secretspeicher integrieren, wie etwa Kubernetes.

Dieser Beitrag gilt sowohl für NGINX Open Source als auch für NGINX Plus. Der besseren Lesbarkeit halber verwenden wir im Folgenden die Bezeichnung „NGINX“.

Anmerkung der Redaktion: Dieser Beitrag ist der erste einer Reihe über den Schutz privater SSL-Schlüssel in NGINX. Lesen Sie auch die anderen Beiträge dieser Reihe:

Warum sollte der private SSL-Schlüssel geschützt werden?

SSL/TLS wird verwendet, um Netzwerktransaktionen zu authentifizieren, zu verschlüsseln und ihre Integrität zu überprüfen. Websites authentifizieren sich mithilfe eines von einer Zertifizierungsstelle (CA) signierten öffentlichen Zertifikats und weisen durch Berechnungen mit dem zugehörigen privaten Schlüssel nach, dass sie Eigentümer des Zertifikats sind (der Schlüssel muss geheim gehalten werden).

Wenn der private Schlüssel kompromittiert (gegenüber einer anderen Partei offengelegt) wird, bestehen zwei wesentliche Risiken.

  • Risiko 1: Identitätsvortäuschung. Ein Angreifer, der über den privaten Schlüssel verfügt, kann den Netzwerkverkehr abfangen und anschließend einen Man-in-the-Middle-Angriff (MITM) durchführen. Bei diesem Angriff wird der gesamte Datenverkehr abgefangen und entschlüsselt und möglicherweise auch verändert, ohne dass die Clients oder die Website dies bemerken.
  • Risiko 2: Entschlüsselung. Ein Angreifer, der über den privaten Schlüssel verfügt und den Netzwerkverkehr aufgezeichnet hat, kann diesen anschließend offline entschlüsseln. Beachten Sie, dass dieser Angriff nicht gegen Verbindungen eingesetzt werden kann, die eine Verschlüsselungssuite mit Perfect Forward Secrecy (PFS) verwenden.

Wenn der private Schlüssel kompromittiert wurde, bleibt Ihnen nur, die Zertifizierungsstelle zu kontaktieren und die Sperrung Ihres Zertifikats zu beantragen. Anschließend müssen Sie darauf vertrauen, dass die Clients den Sperrstatus überprüfen und berücksichtigen.

Darüber hinaus empfiehlt es sich, Zertifikate mit kurzer Gültigkeitsdauer zu verwenden (zum Beispiel laufen Let’s Encrypt-Zertifikate nach 90 Tagen ab). Kurz vor Ablauf eines Zertifikats müssen Sie einen neuen privaten Schlüssel generieren und ein neues Zertifikat von der Zertifizierungsstelle beziehen. Dadurch verringert sich Ihr Risiko für den Fall, dass der private Schlüssel kompromittiert wird.

Die NGINX-Sicherheitsgrenze

Welche Personen und Prozesse können in NGINX auf private SSL-Schlüssel zugreifen?

Zunächst einmal kann jeder Benutzer, der root-Zugriff auf den Server erlangt, auf dem NGINX ausgeführt wird, alle Ressourcen lesen und verwenden, die NGINX selbst nutzt. Beispielsweise gibt es bekannte Methoden, um den privaten SSL-Schlüssel aus dem Arbeitsspeicher eines laufenden Prozesses zu extrahieren.

Daher ist es unabhängig davon, wie der private Schlüssel gespeichert und verteilt wird, nicht möglich, ihn vor einem Angreifer mit root-Rechten auf dem Hostserver zu schützen.

Darüber hinaus kann jeder Benutzer, der die NGINX-Konfiguration ändern und einchecken kann, diese Berechtigung auf vielfältige Weise nutzen – etwa um den Proxy-Zugriff auf interne Dienste zu ermöglichen, Authentifizierungsmaßnahmen zu umgehen usw. Er oder sie kann die NGINX-Konfiguration so ändern, dass dadurch root-Zugriff (oder ein gleichwertiger Zugriff) auf den Server erlangt wird, wobei Tools wie SELinux und AppArmor dazu beitragen, dieses Risiko zu mindern.

Daher ist es im Allgemeinen nicht möglich, den privaten Schlüssel vor einem Angreifer zu schützen, der die NGINX-Konfiguration ändern und committen kann.

Glücklicherweise verfügt jede kompetente Organisation über solide Sicherheitsprozesse, die es einem Angreifer erschweren, root-Rechte zu erlangen oder die NGINX-Konfiguration zu ändern.

Es gibt jedoch zwei weitere Möglichkeiten, wie ein Angreifer mit geringeren Berechtigungen Zugriff auf den privaten Schlüssel erlangen könnte:

  • Ein Benutzer könnte aus einem berechtigten Grund die NGINX-Konfiguration einsehen müssen oder Zugriff auf eine Konfigurationsdatenbank oder eine Sicherungskopie erhalten. Private NGINX-Schlüssel werden üblicherweise in der Konfiguration gespeichert.
  • Ein Benutzer könnte Zugriff auf das Dateisystem des NGINX-Servers erlangen, beispielsweise über einen Hypervisor oder eine Systemsicherung. Auf sämtliche im Dateisystem gespeicherten Daten, einschließlich des privaten Schlüsselmaterials, kann potenziell zugegriffen werden.

Die in diesem Dokument beschriebenen Verfahren schließen diese beiden Angriffswege.

Standard-NGINX-Konfiguration

Zunächst sehen wir uns an, wie eine typische NGINX-Konfiguration mit SSL/TLS aussieht:

server {
    listen 443 ssl;

    server_name a.dev0; 

    ssl_certificate ssl/a.dev0.crt;
    ssl_certificate_key ssl/a.dev0.key;

    location / {
        return 200 "Hello from service A\n";
    }
}

Das öffentliche SSL-Zertifikat (a.dev0.crt) und der private Schlüssel (a.dev0.key) werden im Dateisystem unter /etc/nginx/ssl/ gespeichert. Der private Schlüssel wird nur vom NGINX-Masterprozess gelesen, der normalerweise als root ausgeführt wird. Daher können Sie dafür die strengstmöglichen Zugriffsberechtigungen festlegen:

root@web1:/etc/nginx/ssl# ls -l a.dev0.key-r-------- 1 root root 1766 Aug 15 16:32 a.dev0.key

Der private Schlüssel muss jederzeit verfügbar sein. Der NGINX-Masterprozess liest ihn bei jedem Start der NGINX-Software, beim Neuladen der Konfiguration oder bei der Durchführung einer Syntaxprüfung (nginx -t).

Weitere Informationen zur Konfiguration von SSL/TLS finden Sie im NGINX Plus-Administratorhandbuch.

Sicherheitsauswirkungen der Standardkonfiguration

Wie oben erwähnt, kann der private SSL-Schlüssel von einem Angreifer ausgelesen werden, der root-Zugriff auf den laufenden Container, die virtuelle Maschine oder den Server erlangt, auf dem die NGINX-Software ausgeführt wird.

SSL-Privatschlüssel verschlüsseln

NGINX unterstützt verschlüsselte private Schlüssel und verwendet dabei sichere Algorithmen wie AES256:

root@web1:/etc/nginx/ssl# mv a.dev0.key a.dev0.key.plainroot@web1:/etc/nginx/ssl# openssl rsa -aes256 -in a.dev0.key.plain -out a.dev0.key
writing RSA key
Enter PEM pass phrase: secure password
Verifying - Enter PEM pass phrase: secure password again

Wenn Sie NGINX anschließend starten oder die NGINX-Konfiguration neu laden bzw. testen, fragt NGINX interaktiv nach dem Entschlüsselungspasswort:

root@web1:/etc/nginx# nginx -tEnter PEM pass phrase: secure password
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Verwenden einer SSL-Passwortdatei

Die interaktive Eingabe von Passwörtern ist umständlich und lässt sich nur schwer automatisieren. Sie können NGINX jedoch so konfigurieren, dass eine Liste von Passwörtern verwendet wird, die in einer separaten, durch die Direktive ssl_password_file angegebenen Datei gespeichert ist. Wenn NGINX einen privaten Schlüssel lesen muss, versucht es, den Schlüssel nacheinander mit jedem Passwort in der Datei zu entschlüsseln. Ist keines der Passwörter gültig, verweigert NGINX den Start.

ssl_password_file /var/lib/nginx/ssl_passwords.txt;

Die Datei ssl_password_file muss getrennt von der Konfiguration verteilt werden und darf nur für den Benutzer root lesbar sein. Sie kann als Autorisierungstoken betrachtet werden, das auf vertrauenswürdigen Servern hinterlegt wird. NGINX kann die privaten Schlüssel nur entschlüsseln, wenn es auf einem Server mit diesem Autorisierungstoken ausgeführt wird.

Sicherheitsauswirkungen verschlüsselter Schlüssel in einer separaten Datei

Diese Methode reduziert die Angriffsfläche, da die NGINX-Konfiguration allein für einen Angreifer nutzlos ist. Der Angreifer muss zusätzlich auf den Inhalt der Datei ssl_password_file zugreifen.

Wenn ein Angreifer tatsächlich root-Zugriff auf das Dateisystem erlangt, in dem die ssl_password_file gespeichert ist (beispielsweise über eine Sicherungskopie oder das Hostsystem), kann er die Datei lesen und die Passwörter zum Entschlüsseln privater SSL-Schlüssel verwenden.

Sie können dieses Risiko verringern, indem Sie die Datei ssl_password_file auf einer RAM-Disk oder in einem tmpfs speichern. Auf diesen Speicher kann ein externer Angreifer in der Regel schwerer zugreifen (beispielsweise wird er beim Neustart des Servers gelöscht), und er kann von Systemsicherungen ausgeschlossen werden. Sie müssen sicherstellen, dass die Passwortdatei beim Systemstart initialisiert wird.

SSL-Passwortlisten sicherer verteilen

Der folgende Prozess beschreibt eine sicherere Methode zur Verteilung von Listen mit SSL-Passwörtern von einer zentralen Verteilstelle aus.

Immer wenn NGINX einen SSL-Schlüssel entschlüsseln muss, fragt es die zentrale Verteilstelle ab und verwendet die Passwörter, ohne sie jemals auf der lokalen Festplatte zu speichern. Zur Authentifizierung beim zentralen Passwortserver verwendet die NGINX-Instanz ein Token, das Sie jederzeit widerrufen können, um den Zugriff auf die Passwörter zu sperren.

Erstellen einer zentralen Passwortverteilstelle

Erstellen Sie zunächst einen zentralen Punkt zur Passwortverteilung (Password Distribution Point, PDP). Für diese einfache Implementierung verwenden wir einen HTTPS-Dienst, der die Passwortliste bereitstellt und eine Authentifizierung mit Benutzername und Passwort erfordert:

$ curl -u dev0:mypassword https://pdpserver.local/ssl_passwords.txt
password1
password2
...

Anschließend können Sie den Zugriff nach Bedarf gewähren oder widerrufen, indem Sie beim PDP Authentifizierungstoken hinzufügen oder entfernen. Sie können den Server zur Passwortverteilung mit einem Webserver wie NGINX implementieren und dabei jede geeignete Art von Authentifizierungstoken verwenden.

Als Nächstes müssen wir NGINX so einrichten, dass die Passwörter vom PDP abgerufen werden. Zunächst erstellen wir ein Shell-Skript namens connector.sh mit folgendem Inhalt:

#!/bin/sh
# Usage: connector.sh   

CONNECTOR=$1
CREDS=$2
PDP_URL=$3

[ -e $CONNECTOR ] && /bin/rm -f $CONNECTOR

mkfifo $CONNECTOR; chmod 600 $CONNECTOR

while true; do
    curl -s -u $CREDS -k $PDP_URL -o $CONNECTOR
done

Das Skript muss als Hintergrundprozess ausgeführt und wie folgt aufgerufen werden:

root@web1:~# ./connector.sh /var/run/nginx/ssl_passwords \dev0:mypassword https://pdpserver.local/ssl_passwords.txt &

Der Connector bindet sich an den angegebenen lokalen Pfad (/var/run/nginx/ssl_passwords), und mit der Direktive ssl_password_file konfigurieren Sie NGINX so, dass es auf diesen Pfad zugreift:

ssl_password_file /var/run/nginx/ssl_passwords;

Testen Sie den Konnektor, indem Sie aus dem Konnektorpfad lesen:

root@web1:~# cat /var/run/nginx/ssl_passwords
password1
password2
...

Überprüfen Sie, ob NGINX das Passwort lesen und die SSL-Schlüssel entschlüsseln kann:

root@web1:~# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Mit dem zentralen PDP-Ansatz können Sie alle Ressourcen, die NGINX normalerweise von der Festplatte liest, sicher verteilen, beispielsweise einzelne private Schlüssel oder andere sensible Daten.

Sicherheitsauswirkungen eines PDP

Diese Lösung bietet gegenüber der Speicherung von SSL-Passwörtern auf der Festplatte mehrere Vorteile:

  • Die SSL-Passwörter werden niemals im Dateisystem des Servers gespeichert, sodass Angreifer mit Zugriff auf das Dateisystem nicht direkt auf sie zugreifen können.
  • Passwörter werden von einer zentralen Zugriffsstelle aus verteilt, wodurch sich Überwachung und Audits leichter durchführen lassen.
  • Der Zugriff einzelner Server kann zentral gesteuert werden. Wenn beispielsweise ein Server außer Betrieb genommen wird, widerrufen Sie sein Zugriffstoken.

Beachten Sie, dass ein Benutzer mit Zugriff auf das Dateisystem möglicherweise die für den Zugriff auf den PDP verwendeten Anmeldedaten auslesen kann. Es ist wichtig, diese Anmeldedaten zu widerrufen, sobald sie nicht mehr benötigt werden.

Zusammenfassung

Es gibt viele Möglichkeiten, private SSL-Schlüssel vor Offenlegung zu schützen, die ein zunehmendes Maß an Sicherheit und Komplexität bieten:

  • Für die große Mehrheit der Unternehmen reicht es aus, den Zugriff auf die Umgebungen, in denen NGINX ausgeführt wird, so einzuschränken, dass unbefugte Benutzer keinen root-Zugriff erhalten und die NGINX-Konfiguration nicht einsehen können.
  • In einigen Umgebungen ist es möglicherweise nicht möglich, den Zugriff auf die NGINX-Konfiguration vollständig einzuschränken. In diesem Fall kann eine SSL-Passwortdatei verwendet werden.
  • In bestimmten Fällen möchten Organisationen möglicherweise sicherstellen, dass Schlüssel und Passwörter niemals auf einem Datenträger gespeichert werden. Der Prozess für den Passwortverteilungspunkt veranschaulicht einen Machbarkeitsnachweis für diese Lösung.

In den anderen Beiträgen dieser Reihe werden weitere Maßnahmen beschrieben, mit denen Sie SSL-Schlüssel schützen können:

Testen Sie NGINX Plus selbst – starten Sie noch heute Ihre kostenlose 30-Tage-Testversion oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen.


Teilen

Über den Autor

Owen Garrett
Owen GarrettSenior Director, Produktmanagement

Weitere Blogbeiträge von Owen Garrett

Ähnliche Blogbeiträge

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
NGINX | 23.08.2022

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln

Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
NGINX | 08.09.2021

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen

Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
NGINX | 16.08.2021

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet

Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
NGINX | 12.12.2018

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77

Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.

Ankündigung von NGINX Plus R16
NGINX | 05.09.2018

Ankündigung von NGINX Plus R16

NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
NGINX | 13.10.2016

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing

Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.