使用 Cloud HSM 金鑰搭配 NGINX 使用 TLS 卸載

本指南說明如何設定 NGINX,在 Debian 11 (Bullseye) 上使用 Cloud HSM 金鑰進行 TLS 卸載。您可能需要修改這些指令,才能在 OS 或 Linux 發行版本中運作。

您可以在 kms-solutions GitHub 存放區中,找到以 Terraform 為基礎的本教學課程藍圖版本。

用途

使用 Cloud HSM 金鑰搭配 NGINX 進行 TLS 卸載,有助於滿足下列企業安全需求:

  • 您希望 NGINX 網路伺服器將 TLS 加密編譯作業卸載至 Cloud HSM。
  • 您不希望將憑證的私密金鑰儲存在託管網路應用程式的 Compute Engine 執行個體本機檔案系統中。
  • 您需要符合法規要求,因為公開應用程式的憑證必須受到通過 FIPS 140-2 第 3 級認證的 HSM 保護。
  • 您想使用 NGINX 建立具有 TLS 終止功能的反向 Proxy,保護網頁應用程式。

事前準備

繼續操作前,請先完成「使用 OpenSSL 搭配 Cloud HSM 金鑰」中的步驟。

OpenSSL 設定完成後,請確認已安裝最新版本的 nginx

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

安全性設定建議

請按照下列建議,保護代管 NGINX 的執行個體:

  1. 按照「建立和啟用執行個體的服務帳戶」的操作說明,代管 NGINX。

    1. 指派下列角色:
      • roles/cloudkms.signerVerifier
      • roles/cloudkms.viewer
  2. 請按照下列方式設定機構政策,限制外部 IP 和服務帳戶金鑰的建立。

    • constraints/compute.vmExternalIpAccess
    • constraints/iam.disableServiceAccountKeyCreation
  3. 建立自訂子網路,並啟用私人 Google 存取權

  4. 設定防火牆規則。

  5. 建立 Linux VM,並按照以下步驟進行設定:

    • 選取您先前建立的正確服務帳戶。
    • 選取您先前建立的網路。
      • 為所有防火牆規則新增適當的標籤。
      • 確認子網路的「外部 IP」欄位設為 none
  6. 在執行個體上,授予身分「受 IAP 保護的通道使用者」角色 (roles/iap.tunnelResourceAccessor)。

建立及設定 Cloud HSM 簽署金鑰

接下來的章節會詳細說明建立及設定 Cloud HSM 簽署金鑰的必要步驟。

建立 Cloud HSM 代管的簽署金鑰

在專案中,於先前為 OpenSSL 設定的金鑰環中,建立 Cloud HSM EC-P256-SHA256 簽署金鑰:Google Cloud

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 和 IAP 連線至 VM

使用下列指令,透過 SSH 和 IAP 連線至 VM:

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

如果遇到問題,請確認您是否使用了 --tunnel-through-iap 標記。 此外,請確認您在執行個體上擁有「受 IAP 保護的通道使用者」(roles/iap.tunnelResourceAccessor) 角色,可供透過 gcloud CLI 驗證的身分使用。

使用 OpenSSL 建立憑證

如果是實際工作環境,請建立憑證簽署要求 (CSR)。請參閱範例,進一步瞭解如何產生 CSR。將 CSR 提供給憑證授權單位 (CA),讓他們為您建立憑證。在後續章節中,請使用 CA 提供的憑證。

舉例來說,您可以使用 Cloud HSM 簽署金鑰產生自行簽署的憑證。為此,OpenSSL 可讓您使用 PKCS #11 URI,而非一般路徑,並依標籤識別金鑰 (如果是 Cloud KMS 金鑰,標籤就是 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

