Azure Key Vault Managed HSM を使用してキーレス TLS 終端を構成する

Azure Application Gatewayは、秘密鍵がAzure Key Vault管理HSMに残る証明書を使用することでTLSを終了できます。 この方法は秘密鍵の内容をHSM内に保持しつつ、アプリケーションゲートウェイがTLSのオフロードやバックエンドサーバーへの再暗号化を処理できるようにします。

概念的な背景については、「Azure Application Gateway および Azure Key Vault Managed HSM のキーレスTLSとは何か?」をご覧ください。

このチュートリアルでは、以下の内容を学習します。

  • Azure Key Vault Managed HSM instanceをプロビジョニングおよび初期化する
  • マネージドアイデンティティを作成し、HSMロールを割り当てます
  • HSM 秘密鍵で保護された証明書を生成する
  • HSM によって保護された証明書を使用するように Application Gateway を構成する
  • 診断機能でキーレスTLS操作を監視

すでにApplication Gateway、Managed HSM、OpenSSL 3.0.13を動作させるLinux VMを持っている場合は、プロビジョニングのステップを省略して証明書生成セクションから始めることができます。

Note

この記事では、ほとんどのタスクにAzure CLIを使用し、Azureポータルのステップはポータルでの操作が最も直接的な方法である場合にのみ使用しています。 ポータルファーストのクイックスタートについては、「TLS 終端付きアプリケーション ゲートウェイの作成」を参照してください。

Prerequisites

始める前に、以下のことを確認してください:

セットアップ時には以下の役割も必要です:

  • Azure Key Vault マネージド HSM の初期設定向けマネージド HSM Crypto Officer
  • 証明書操作用のマネージド HSM Crypto User
  • ロールの割り当てに関する所有者またはユーザー アクセス管理者

Important

この記事の例では、<your-resource-group-name>のようなプレースホルダー値が使われています。 それらを自分の環境に合った値に置き換えてください。

Provision Azure Key Vault Managed HSM

リソースグループを作成し、Azure Key Vault管理型HSMインスタンスをプロビジョニングします。

az group create --name $RESOURCE_GROUP --location $LOCATION

export oid=$(az ad signed-in-user show --query id -o tsv)

az keyvault create --hsm-name $MHSM_NAME --resource-group $RESOURCE_GROUP --location $LOCATION --administrators $oid --retention-days 7

3つのセキュリティドメイン証明書を作成し、セキュリティドメインを初期化します。

openssl req -newkey rsa:2048 -nodes -keyout cert_0.key -x509 -days 365 -out cert_0.cer -subj "/C=US/ST=WA/L=Redmond/O=MyCompany/CN=myapp.example.com"
openssl req -newkey rsa:2048 -nodes -keyout cert_1.key -x509 -days 365 -out cert_1.cer -subj "/C=US/ST=WA/L=Redmond/O=MyCompany/CN=myapp.example.com"
openssl req -newkey rsa:2048 -nodes -keyout cert_2.key -x509 -days 365 -out cert_2.cer -subj "/C=US/ST=WA/L=Redmond/O=MyCompany/CN=myapp.example.com"

az keyvault security-domain download --hsm-name $MHSM_NAME --sd-wrapping-keys ./cert_0.cer ./cert_1.cer ./cert_2.cer --sd-quorum 2 --security-domain-file $SECURITY_DOMAIN

Azure Cloud Shellを使っている場合は、生成されたファイルをダウンロードできるようにパッケージ化してください。

