使用 Azure 金鑰保存庫 憑證在 Spring Boot 中啟用 HTTPS

本教學課程說明如何使用 Azure 金鑰保存庫 和 Azure 資源的受控識別,使用 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 資源的 Azure 金鑰保存庫 和受控識別來啟用 TLS。

Diagram showing interaction of elements in this tutorial.

重要

目前,Spring Cloud Azure 憑證入門 4.x 版或更新版本不支援 TLS/mTLS,它們只會自動設定 金鑰保存庫 憑證用戶端。 因此,如果您想要使用 TLS/mTLS,則無法移轉至 4.x 版。

必要條件

  • Azure 訂用帳戶 - 免費建立一個訂用帳戶。

  • 第 11 版支援的 Java 開發工具套件 (JDK)。

  • Apache Maven 3.0 版或更高版本。

  • Azure CLI

  • cURL 或類似的 HTTP 公用程式來測試功能。

  • Azure 虛擬機 (VM) 實例。 如果您沒有,請使用 az vm create 命令和 UbuntuServer 提供的 Ubuntu 映射,建立已啟用系統指派受控識別的 VM 實例。 將 Contributor 角色授與系統指派的受控識別,然後設定訂用帳戶的存取權 scope

  • Azure 金鑰保存庫 實例。 如果您沒有金鑰保存庫,請參閱快速入門:使用 Azure 入口網站 建立金鑰保存庫。

  • Spring Boot 應用程式。 如果您沒有 Maven 專案,請使用 Spring Initializr 建立 Maven 專案。 請務必選取 Maven 專案,然後在 [相依性] 底下新增 Spring Web 相依性,然後選取 [Java 第 8 版] 或更新版本。

重要

需要 Spring Boot 2.5 版或更高版本,才能完成本文中的步驟。

設定自我簽署 TLS/SSL 憑證

本教學課程中的步驟適用於直接儲存在 Azure 金鑰保存庫 的任何 TLS/SSL 憑證(包括自我簽署)。 自我簽署憑證不適用於生產環境,但對開發和測試應用程式很有用。

本教學課程使用自我簽署憑證。 若要設定憑證,請參閱快速入門:使用 Azure 入口網站 從 Azure 金鑰保存庫 設定及擷取憑證。

注意

設定憑證之後,請依照指派 金鑰保存庫 存取原則中的指示,將 VM 存取權授與 金鑰保存庫。

透過 TLS/SSL 憑證保護連線

您現在有 VM 和 金鑰保存庫 實例,並已將 VM 存取權授與 金鑰保存庫。 下列各節說明如何在 Spring Boot 應用程式中透過來自 Azure 金鑰保存庫 的 TLS/SSL 憑證安全地連線。 本教學課程示範下列兩個案例:

  • 執行具有安全輸入連線的 Spring Boot 應用程式
  • 執行具有安全輸出連線的 Spring Boot 應用程式

提示

在下列步驟中,程式代碼會封裝成可執行檔,並上傳至 VM。 別忘了在 VM 中安裝 OpenJDK

執行具有安全輸入連線的 Spring Boot 應用程式

