Azure Key Vault 認定資格証を使用して Spring Boot で HTTPS を有効にする
このチュートリアルでは、Azure Key Vault と Azure リソース用マネージド ID を使用して、TLS/SSL 証明書付きの Spring Boot (Azure Spring Apps を含む) アプリをセキュリティで保護する方法について説明します。
運用環境グレードの Spring Boot アプリケーションでは、クラウドかオンプレミスかに関わらず、標準の TLS プロトコルを使用したネットワーク トラフィックに対してエンドツーエンドの暗号化が必要です。 ほとんどの TLS/SSL 証明書は、パブリック ルート証明機関 (CA) から検出可能です。 ただし、この検出が不可能な場合もあります。 証明書が検出されない場合に備え、アプリにはこのような証明書を読み込んで、受信ネットワーク接続にその証明書を提示し、送信ネットワーク接続からそれらを受け入れる方法が準備されている必要があります。
Spring Boot アプリは通常、証明書をインストールすることによって TLS を有効にします。 証明書は、Spring Boot アプリを実行している JVM のローカル キー ストアにインストールされます。 Azure 上の Spring では、認定資格証はローカルにインストールされません。 代わりに、Microsoft Azure の Spring 統合では、Azure Key Vault と Azure リソース用マネージド ID の支援を活用して、TLS を安全かつ円滑に有効にする方法を提供します。
重要
現在、Spring Cloud Azure Certificate Starter バージョン 4.x 以降では TLS/mTLS はサポートされていません。Key Vault 認定資格証クライアントのみを自動構成します。 そのため、TLS/mTLS を使用する場合は、バージョン 4.x に移行できません。
前提条件
Azure サブスクリプション - 無料アカウントを作成します。
バージョン 11 を含む、サポートされている Java Development Kit (JDK)。
Apache Maven バージョン 3.0 以降。
cURL または機能をテストするための類似の HTTP ユーティリティ。
Azure virtual machine (VM) インスタンス。 保持していない場合は、az vm create コマンドと UbuntuServer から提供された Ubuntu イメージを使用して、システムが割り当てたマネージド ID が有効になっている VM インスタンスを作成します。
Contributor
ロールをシステムが割り当てたマネージド ID に付与し、アクセスscope
をサブスクリプションに設定します。Azure Key Vault インスタンス。 お持ちでない場合は、「クイック スタート: Azure CLI を使用したキー コンテナーの作成」を参照してください。
Spring Boot アプリケーション。 ない場合は、Spring Initializr で Maven プロジェクトを作成します。 必ず、[Maven プロジェクト] を選択し、[依存関係] に [Spring Web] 依存関係を追加してから、Java のバージョン 8 以降を選択してください。
重要
この記事の手順を完了するには、Spring Boot 2.5 以降のバージョンが必要です。
自己署名 TLS/SSL 認定資格証の設定
このチュートリアルの手順は、Azure Key Vault に直接格納されているすべての TLS/SSL 証明書 (自己署名を含む) に適用されます。 自己署名証明書は、運用環境での使用に適しているわけではありませんが、アプリケーションの開発やテスト段階で役立ちます。
このチュートリアルでは自己署名証明書を使用します。 認定資格証の設定にちては、「クイック スタート: Azure Portal を使用して Azure Key Vault から認定資格証を取得する」を参照してください。
Note
認定資格証を設定したら、「Key Vault アクセス ポリシーを割り当てる」の手順を実行して、VM に Key Vault へのアクセス権を付与します。
TLS/SSL 認定資格証を使用したセキュリティで保護された接続
これで、VM と Key Vault インスタンスが作成され、Key Vault へのアクセス権が VM に付与されました。 次のセクションでは、Spring Boot アプリケーションで Azure Key Vault から TLS/SSL 認定資格証を介して安全に接続する方法について説明します。 このチュートリアルでは、次の 2 つのシナリオについてデモします。
- セキュリティで保護された受信接続を伴う Spring Boot アプリケーションを実行する
- セキュリティで保護された送信接続を伴う Spring Boot アプリケーションを実行する
ヒント
次の手順では、コードが実行可能ファイルにパッケージ化され、VM にアップロードされます。 VM に OpenJDK をインストールすることを忘れないでください。
セキュリティで保護された受信接続を伴う Spring Boot アプリケーションを実行する
受信接続の TLS/SSL 認定資格証が Azure Key Vault から取得される場合は、次の手順を実行してアプリケーションを構成します。
pom.xml ファイルに次の依存関係を追加します。
<dependency> <groupId>com.azure.spring</groupId> <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId> <version>3.14.0</version> </dependency>
application.properties 構成ファイルで Key Vault 資格情報を構成します。
server.ssl.key-alias=<the name of the certificate in Azure Key Vault to use> server.ssl.key-store-type=AzureKeyVault server.ssl.trust-store-type=AzureKeyVault server.port=8443 azure.keyvault.uri=<the URI of the Azure Key Vault to use>
これらの値により、このチュートリアルの冒頭で説明したように、Spring Boot アプリは TLS/SSL 証明書の '読み込み' アクションを実行できるようになります。 次の表に、使用可能なプロパティ値を示します。
プロパティ 説明 server.ssl.key-alias
az keyvault certificate create
に渡された--name
引数の値。server.ssl.key-store-type
AzureKeyVault
である必要があります。server.ssl.trust-store-type
AzureKeyVault
である必要があります。server.port
HTTPS 接続をリッスンするローカル TCP ポート。 azure.keyvault.uri
az keyvault create
から戻ってきた JSON のvaultUri
プロパティ。 この値を環境変数に保存しました。Key Vault 固有の唯一のプロパティは
azure.keyvault.uri
です。 このアプリは、システム割り当てマネージド ID に対して、Key Vault へのアクセス許可が付与されている VM で実行されています。 そのため、アプリにもアクセス権が付与されています。これらの変更により、Spring Boot アプリは TLS/SSL 証明書を読み込むことができます。 次の手順では、チュートリアルの冒頭で説明したように、アプリが TLS/SSL 認定資格証に対して受け入れアクションを実行できるようにします。
次の内容が含まれるようにスタートアップ クラス ファイルを編集します。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class SsltestApplication { public static void main(String[] args) { SpringApplication.run(SsltestApplication.class, args); } @GetMapping(value = "/ssl-test") public String inbound(){ return "Inbound TLS is working!!"; } @GetMapping(value = "/exit") public void exit() { System.exit(0); } }
認証されていない REST GET 呼び出し内から
System.exit(0)
を呼び出すことは、デモンストレーションのみを目的としています。 実際のアプリケーションでは、System.exit(0)
を使用しないでください。このコードは、このチュートリアルの冒頭で説明した '提示' アクションを示しています。 次の一覧で、このコードの詳細について説明します。
- Spring Initializr によって生成される
SsltestApplication
クラスに@RestController
注釈が付けられました。 @GetMapping
の注釈がつけられたメソッドがあり、HTTP 呼び出し用のvalue
が使用されています。inbound
メソッドは、ブラウザーが/ssl-test
パスに対して HTTPS 要求を行ったときに、単にメッセージを返します。inbound
メソッドは、サーバーが TLS/SSL 証明書をブラウザーに提示する方法を示しています。exit
メソッドが呼び出されると、JVM が終了します。 このメソッドは、このチュートリアルのコンテキストでサンプルを簡単に実行できるようにするための便宜的なものです。
- Spring Initializr によって生成される
次のコマンドを実行してコードをコンパイルし、実行可能な JAR ファイルにパッケージ化します。
mvn clean package
<your-resource-group-name>
で作成されたネットワーク セキュリティ グループが、IP アドレスからポート 22 と 8443 の受信トラフィックを許可していることを確認します。 受信トラフィックを許可するネットワーク セキュリティ グループの規則を構成する方法については、「ネットワーク セキュリティ グループの作成、変更、削除」の「セキュリティ規則を操作する」セクションを参照してください。実行可能な JAR ファイルを VM に配置します。
cd target sftp azureuser@<your VM public IP address> put *.jar
Spring Boot アプリをビルドして、VM にアップロードしたので、次の手順を実行して、VMを実行し、
curl
を使用して REST エンドポイントを呼び出します。SSH を使用して VM に接続し、実行可能な JAR を実行します。
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
新しい Bash シェルを開き、次のコマンドを実行して、サーバーが TLS/SSL 証明書を提示していることを確認します。
curl --insecure https://<your VM public IP address>:8443/ssl-test
exit
パスを呼び出して、サーバーを強制終了し、ネットワーク ソケットを閉じます。curl --insecure https://<your VM public IP address>:8443/exit
これで、自己署名 TLS/SSL 認定資格証を使用して読み込みと提示アクションが確認できました。次は、アプリにいくつかの簡単な変更を加えて、受け入れアクションも確認します。
セキュリティで保護された送信接続を伴う Spring Boot アプリケーションを実行する
このセクションでは、送信接続用の TLS/SSL 認定資格証を Azure Key Vault から取得するように、前のセクションのコードを変更します。 その結果、Azure Key Vault からの '読み込み'、'提示'、および '受け入れ' アクションが満たされます。
Apache HTTP クライアント依存関係を pom.xml ファイルに追加します。
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency>
ssl-test-outbound
という新しい REST エンドポイントを追加します。 このエンドポイントは、TLS ソケット自体を開き、TLS 接続が TLS/SSL 証明書を受け入れることを確認します。 スタートアップ クラスの前の部分を次のコードで置き換えます。import java.security.KeyStore; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.azure.security.keyvault.jca.KeyVaultLoadStoreParameter; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; @SpringBootApplication @RestController public class SsltestApplication { public static void main(String[] args) { SpringApplication.run(SsltestApplication.class, args); } @GetMapping(value = "/ssl-test") public String inbound(){ return "Inbound TLS is working!!"; } @GetMapping(value = "/ssl-test-outbound") public String outbound() throws Exception { KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault"); KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter( System.getProperty("azure.keyvault.uri")); azureKeyVaultKeyStore.load(parameter); SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(azureKeyVaultKeyStore, null) .build(); HostnameVerifier allowAll = (String hostName, SSLSession session) -> true; SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, allowAll); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); String sslTest = "https://localhost:8443/ssl-test"; ResponseEntity<String> response = restTemplate.getForEntity(sslTest, String.class); return "Outbound TLS " + (response.getStatusCode() == HttpStatus.OK ? "is" : "is not") + " Working!!"; } @GetMapping(value = "/exit") public void exit() { System.exit(0); } }
次のコマンドを実行してコードをコンパイルし、実行可能な JAR ファイルにパッケージ化します。
mvn clean package
この記事の前の手順と同じ
sftp
コマンドを使用して、もう一度アプリをアップロードします。cd target sftp <your VM public IP address> put *.jar
VM でアプリを実行します。
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
サーバーが実行されたら、サーバーが TLS/SSL 証明書を受け入れることを確認します。 前の
curl
コマンドを発行したのと同じ Bash シェルで、次のコマンドを実行します。curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
Outbound TLS is working!!
というメッセージが表示されます。exit
パスを呼び出して、サーバーを強制終了し、ネットワーク ソケットを閉じます。curl --insecure https://<your VM public IP address>:8443/exit
これで、Azure Key Vault に格納されている自己署名 TLS/SSL 証明書を使用して、'読み込み'、'提示'、および '受け入れ' アクションを簡単に確認できました。
Azure Spring Apps にデプロイする
Spring Boot アプリケーションがローカルで実行されたので、運用環境に移行します。 Azure Spring Apps では、コードを変更せずに、Spring Boot アプリケーションを Azure に簡単にデプロイできます。 Spring アプリケーションのインフラストラクチャはこのサービスによって管理されるため、開発者はコードに専念できます。 Azure Spring Apps では、包括的な監視と診断、構成管理、サービス検出、CI/CD 統合、ブルー/グリーン デプロイなどを使用して、ライフサイクルを管理できます。 Azure Spring Apps にアプリケーションをデプロイするには、「初めてのアプリケーションを Azure Spring Apps にデプロイする」を参照してください。
次のステップ
Spring および Azure の詳細については、Azure ドキュメント センターで引き続き Spring に関するドキュメントをご確認ください。