tar -czvf mhsm.tar.gz ./*

HSMアクセスを許可し、鍵を作成する

自分でマネージドHSM暗号ユーザーの役割を割り当てて、鍵の作成と管理を行ってください。

az keyvault role assignment create --hsm-name $MHSM_NAME --role "Managed HSM Crypto User" --assignee-object-id $oid --assignee-principal-type MSI --scope /keys

Azure CLIで使うIDがHSMキーにアクセスできるか確認してください。

Tip

もしアイデンティティが単一のキーにしかアクセスしないようにする場合は、ロールの割り当てを /keys ではなく /keys/<key-name> に割り当てます。

az keyvault key list --hsm-name $MHSM_NAME

TLS操作に署名するHSMキーを作成します。

az keyvault key create --hsm-name $MHSM_NAME --name $PRIVATE_KEY --ops wrapKey unwrapKey sign --kty RSA-HSM --size 2048

証明書操作のためにLinux VMを準備します

UbuntuのVMをプロビジョニングし、システム割り当てのマネージドIDを有効にします。 ポータルの手順については、「Azure ポータルで Linux 仮想マシンを作成」および「既存の VM でシステム割り当てマネージド ID を有効にする」をご覧ください。

アイデンティティを有効にした後、オブジェクトIDを記録し、VMにHSMへのアクセスを許可します。

export smioid="<system-managed-identity-object-id>"

az keyvault role assignment create --hsm-name $MHSM_NAME --role "Managed HSM Crypto User" --assignee-object-id $smioid --assignee-principal-type MSI --scope /keys

TLSオフロードライブラリをVMにコピーし、OpenSSLに必要なビルド依存関係をインストールします。

chmod 755 ~/appgw_akv.so

sudo apt update && sudo apt upgrade -y
sudo apt install build-essential zlib1g-dev -y

OpenSSLを構築し、TLSオフロードライブラリを設定します

OpenSSL 3.0.13を構築し、TLSオフロードライブラリをインストールし、エンジンに必要な環境変数を設定してください。

cd /usr/local/src
sudo wget https://www.openssl.org/source/openssl-3.0.13.tar.gz --no-check-certificate
sudo tar -xvzf openssl-3.0.13.tar.gz
cd openssl-3.0.13

sudo ./config --prefix=/opt/openssl-3.0.13 --openssldir=/opt/openssl-3.0.13 shared zlib
sudo make -j$(nproc)
sudo make install

エンジンのバイナリをOpenSSLのエンジンディレクトリにコピーし、公開済みのチェックサムがある場合は、そのチェックサムを照合してください。

sudo cp ~/appgw_akv.so /opt/openssl-3.0.13/lib64/engines-3/

export LD_LIBRARY_PATH=/opt/openssl-3.0.13/lib64:$LD_LIBRARY_PATH
export OPENSSL_ENGINES=/opt/openssl-3.0.13/lib64/engines-3
export PATH=/opt/openssl-3.0.13/bin:$PATH

openssl engine -t -c -vvvv e_akv
openssl version

Warning

このライブラリバージョンにはOpenSSL 3.0.13が必要です。 それ以前のバージョンや後のバージョンではエンジンが正しく積み込まれないことがあります。

HSM秘密鍵を使用した自己署名証明書を作成し、その証明書をbase64エンコードして後でApplication Gatewayで使用する。

export OPENSSL_CERT_DAYS=365
export OPENSSL_CERT_SUBJ=/CN=contoso.com

cd ~

openssl req -new -x509 -engine e_akv -keyform engine -key managedHsm:$MHSM_NAME:$PRIVATE_KEY -out cert_rsa.pem -subj $OPENSSL_CERT_SUBJ -days $OPENSSL_CERT_DAYS
base64 -w0 cert_rsa.pem > base64.txt

Important

証明書ファイルとbase64の出力は安全な場所に保管してください。 証明書はアプリケーションゲートウェイの設定を更新するために使用されますが、秘密鍵はマネージドHSMに残ります。

アプリケーションゲートウェイの設定

既存のアプリケーションゲートウェイを使用するか、新しいテストデプロイを作成すること。 以下の例は、Container Apps バックエンドを含むオプションのテスト環境を示しています。

テスト バックエンドと Application Gateway を作成する

ネットワーク、コンテナアプリ環境、そしてサンプルのバックエンドアプリケーションを作成します。

az network vnet create --name $VNET_NAME --resource-group $RESOURCE_GROUP --location $LOCATION --address-prefix $ADDRESS_PREFIX --subnet-name $APPGW_SUBNET --subnet-prefix $APPGW_SUBNET_PREFIX
az network vnet subnet create --name $BACKEND_SUBNET --resource-group $RESOURCE_GROUP --vnet-name $VNET_NAME --address-prefix $BACKEND_SUBNET_PREFIX

az containerapp env create --name $ACA_ENV --resource-group $RESOURCE_GROUP --location $LOCATION --logs-destination none
az containerapp create --name $ACA_NAME --resource-group $RESOURCE_GROUP --environment $ACA_ENV --image nginxdemos/hello --target-port 80 --ingress external

ACA_URL=$(az containerapp show --name $ACA_NAME --resource-group $RESOURCE_GROUP --query properties.configuration.ingress.fqdn --output tsv)

パブリックIP、自己署名証明書、アプリケーションゲートウェイを作成します。

az network public-ip create --resource-group $RESOURCE_GROUP --name $APPGW_PIP_NAME --sku Standard

openssl req -x509 -newkey rsa:2048 -keyout mykey.key -out mycert.crt -days 365 -nodes -subj "/C=US/ST=WA/L=Redmond/O=MyCompany/CN=myapp.example.com"
openssl pkcs12 -export -out $SSCERT_FILE -inkey mykey.key -in mycert.crt -passout pass:$SSCERT_PASSWD

az network application-gateway create --name $APPGW_NAME --location $LOCATION --resource-group $RESOURCE_GROUP --sku Standard_v2 --capacity 2 --public-ip-address $APPGW_PIP_NAME --vnet-name $VNET_NAME --subnet $APPGW_SUBNET --priority 100

証明書、リスナー、バックエンドプール、ルーティングルールを設定してください。

az network application-gateway ssl-cert create --resource-group $RESOURCE_GROUP --gateway-name $APPGW_NAME --name $SSCERT_NAME --cert-file $SSCERT_FILE --cert-password $SSCERT_PASSWD
az network application-gateway frontend-port create --resource-group $RESOURCE_GROUP --gateway-name $APPGW_NAME --name $HTTPS_PORT --port 443
az network application-gateway http-listener create --resource-group $RESOURCE_GROUP --gateway-name $APPGW_NAME --name $LISTENER --frontend-ip "appGatewayFrontendIP" --frontend-port $HTTPS_PORT --ssl-cert $SSCERT_NAME

az network application-gateway address-pool create --gateway-name $APPGW_NAME --resource-group $RESOURCE_GROUP --name $BACKEND_POOL --servers $ACA_URL
az network application-gateway http-settings create --gateway-name $APPGW_NAME --resource-group $RESOURCE_GROUP --name $HTTPS_SETTING_NAME --port 443 --protocol Https --cookie-based-affinity Disabled --host-name-from-backend-pool true
az network application-gateway probe create --gateway-name $APPGW_NAME --resource-group $RESOURCE_GROUP --name $PROBE_NAME --protocol Https --path "/" --interval 30 --timeout 30 --host-name-from-http-settings true
az network application-gateway http-settings update --gateway-name $APPGW_NAME --resource-group $RESOURCE_GROUP --name $HTTPS_SETTING_NAME --probe $PROBE_NAME --port 443 --protocol Https --host-name-from-backend-pool true

RULE_NAME=$(az network application-gateway rule list --gateway-name $APPGW_NAME --resource-group $RESOURCE_GROUP --query "[0].name" --output tsv)
az network application-gateway rule update --gateway-name $APPGW_NAME --resource-group $RESOURCE_GROUP --name $RULE_NAME --http-listener $LISTENER --http-settings $HTTPS_SETTING_NAME --address-pool $BACKEND_POOL --priority 100

キーレスTLSに移行する前に、デプロイメントをテストしてください。

APPGW_PUBLIC_IP=$(az network public-ip show --resource-group $RESOURCE_GROUP --name $APPGW_PIP_NAME --query ipAddress --output tsv)

echo "Container App URL: $ACA_URL"
echo "Application Gateway public IP: $APPGW_PUBLIC_IP"

Tip

もしアプリケーション ゲートウェイがネットワークからアクセスできない場合は、ゲートウェイ サブネットへの受信 HTTPS トラフィックをブロックする NSG ルールを確認してください。

マルチサイトリスナーの設定

ホスト名に基づいてリクエストをルーティングするには、2 番目のリスナーとルーティング ルールを作成してください。

az network application-gateway http-listener create --resource-group "$RESOURCE_GROUP" --gateway-name "$APPGW_NAME" --name "$MULTISITE_LISTENER_NAME" --frontend-ip "appGatewayFrontendIP" --frontend-port "$HTTPS_PORT" --ssl-cert "$SSCERT_NAME" --host-name "$MULTISITE_HOSTNAME"

az network application-gateway rule create --resource-group "$RESOURCE_GROUP" --gateway-name "$APPGW_NAME" --name "rule2" --rule-type Basic --http-listener "$MULTISITE_LISTENER_NAME" --address-pool "$BACKEND_POOL" --http-settings "$HTTPS_SETTING_NAME" --priority 50

curl -vk "https://<application-gateway-public-ip>/" -H "Host: <hostname>"

Note

マルチサイトリスナーは Host ヘッダーを使ってリスナーを選択します。 本番環境では、各ホスト名のDNSレコードをアプリケーションゲートウェイのパブリックIPアドレスに割り当てます。

Caution

この段階では、Application Gateway は、引き続き .pfx ファイルからローカル証明書を使用します。 次のセクションでは、その証明書を マネージド HSM によって保護された証明書に置き換えます。

キーレスTLSの設定

アプリケーションゲートウェイ用にユーザー割り当てのマネージドアイデンティティを作成し、マネージドHSMキーへのアクセスを許可します。

az identity create --name $MI_NAME --resource-group $RESOURCE_GROUP --location $LOCATION

export mioid=$(az identity show --name $MI_NAME --resource-group $RESOURCE_GROUP --query principalId --output tsv)

az keyvault role assignment create --hsm-name $MHSM_NAME --role "Managed HSM Crypto User" --assignee-object-id $mioid --assignee-principal-type MSI --scope /keys

Tip

Application Gateway の ID が 1 つのキーのみにアクセスする必要がある場合は、ロールの割り当てのスコープを /keys/<key-name> に設定します。

ユーザー割り当てのマネージド ID をアプリケーション ゲートウェイに関連付け、Managed HSM への認証を可能にします。

export identityId=$(az identity show --name $MI_NAME --resource-group $RESOURCE_GROUP --query id -o tsv)

az network application-gateway update --name $APPGW_NAME --resource-group $RESOURCE_GROUP --set identity='{"type":"UserAssigned","userAssignedIdentities":{"'"$identityId"'":{}}}'
az network application-gateway show --name $APPGW_NAME --resource-group $RESOURCE_GROUP --query identity

sslCertificatesにマネージドHSMへの新しい参照を追加します。

# Add reference to the HSM-backed key and the base64-encoded public certificate
az network application-gateway ssl-cert create \
--resource-group $RESOURCE_GROUP \
--gateway-name $APPGW_NAME \
--name mHSM-Key001 \
--hsm keyId="https://<HSM NAME>.managedhsm.azure.net/keys/<key-name>" publicCertData="Q......................=="

管理されているHSM構成を参照して新しいリスナーを作成します。

# Associate certificate to a new listener
az network application-gateway http-listener create \
--resource-group $RESOURCE_GROUP \
--gateway-name $APPGW_NAME \
--name mhsm-listener \
--frontend-ip appGwPublicFrontendIpIPv4 \
--frontend-port port_443 \
--ssl-cert mHSM-Key001 \
--host-name contoso.com

展開完了後、アプリケーションゲートウェイの設定で sslCertificates アレイに新しいSSL証明書名が表示されているか確認してください。

Note

キーレスTLS設定では、プライベートキーはAzure Key VaultのマネージドHSMに保管され、Application Gatewayがハンドシェイク中にTLS署名処理を行います。

キーレスTLS操作の監視

オプション:管理型HSMでアプリケーションゲートウェイによって生成された暗号操作を確認するための診断を有効にしてください。

  1. AzureポータルでマネージドHSMリソースを開きます。
  2. [監視] で [ 診断設定 ] を選択 します。
  3. AuditEventカテゴリをLog Analyticsワークスペースに送信する診断設定を追加してください。
  4. 設定を保存して数分待ち、ログが表示されるまで待ちます。

トラフィックを生成し、ログをクエリします。

for i in {1..10}; do
    curl -k --resolve contoso.com:443:<appgw-frontend-ip-address> "https://contoso.com"
done
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where Category == "AuditEvent"
| where OperationName == "KeySign"
| project TimeGenerated, OperationName, CallerIPAddress, identity_claim_appid_g, properties_s
| order by TimeGenerated desc

Tip

クエリ結果を使って、TLSハンドシェイク中にApplication GatewayがManaged HSMを呼び出して署名操作を行っているか確認してください。

Troubleshooting

無効なリスナーの動作

無効なリスナーは以下の状況で発生する可能性があります。

  • Application GatewayはRBAC権限の誤りによりマネージドHSMに認証できません。
  • Application Gateway は、参照されたキーが削除されたため、TLS ハンドシェイクの情報を復号できません。

Limitations

  • リスナーはTLS 1.2以降のバージョンを使用しなければなりません。
  • 対応するSSLポリシーは AppGwSslPolicy20220101、 AppGwSslPolicy20220101S、 CustomV2に限定されています。
  • スループットと容量の計画については、Azure Key Vault Managed HSM スケーリングガイダンスと Azure Key Vault Managed HSM サービス制限を確認してください。
  • マネージドHSMオブジェクト上の証明書の置換は、最初の更新時に適用されない場合があります。 この状況が発生した場合は、タグの更新など Application Gateway にもう一度小さな変更を加えるか、マネージド HSM 参照を別々の操作で削除してから再追加してください。
  • 以下のシナリオはサポートされていません:
    • Application Gateway イングレス コントローラー (AGIC)
    • WebSockets
    • L4 TCP/TLSプロキシ
    • FIPS モード
    • EC キー

次のステップ

このセットアップを拡張するには、リスナー固有のSSLポリシーガイダンスとアプリケーションゲートウェイの診断を確認してください。