當輸入連線的 TLS/SSL 憑證來自 Azure 金鑰保存庫 時,請遵循下列步驟來設定應用程式:

  1. 將下列相依性新增至 您的 pom.xml 檔案:

    <dependency>
       <groupId>com.azure.spring</groupId>
       <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId>
       <version>3.14.0</version>
    </dependency>
    
  2. 在 application.properties 組態檔中設定 金鑰保存庫 認證。

    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 vaultUriaz keyvault create傳回 JSON 中的屬性。 您已將此值儲存在環境變數中。

    金鑰保存庫 特有的唯一屬性是 azure.keyvault.uri。 應用程式正在 VM 上執行,其系統指派的受控識別已獲授與 金鑰保存庫 的存取權。 因此,應用程式也已獲得存取權。

    這些變更可讓 Spring Boot 應用程式載入 TLS/SSL 憑證。 在下一個步驟中,您將讓應用程式執行 TLS/SSL 憑證的接受 動作,如教學課程開頭所述。

  3. 編輯啟動類別檔案,使其具有下列內容。

    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);
        }
    
    }
    

    System.exit(0)從未經驗證的 REST GET 呼叫內呼叫僅供示範之用。 請勿在實際應用程式中使用 System.exit(0)

    此程式代碼說明 本教學課程開頭所述的目前 動作。 下列清單會醒目提示此程式碼的一些詳細資料:

    • 現在有 Spring @RestController Initializr 所產生的類別註釋 SsltestApplication
    • 有一個以標註的方法 @GetMapping,其中包含 value 您進行之 HTTP 呼叫的 。
    • inbound 瀏覽器對 /ssl-test 路徑提出 HTTPS 要求時,方法只會傳回問候語。 方法 inbound 說明伺服器如何將 TLS/SSL 憑證呈現給瀏覽器。
    • 方法 exit 會導致 JVM 在叫用時結束。 這個方法可讓您在本教學課程的內容中輕鬆執行範例。
  4. 執行下列命令來編譯程序代碼,並將其封裝成可執行的 JAR 檔案。

    mvn clean package
    
  5. 確認在 內 <your-resource-group-name> 建立的網路安全組允許來自IP位址的埠22和8443上的輸入流量。 若要瞭解如何設定網路安全組規則以允許輸入流量,請參閱建立、變更或刪除網路安全組的安全性規則一節。

  6. 將可執行檔 JAR 檔案放在 VM 上。

    cd target
    sftp azureuser@<your VM public IP address>
    put *.jar
    

    既然您已建置 Spring Boot 應用程式並將其上傳至 VM,請使用下列步驟在 VM 上執行,並使用呼叫 REST 端點 curl

  7. 使用 SSH 連線到 VM,然後執行可執行的 JAR。

    set -o noglob
    ssh azureuser@<your VM public IP address> "java -jar *.jar"
    
  8. 開啟新的 Bash 殼層,然後執行下列命令來確認伺服器是否顯示 TLS/SSL 憑證。

    curl --insecure https://<your VM public IP address>:8443/ssl-test
    
  9. exit叫用路徑以終止伺服器並關閉網路套接字。

    curl --insecure https://<your VM public IP address>:8443/exit
    

既然您已看到 載入呈現 具有自我簽署 TLS/SSL 憑證的動作,請對應用程式進行一些簡單的變更,以查看 接受 動作。

執行具有安全輸出連線的 Spring Boot 應用程式

在本節中,您會修改上一節中的程序代碼,讓輸出連線的 TLS/SSL 憑證來自 Azure 金鑰保存庫。 因此,Azure 金鑰保存庫 會滿足負載呈現接受動作。

  1. 將 Apache HTTP 用戶端相依性新增至 pom.xml 檔案:

    <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
       <version>4.5.13</version>
    </dependency>
    
  2. 新增名為 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);
        }
    
    }
    
  3. 執行下列命令來編譯程序代碼,並將其封裝成可執行的 JAR 檔案。

    mvn clean package
    
  4. 使用本文稍早的相同 sftp 命令再次上傳應用程式。

    cd target
    sftp <your VM public IP address>
    put *.jar
    
  5. 在 VM 上執行應用程式。

    set -o noglob
    ssh azureuser@<your VM public IP address> "java -jar *.jar"
    
  6. 執行伺服器之後,請確認伺服器接受 TLS/SSL 憑證。 在您發出上一 curl 個命令的相同Bash殼層中,執行下列命令。

    curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
    

    您應該會看到訊息 Outbound TLS is working!!

  7. exit叫用路徑以終止伺服器並關閉網路套接字。

    curl --insecure https://<your VM public IP address>:8443/exit
    

您現在已觀察到載入、呈現和接受動作的簡單圖例,其中包含儲存在 Azure 金鑰保存庫 中的自我簽署 TLS/SSL 憑證。

部署至 Azure Spring Apps

現在您已在本機執行 Spring Boot 應用程式,現在可以將其移至生產環境。 Azure Spring Apps 可讓您輕鬆地將 Spring Boot 應用程式部署至 Azure,而不需要變更任何程式代碼。 服務會管理 Spring 應用程式的基礎結構,讓開發人員可以專注於處理程式碼。 Azure Spring 應用程式提供生命週期管理,使用全方位的監視和診斷、組態管理、服務探索、持續整合與持續傳遞的整合、藍綠部署等等。 若要將應用程式部署至 Azure Spring Apps,請參閱 將第一個應用程式部署至 Azure Spring Apps

下一步

若要深入瞭解 Spring 和 Azure,請繼續前往 Azure 上的 Spring 檔中心。