更改下列內容:

  • CERTIFICATE_NAME:憑證名稱。
  • DIGEST_FLAG:非對稱簽署金鑰使用的摘要演算法。視金鑰而定,使用 -sha256-sha384-sha512
  • PKCS_KEY_TYPE:用於識別金鑰的 ID 類型。 如要使用最新金鑰版本,請搭配金鑰名稱使用 pkcs11:object。如要使用特定金鑰版本,請搭配金鑰版本的完整資源 ID 使用 pkcs11:id
  • KEY_IDENTIFIER:金鑰的 ID。如果您使用 pkcs11:object,請使用金鑰名稱,例如 NGINX_KEY。如果您使用 pkcs11:id,請使用金鑰或金鑰版本的完整資源 ID,例如 projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/NGINX_KEY/cryptoKeyVersions/KEY_VERSION
  • CA_CERT:您要儲存憑證檔案的路徑。

如果指令失敗,可能是 PKCS11_MODULE_PATH 設定有誤,或是您沒有使用 Cloud KMS 簽署金鑰的正確權限。

現在您應該會看到類似下方的認證:

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

安裝 NGINX 憑證

執行下列指令,建立放置公開認證的位置:

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

設定環境以使用 PKCS #11 程式庫

接下來的章節將詳細說明準備及測試環境所需的步驟。

準備 NGINX 的程式庫設定

允許 NGINX 使用下列程式庫記錄 PKCS #11 引擎作業:

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

建立空白的程式庫設定檔,並為 NGINX 設定適當權限。

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

編輯空白設定檔,並新增所需設定,如以下程式碼片段所示:

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

測試 OpenSSL 設定

執行下列指令:

openssl engine -tt -c -v pkcs11

輸出結果應該會類似下列內容:

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

設定 NGINX 使用 Cloud HSM

編輯幾個 NGINX 檔案,允許 TLS 卸載。首先,請在兩個位置編輯 /etc/nginx/nginx.conf 檔案,新增幾個指令來設定 NGINX 使用 PKCS #11。

event 區塊之後,但在 http 區塊之前,新增下列指令:

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

在同一個 /etc/nginx/nginx.conf 檔案中,設定 SSL 指令,在 Cloud HSM 中使用您的憑證和私密金鑰。在 http 區塊中新增下列屬性:

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.

您的 /etc/nginx/nginx.conf 檔案應如下所示:

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 監聽 TLS 流量

編輯 /etc/nginx/sites-enabled/default 檔案,監聽 TLS 流量。 取消 server 區塊中的 SSL 設定註解。 變更結果應如下列範例所示:


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

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

        # ...
        # ...
}

為 NGINX 服務提供環境變數

執行下列指令:

sudo systemctl edit nginx.service

在產生的編輯器中新增下列幾行,並將 LIBPATH 替換為安裝 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"

設定這些值後,您需要執行下列指令,才能使用這些值:

sudo systemctl daemon-reload

重新啟動 NGINX (TLS 卸載)

執行下列指令,重新啟動 NGINX 並使用更新後的設定:

sudo systemctl start nginx

測試 NGINX 是否使用 TLS 卸載至 Cloud HSM

使用 openssl s_client 執行下列指令,測試與 NGINX 伺服器的連線:

openssl s_client -connect localhost:443

用戶端完成 SSL 握手程序,並等待您的輸入內容:

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

稽核記錄現在應該會顯示對 NGINX_KEY 金鑰執行的作業。 如要查看記錄,請前往 Google Cloud 控制台中的 Cloud Logging。 在您使用的專案中,新增下列篩選器:

resource.type="cloudkms_cryptokeyversion"

執行查詢後,您應該會看到對 NGINX_KEY 金鑰執行的非對稱金鑰作業。

選用設定

您可能需要建立外部直通式網路負載平衡器,透過外部 IP 公開 NGINX 伺服器。

如要將 NGINX 做為反向 Proxy 使用,並進行負載平衡,請考慮更新 NGINX 設定檔。如要進一步瞭解如何將 NGINX 設定為反向 Proxy,請參閱平台上的「All-Active HA for NGINX Plus」 Google Cloud

後續步驟

您已將 NGINX 伺服器設為使用 TLS 卸載功能,將流量導向 Cloud HSM。