Utilizzare una chiave Cloud HSM per il trasferimento TLS con NGINX

Questa guida fornisce istruzioni per configurare NGINX in modo da utilizzare una chiave Cloud HSM per il trasferimento TLS su Debian 11 (Bullseye). Potresti dover modificare questi comandi in modo che funzionino con il tuo sistema operativo o la tua distribuzione Linux.

Puoi trovare una versione del progetto basata su Terraform di questo tutorial nel repository GitHub kms-solutions.

Casi d'uso

L'utilizzo di una chiave Cloud HSM con NGINX per il trasferimento TLS consente di rispondere alle seguenti esigenze di sicurezza aziendale:

  • Vuoi che il server web NGINX offload le operazioni di crittografia TLS su Cloud HSM.
  • Non vuoi memorizzare la chiave privata del certificato nel file system locale dell'istanza Compute Engine che ospita la tua applicazione web.
  • Devi soddisfare i requisiti normativi per le applicazioni rivolte al pubblico, i cui certificati devono essere protetti da un HSM con certificazione FIPS 140-2 di livello 3.
  • Vuoi utilizzare NGINX per creare un proxy inverso con terminazione TLS per proteggere la tua applicazione web.

Prima di iniziare

Prima di continuare, completa i passaggi descritti in Utilizzo di una chiave Cloud HSM con OpenSSL.

Al termine della configurazione di OpenSSL, assicurati che sia installata una versione recente di nginx:

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

Suggerimenti per la configurazione di sicurezza

Proteggi l'istanza che ospita NGINX con i seguenti consigli:

  1. Segui le istruzioni per creare e abilitare gli account di servizio per le istanze per ospitare NGINX.

    1. Assegna i seguenti ruoli:
      • roles/cloudkms.signerVerifier
      • roles/cloudkms.viewer
  2. Configura i criteri dell'organizzazione come segue per limitare gli IP esterni e la creazione di chiavi dell'account di servizio.

    • constraints/compute.vmExternalIpAccess
    • constraints/iam.disableServiceAccountKeyCreation
  3. Crea una subnet personalizzata che abiliti l'accesso privato Google.

  4. Configura le regole del firewall.

  5. Crea una VM Linux e configurala nel seguente modo:

    • Seleziona l'account di servizio corretto che hai creato in precedenza.
    • Seleziona la rete creata in precedenza.
      • Aggiungi le etichette appropriate per le eventuali regole firewall.
      • Assicurati che il campo "IP esterno" della subnet sia impostato su none.
  6. Concedi alla tua identità il ruolo IAP-Secured Tunnel User (roles/iap.tunnelResourceAccessor) nell'istanza.

Crea e configura una chiave di firma ospitata in Cloud KMS

Le sezioni seguenti descrivono i passaggi necessari per creare e configurare una chiave di firma ospitata in Cloud KMS.

Crea una chiave di firma ospitata in Cloud KMS

Crea una chiave di firma EC-P256-SHA256 Cloud KMS nel tuo progettoGoogle Cloud , nel portachiavi configurato in precedenza per OpenSSL:

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"

Accedi tramite SSH alla VM utilizzando IAP

Accedi alla VM tramite SSH utilizzando IAP con il seguente comando:

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

Se riscontri un problema, verifica di aver utilizzato il flag --tunnel-through-iap. Inoltre, verifica di disporre del ruolo Utente del tunnel con protezione IAP (roles/iap.tunnelResourceAccessor) nell'istanza per l'identità autenticata con gcloud CLI.

Creare un certificato con OpenSSL

Per un ambiente di produzione, crea una richiesta di firma del certificato (CSR). Scopri di più leggendo l'esempio per generare un CSR. Fornisci la CSR alla tua autorità di certificazione (CA) in modo che possa creare un certificato per te. Utilizza il certificato fornito dalla tua CA nelle sezioni successive.

A titolo esemplificativo, puoi generare un certificato autofirmato con la chiave di firma ospitata in Cloud KMS. A tale scopo, OpenSSL ti consente di utilizzare gli URI PKCS #11 anziché un percorso normale, identificando la chiave tramite l'etichetta (per le chiavi Cloud KMS, l'etichetta è il nome della chiave CryptoKey).

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

