使用 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 KMS 代管的簽署金鑰

接下來幾節將詳細說明如何建立及設定 Cloud KMS 代管的簽署金鑰。

建立由 Cloud KMS 代管的簽署金鑰

在Google Cloud 專案中,使用先前為 OpenSSL 設定的金鑰環,建立 Cloud KMS 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"

使用 IAP 透過 SSH 存取 VM

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

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

如果遇到問題,請確認您已使用 --tunnel-through-iap 標記。此外,請確認您已為透過 gcloud CLI 驗證的身分識別資訊,在執行個體上設定「受 IAP 保護的通道使用者」(roles/iap.tunnelResourceAccessor) 角色。

使用 OpenSSL 建立憑證

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

您可以使用 Cloud KMS 代管的簽署金鑰,產生自行簽署的憑證,以供示範用途。為此,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 搭配金鑰名稱。如要使用特定金鑰版本,請使用 pkcs11:id 搭配金鑰版本的完整資源 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

使用 TLS Offloading 重新啟動 NGINX

執行下列指令,讓 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 索引鍵的作業。如要查看記錄,請在雲端控制台中前往 Cloud Logging。在您使用的專案中,新增下列篩選器:

resource.type="cloudkms_cryptokeyversion"

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

選用設定

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

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

後續步驟

您現在已將 NGINX 伺服器設為使用 TLS 卸載至 Cloud HSM。