Cloud HSM-Schlüssel für TLS-Offloading mit NGINX verwenden

Diese Anleitung enthält eine Anleitung zum Einrichten von NGINX zur Verwendung eines Cloud HSM-Schlüssels für die TLS-Übertragung unter Debian 11 (Bullseye). Möglicherweise müssen Sie diese Befehle ändern, damit sie mit Ihrer Betriebssystem- oder Linux-Distribution funktionieren.

Anwendungsfälle

Die Verwendung eines Cloud HSM-Schlüssels mit NGINX für TLS-Auslagerung hilft dabei, die folgenden Sicherheitsanforderungen von Unternehmen zu erfüllen:

  • Sie möchten, dass Ihr NGINX-Webserver kryptografische TLS-Vorgänge auf Cloud HSM auslagert.
  • Sie sollten den privaten Schlüssel Ihres Zertifikats nicht im lokalen Dateisystem der Compute Engine-Instanz speichern, auf der Ihre Webanwendung gehostet wird.
  • Sie müssen die regulatorischen Anforderungen erfüllen, wenn ihre Zertifikate für öffentliche Anwendungen durch ein HSM geschützt werden müssen, das nach FIPS 140-2 Level 3 zertifiziert ist.
  • Sie möchten mit NGINX einen Reverse-Proxy mit TLS-Beendigung erstellen, um Ihre Webanwendung zu schützen.

Hinweise

Führen Sie die Schritte unter Cloud HSM-Schlüssel mit OpenSSL verwenden aus, bevor Sie fortfahren.

Prüfen Sie nach Abschluss der OpenSSL-Einrichtung, ob eine aktuelle Version von nginx installiert ist:

sudo apt-get update
sudo apt-get install libengine-pkcs11-openssl opensc nginx

Empfehlungen für die Sicherheitskonfiguration

Schützen Sie die Instanz, auf der NGINX gehostet wird, mit den folgenden Empfehlungen:

  1. Folgen Sie der Anleitung zum Erstellen und Aktivieren von Dienstkonten für Instanzen, um NGINX zu hosten.

    1. Weisen Sie die folgenden Rollen zu:
      • roles/cloudkms.signerVerifier
      • roles/cloudkms.viewer
  2. Konfigurieren Sie Organisationsrichtlinien wie unten beschrieben, um externe IP-Adressen zu begrenzen und Dienstkontoschlüssel zu erstellen.

    • constraints/compute.vmExternalIpAccess
    • constraints/iam.disableServiceAccountKeyCreation
  3. Erstellen Sie ein benutzerdefiniertes Subnetz, das den privaten Google-Zugriff ermöglicht.

  4. Firewallregeln konfigurieren

  5. Erstellen Sie eine Linux-VM und konfigurieren Sie sie so:

    • Wählen Sie das richtige Dienstkonto aus, das Sie zuvor erstellt haben.
    • Wählen Sie das Netzwerk aus, das Sie zuvor erstellt haben.
      • Fügen Sie geeignete Labels für alle Firewallregeln hinzu.
      • Achten Sie darauf, dass das Feld „Externe IP-Adresse“ im Subnetz auf none festgelegt ist.
  6. Gewähren Sie Ihrer Identität die Rolle „Nutzer von IAP-gesicherten Tunneln“ (roles/iap.tunnelResourceAccessor) für die Instanz.

In Cloud KMS gehosteten Signaturschlüssel erstellen und konfigurieren

In den nächsten Abschnitten werden die Schritte zum Erstellen und Konfigurieren eines Cloud KMS-gehosteten Signaturschlüssels beschrieben.

In Cloud KMS gehosteten Signaturschlüssel erstellen

Erstellen Sie in Ihrem Google Cloud-Projekt in dem Schlüsselbund, den Sie zuvor für OpenSSL konfiguriert haben, einen Cloud KMS-Signaturschlüssel EC-P256-SHA256:

gcloud kms keys create NGINX_KEY \
  --keyring "KEY_RING" --project "PROJECT_ID" \
  --location "LOCATION" --purpose "asymmetric-signing" \
  --default-algorithm "ec-sign-p256-sha256" --protection-level "hsm"

SSH-Verbindung zur VM mit IAP herstellen

Stellen Sie mit dem folgenden Befehl über IAP eine SSH-Verbindung zu Ihrer VM her:

gcloud compute ssh INSTANCE \
  --zone ZONE --tunnel-through-iap

Wenn ein Problem auftritt, prüfen Sie, ob Sie das Flag --tunnel-through-iap verwendet haben. Prüfen Sie außerdem, ob Sie die Rolle „IAP-Secured Tunnel User“ (roles/iap.tunnelResourceAccessor) auf der Instanz für die Identität haben, die mit der gcloud CLI authentifiziert wird.

Zertifikat mit OpenSSL erstellen