Sostituisci quanto segue:

  • CERTIFICATE_NAME: un nome per il certificato.
  • DIGEST_FLAG: l'algoritmo di hashing utilizzato dalla chiave di firma asimmetrica. Utilizza -sha256, -sha384 o -sha512 a seconda della chiave.
  • PKCS_KEY_TYPE: il tipo di identificatore utilizzato per identificare la chiave. Per utilizzare la versione più recente della chiave, utilizza pkcs11:object con il nome della chiave. Per utilizzare una versione della chiave specifica, utilizza pkcs11:id con l'ID risorsa completo della versione della chiave.
  • KEY_IDENTIFIER: un identificatore per la chiave. Se utilizzi pkcs11:object, utilizza il nome della chiave, ad esempio NGINX_KEY. Se utilizzi pkcs11:id, utilizza l'ID risorsa completo della chiave o della versione della chiave, ad esempio projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/NGINX_KEY/cryptoKeyVersions/KEY_VERSION.
  • CA_CERT: il percorso in cui vuoi salvare il file del certificato.

Se il comando non va a buon fine, è possibile che PKCS11_MODULE_PATH sia stato impostato in modo errato o che tu non disponga delle autorizzazioni corrette per utilizzare la chiave di firma Cloud KMS.

A questo punto dovresti avere un certificato simile al seguente:

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

Installa il certificato per NGINX

Esegui i seguenti comandi per creare una posizione in cui inserire il tuo certificato pubblico:

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

Configurare l'ambiente per l'utilizzo della libreria PKCS #11

Le sezioni successive descrivono i passaggi necessari per preparare e testare l'ambiente.

Prepara le configurazioni della libreria per NGINX

Consenti a NGINX di registrare le operazioni del motore PKCS #11 con la biblioteca con quanto segue:

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

Crea un file di configurazione della libreria vuoto con le autorizzazioni appropriate per NGINX.

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

Modifica il file di configurazione vuoto e aggiungi la configurazione necessaria come mostrato nel seguente snippet:

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

Testa la configurazione di OpenSSL

Esegui questo comando:

openssl engine -tt -c -v pkcs11

Dovresti vedere un output simile al seguente:

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

Configurare NGINX per l'utilizzo di Cloud HSM

Consenti il trasferimento TLS modificando alcuni file NGINX. Innanzitutto, modifica il file/etc/nginx/nginx.conf in due punti per aggiungere alcune direttive per configurare NGINX in modo che utilizzi PKCS #11.

Dopo il blocco event e prima del blocco http, aggiungi le seguenti direttive:

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

Nello stesso file /etc/nginx/nginx.conf, configura le direttive SSL per utilizzare il tuo certificato e la relativa chiave privata in Cloud HSM. Nel blocco http, aggiungi i seguenti attributi:

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.

Il file /etc/nginx/nginx.conf dovrebbe avere il seguente aspetto:

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;

        #...
        #...

}

Configura NGINX per l'ascolto del traffico TLS

Modifica il file /etc/nginx/sites-enabled/default per ascoltare il traffico TLS. Rimuovi il commento dalla configurazione SSL nel blocco server. La modifica risultante dovrebbe avere l'aspetto seguente:


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

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

        # ...
        # ...
}

Fornisci le variabili di ambiente al servizio NGINX

Esegui questo comando:

sudo systemctl edit nginx.service

Nell'editor visualizzato, aggiungi le seguenti righe e sostituisci LIBPATH con il valore della posizione in cui hai installato libkmsp11.so:

[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"

Dopo aver configurato questi valori, dovrai eseguire il seguente comando per metterli a disposizione:

sudo systemctl daemon-reload

Riavviare NGINX con il trasferimento TLS

Esegui il seguente comando per riavviare NGINX e utilizzare la configurazione aggiornata:

sudo systemctl start nginx

Verifica che NGINX utilizzi il trasferimento TLS al tuo Cloud HSM

Utilizza openssl s_client per testare la connessione al server NGINX eseguendo il seguente comando:

openssl s_client -connect localhost:443

Il client deve completare l'handshake SSL e mettere in pausa. Il cliente è in attesa del tuo input, come mostrato di seguito:

# 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.

Ora i log di controllo dovrebbero mostrare le operazioni relative alla chiave NGINX_KEY. Per visualizzare i log, vai a Cloud Logging nella console Cloud. Nel progetto che hai utilizzato, aggiungi il seguente filtro:

resource.type="cloudkms_cryptokeyversion"

Dopo aver eseguito la query, dovresti vedere le operazioni con chiavi asimmetriche per la chiave NGINX_KEY.

Configurazioni facoltative

Potresti dover creare un bilanciatore del carico di rete passthrough esterno per esporre il server NGINX con un indirizzo IP esterno.

Se devi utilizzare NGINX come proxy inverso con bilanciamento del carico, valuta la possibilità di aggiornare il file di configurazione di NGINX. Scopri di più sulla configurazione di NGINX come proxy inverso leggendo l'articolo HA All-Active per NGINX Plus sulla piattaforma Google Cloud.

Passaggi successivi

Ora hai configurato il server NGINX per utilizzare il trasferimento TLS su Cloud HSM.