NGINX での TLS オフロードに Cloud HSM 鍵を使用する

このガイドでは、Debian 11(Bullseye)での TLS オフロードに Cloud HSM 鍵を使用するように NGINX を設定する手順について説明します。OS または Linux ディストリビューションで動作するように、これらのコマンドの変更が必要になる場合があります。

このチュートリアルの Terraform ベースのブループリント バージョンは、kms-solutions GitHub リポジトリにあります。

ユースケース

TLS オフロード用に NGINX で Cloud HSM 鍵を使用すると、次のエンタープライズ セキュリティのニーズに対応できます。

  • NGINX ウェブサーバーで TLS 暗号オペレーションを Cloud HSM にオフロードする。
  • 証明書の秘密鍵を、ウェブ アプリケーションをホストしている Compute Engine インスタンスのローカル ファイル システムに保存することを回避する必要がある場合。
  • 一般向けのアプリケーションが、FIPS 140-2 レベル 3 認定取得済みの HSM で証明書を保護するために、規制要件を満たす必要がある場合。
  • ウェブ アプリケーションを保護するために、NGINX を使用して TLS 終端型のリバース プロキシを作成する場合。

始める前に

続行する前に、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. ID にインスタンスに対する IAP で保護されたトンネル ユーザー(roles/iap.tunnelResourceAccessor)のロールを付与します。

Cloud KMS でホストされる署名鍵を作成して構成する

以降のセクションでは、Cloud KMS でホストされる署名鍵を作成して構成するために必要な手順について詳しく説明します。

Cloud KMS でホストされる署名鍵を作成する

OpenSSL 用に構成済みのキーリングで、Google Cloud プロジェクトの 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 を使用して VM に SSH 接続する

次のコマンドで、IAP を使用して VM に SSH 接続します。

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

問題が発生した場合は、--tunnel-through-iap フラグを使用していることを確認してください。また、gcloud CLI で認証された ID のインスタンスに 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: 鍵の識別に使用される識別子のタイプ。最新の鍵バージョンを使用するには、鍵の名前とともに pkcs11:object を使用します。特定の鍵バージョンを使用するには、鍵バージョンの完全なリソース ID とともに pkcs11:id を使用します。
  • KEY_IDENTIFIER: 鍵の識別子。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

Cloud HSM を使用するように NGINX を構成する

いくつかの NGINX ファイルを編集して TLS オフロードを許可します。まず、/etc/nginx/nginx.conf ファイルを 2 か所で編集し、NGINX が PKCS #11 を使用するように構成するためのディレクティブをいくつか追加します。

event ブロックの後、http ブロックの前に、次のディレクティブを追加します。

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

同じ /etc/nginx/nginx.conf ファイルで、Cloud HSM で証明書とその秘密鍵を使用するように SSL ディレクティブを構成します。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;

        #...
        #...

}

TLS トラフィックをリッスンするように NGINX を構成する

TLS トラフィックをリッスンするように /etc/nginx/sites-enabled/default ファイルを編集します。 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

表示されたエディタで、次の行を追加し、LIBPATHlibkmsp11.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 オフロードで NGINX を再起動する

次のコマンドを実行して、NGINX が再起動して更新された構成を使用するようにします。

sudo systemctl start nginx

NGINX で TLS を使用した Cloud HSM へのオフロードをテストする

openssl s_client を使用して、次のコマンドを実行して NGINX サーバーへの接続をテストします。

openssl s_client -connect localhost:443

クライアントは SSL handshake を完了して一時停止します。クライアントは、次のようにお客様からの入力を待っています。

# 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 コンソールで Cloud Logging に移動します。 使用しているプロジェクトで、次のフィルタを追加します。

resource.type="cloudkms_cryptokeyversion"

クエリを実行すると、NGINX_KEY 鍵に対する非対称鍵オペレーションが表示されます。

オプションの構成

NGINX サーバーを外部 IP で公開するには、外部パススルー ネットワーク ロードバランサの作成が必要になる場合があります。

負荷分散でリバース プロキシとして NGINX を使用する必要がある場合は、NGINX 構成ファイルの更新を検討してください。NGINX をリバース プロキシとして構成する方法については、Google Cloud Platform での NGINX Plus のすべてのアクティブ HA をご覧ください。

次のステップ

Cloud HSM への TLS オフロードを使用するように NGINX サーバーが構成されました。