Erstellen Sie für eine Produktionsumgebung eine Anfrage zur Zertifikatsignierung (Certificate Signing Request, CSR). Weitere Informationen finden Sie im Beispiel zum Generieren einer CSR. Geben Sie die CSR an Ihre Zertifizierungsstelle weiter, damit diese ein Zertifikat für Sie erstellen kann. Verwenden Sie in den folgenden Abschnitten das von Ihrer Zertifizierungsstelle bereitgestellte Zertifikat.

Sie können beispielsweise ein selbst signiertes Zertifikat mit dem in Cloud KMS gehosteten Signaturschlüssel generieren. Dazu können Sie mit OpenSSL PKCS #11-URIs anstelle eines regulären Pfads verwenden, der den Schlüssel anhand seines Labels identifiziert (bei Cloud KMS-Schlüsseln ist das Label der CryptoKey-Name).

openssl req -new -x509 -days 3650 -subj '/CN=CERTIFICATE_NAME/' \
  DIGEST_FLAG -engine pkcs11 -keyform engine \
  -key PKCS_KEY_TYPE=KEY_IDENTIFIER > CA_CERT

Ersetzen Sie Folgendes:

  • CERTIFICATE_NAME ist ein Name für das Zertifikat.
  • DIGEST_FLAG: Der vom asymmetrischen Signaturschlüssel verwendete Digest-Algorithmus. Verwenden Sie je nach Schlüssel -sha256, -sha384 oder -sha512.
  • PKCS_KEY_TYPE: die Art der Kennung, die zur Identifizierung des Schlüssels verwendet wird. Wenn Sie die neueste Schlüsselversion verwenden möchten, geben Sie pkcs11:object mit dem Namen des Schlüssels ein. Wenn Sie eine bestimmte Schlüsselversion nutzen möchten, geben Sie pkcs11:id mit der vollständigen Ressourcen-ID der Schlüsselversion ein.
  • KEY_IDENTIFIER: eine Kennung für den Schlüssel. Wenn Sie pkcs11:object verwenden, verwenden Sie den Namen des Schlüssels, z. B. NGINX_KEY. Wenn Sie pkcs11:id verwenden, geben Sie die vollständige Ressourcen-ID des Schlüssels oder der Schlüsselversion an, z. B. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/NGINX_KEY/cryptoKeyVersions/KEY_VERSION.
  • CA_CERT: der Pfad, unter dem Sie die Zertifikatsdatei speichern möchten.

Wenn der Befehl fehlschlägt, wurde PKCS11_MODULE_PATH möglicherweise falsch festgelegt oder Sie haben nicht die erforderlichen Berechtigungen zur Verwendung des Cloud KMS-Signaturschlüssels.

Sie sollten jetzt ein Zertifikat haben, das so aussieht:

-----BEGIN CERTIFICATE-----
...
...
...
-----END CERTIFICATE-----

Zertifikat für NGINX installieren

Führen Sie die folgenden Befehle aus, um einen Speicherort für Ihr öffentliches Zertifikat zu erstellen:

sudo mkdir /etc/ssl/nginx
sudo mv CA_CERT /etc/ssl/nginx

Konfigurieren Sie Ihre Umgebung für die Verwendung der PKCS #11-Bibliothek

In den nächsten Abschnitten werden die Schritte zum Vorbereiten und Testen Ihrer Umgebung beschrieben.

Bibliothekskonfigurationen für NGINX vorbereiten

Erlauben Sie NGINX, seine PKCS #11-Engine-Vorgänge mit der Bibliothek so zu protokollieren:

sudo mkdir /var/log/kmsp11
sudo chown www-data /var/log/kmsp11

Erstellen Sie eine leere Bibliothekskonfigurationsdatei mit den entsprechenden Berechtigungen für NGINX.

sudo touch /etc/nginx/pkcs11-config.yaml
sudo chmod 744 /etc/nginx/pkcs11-config.yaml

Bearbeiten Sie die leere Konfigurationsdatei und fügen Sie die erforderliche Konfiguration hinzu, wie im folgenden Snippet gezeigt:

# cat /etc/nginx/pkcs11-config.yaml
---
tokens:
  - key_ring: "projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING"
log_directory: "/var/log/kmsp11"

OpenSSL-Konfiguration testen

Führen Sie dazu diesen Befehl aus:

openssl engine -tt -c -v pkcs11

Die Ausgabe sollte in etwa so aussehen:

(pkcs11) pkcs11 engine
 [RSA, rsaEncryption, id-ecPublicKey]
     [ available ]
     SO_PATH, MODULE_PATH, PIN, VERBOSE, QUIET, INIT_ARGS, FORCE_LOGIN

NGINX für die Verwendung von Cloud HSM konfigurieren

Lassen Sie die TLS-Auslagerung durch Bearbeiten einiger NGINX-Dateien zu. Bearbeiten Sie zuerst die Datei /etc/nginx/nginx.conf an zwei Stellen und fügen Sie einige Anweisungen hinzu, um NGINX für die Verwendung von PKCS #11 zu konfigurieren.

Fügen Sie nach dem event-Block und vor dem http-Block die folgenden Anweisungen hinzu:

ssl_engine pkcs11;
env KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml;

Konfigurieren Sie in derselben Datei /etc/nginx/nginx.conf SSL-Anweisungen zur Verwendung Ihres Zertifikats und seines privaten Schlüssels in Cloud HSM. Fügen Sie dem http-Block die folgenden Attribute hinzu:

ssl_certificate "/etc/ssl/nginx/CA_CERT";
ssl_certificate_key "engine:pkcs11:PKCS_KEY_TYPE=KEY_IDENTIFIER";
ssl_protocols TLSv1.2 TLSv1.3; # Consider changing the default to only TLS1.2 or newer

# Consider defining the `ssl_ciphers` to use ciphers approved by your security teams and handle
# appropriate client compatibility requirements.

Ihre /etc/nginx/nginx.conf-Datei sollte so aussehen:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

ssl_engine pkcs11;
env KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml;

http {

        #...
        #...

        # SSL configuration
        ssl_certificate "/etc/ssl/nginx/CA_CERT";
        ssl_certificate_key "engine:pkcs11:pkcs11:object=NGINX_KEY";
        ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        # ssl_ciphers YOUR_CIPHERS
        ssl_prefer_server_ciphers on;

        #...
        #...

}

NGINX für das Überwachen von TLS-Traffic konfigurieren

Bearbeiten Sie die Datei /etc/nginx/sites-enabled/default, um TLS-Traffic zu überwachen. Entfernen Sie das Kommentarzeichen für die SSL-Konfiguration im Block server. Die resultierende Änderung sollte in etwa so aussehen:


server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;

        # ...
        # ...
}

Umgebungsvariablen für den NGINX-Dienst bereitstellen

Führen Sie dazu diesen Befehl aus:

sudo systemctl edit nginx.service

Fügen Sie im resultierenden Editor die folgenden Zeilen hinzu und ersetzen Sie LIBPATH durch den Wert für den Standort, an dem Sie libkmsp11.so installiert haben:

[Service]
Environment="GRPC_ENABLE_FORK_SUPPORT=1"
Environment="KMS_PKCS11_CONFIG=/etc/nginx/pkcs11-config.yaml"
Environment="PKCS11_MODULE_PATH=LIBPATH/libkmsp11-1.0-linux-amd64/libkmsp11.so"

Nachdem Sie diese Werte konfiguriert haben, müssen Sie den folgenden Befehl ausführen, um sie verfügbar zu machen:

sudo systemctl daemon-reload

NGINX mit TLS-Offloading neu starten

Führen Sie den folgenden Befehl aus, damit NGINX neu startet und die aktualisierte Konfiguration verwendet:

sudo systemctl start nginx

Test NGINX verwendet die TLS-Auslagerung zu Ihrem Cloud HSM

Verwenden Sie openssl s_client, um die Verbindung zu Ihrem NGINX-Server zu testen. Führen Sie dazu den folgenden Befehl aus:

openssl s_client -connect localhost:443

Der Client sollte den SSL-Handshake abschließen und pausieren. Der Client wartet auf Ihre Eingaben, wie hier gezeigt:

# completes SSL handshake
# ...
# ...
# ...
    Verify return code: 18 (self signed certificate)
# ...
    Max Early Data: 0
---
read R BLOCK

# When the client pauses, it’s waiting for instructions.
# Have the client get the index.html file in the root path (“/”), by typing the following:

GET /

# Press enter.
# You should now see the default NGINX index.html file.

In den Audit-Logs sollten jetzt Vorgänge für den Schlüssel NGINX_KEY angezeigt werden. Rufen Sie Cloud Logging in der Cloud Console auf, um die Logs anzusehen. Fügen Sie dem verwendeten Projekt den folgenden Filter hinzu:

resource.type="cloudkms_cryptokeyversion"

Nachdem Sie die Abfrage ausgeführt haben, sollten asymmetrische Schlüsselvorgänge für Ihren NGINX_KEY-Schlüssel angezeigt werden.

Optionale Konfigurationen

Möglicherweise müssen Sie einen externen Passthrough-Network Load Balancer erstellen, um Ihren NGINX-Server mit einer externen IP-Adresse verfügbar zu machen.

Wenn Sie NGINX als Reverse-Proxy mit Load-Balancing verwenden müssen, sollten Sie die NGINX-Konfigurationsdatei aktualisieren. Weitere Informationen zum Konfigurieren von NGINX als Reverse-Proxy finden Sie unter Vollständig aktive HA für NGINX Plus auf der Google Cloud Platform.

Weitere Informationen

Sie haben jetzt Ihren NGINX-Server so konfiguriert, dass die TLS-Übertragung an Cloud HSM verwendet wird.