領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多安全套接字層 (SSL) 和傳輸層安全 (TLS) 是分層或面向服務架構中系統間安全通訊的關鍵元件。此類架構中的 Spring Boot 應用程式通常接受傳入的網路連線或建立傳出連線,開發人員的任務是配置應用程式以在此類安全環境中工作。
如果您曾使用過 Java 安全和 SSL API,您可能會意識到這不是一個特別有趣的任務。它通常涉及多次訪問 stackoverflow.com 複製貼上程式碼。有幾個因素使得使用 SSL 變得痛苦。
首先,您可能會獲得用於生產的信任材料,如證書和私鑰。您可能需要為預生產測試生成不同的信任材料(通常使用自簽名證書頒發機構)。這些信任材料通常以 JKS 或 PKCS #12 格式的 Java 金鑰庫檔案形式存在,或者它們可能是 PEM 編碼的文字檔案。每種檔案型別都需要不同的處理方式。
一旦您有了信任材料,就需要將其轉換為可以傳遞給 Java 連線 API 的形式。這可能會變得困難,因為連線 API 可以透過多種方式進行配置
java.security.KeyStore 例項。javax.net.ssl.KeyManager 和 javax.net.ssl.TrustManager 例項。javax.net.ssl.SSLContext 例項。SSL 也相當底層,所以您通常需要剝開幾層抽象才能找到需要使用 java.security 或 java.net.ssl 包中的物件進行配置的東西。例如,如果您想在 Spring RestTemplate 上配置 SSL,您需要深入到支援它的 ClientHttpRequestFactory。對於典型的 Spring Boot 應用程式,這可能是 HttpComponentsClientHttpRequestFactory、OkHttp3ClientHttpRequestFactory 或 SimpleClientHttpRequestFactory。每個都提供了不同的配置 API。
配置連線以使用 SSL 或 TLS 對 Spring Boot 來說並不新鮮,但團隊決定對當前支援的功能進行整體審視,並尋找改進和擴充套件支援的機會。我們希望您會發現 Spring Boot 3.1 讓 SSL 配置變得更加容易。
Spring Boot 3.1 引入了 SSL 捆綁包的概念,用於配置和使用自定義 SSL 信任材料,如金鑰庫、證書和私鑰。配置後,捆綁包可以使用配置屬性或 API 應用到一個或多個連線。
用於配置 SSL 信任材料的屬性位於 application.yaml 或 application.properties 檔案中的 spring.ssl.bundle 字首下。提供了兩個頂層分組,以反映配置不同型別信任材料所需的獨特資訊。
spring.ssl.bundle.jks 可用於使用 Java 金鑰庫檔案配置捆綁包。spring.ssl.bundle.pem 可用於使用 PEM 編碼的文字檔案配置捆綁包。可以配置一種或多種型別的捆綁包,每個配置的捆綁包都給定一個使用者提供的名稱。該名稱在透過屬性應用捆綁包或透過 API 檢索它時使用。
以下示例 application.yaml 檔案展示了兩個 SSL 捆綁包的配置。第一個名為 server,定義了一個 Java 金鑰庫檔案(PKCS #12 格式),可用於保護嵌入式 Web 伺服器。第二個名為 client,定義了一個包含 PEM 編碼證書檔案的信任庫,可用於保護需要客戶端認證的伺服器連線的客戶端側。
spring:
ssl:
bundle:
jks:
server:
key:
alias: "server"
keystore:
location: "classpath:server.p12"
password: "secret"
type: "PKCS12"
pem:
client:
truststore:
certificate: "classpath:client.crt"
有關可用配置屬性的更多詳細資訊,請參閱 Spring Boot 參考文件以及 JksSslBundleProperties 和 PemSslBundleProperties 類。
Spring Boot 使用 spring.ssl.bundle 屬性建立提供訪問指定信任材料的物件。
如上所述,Java 安全和 SSL API 提供了三個抽象級別來暴露從 Java 金鑰庫或 PEM 檔案讀取的信任材料
java.security.KeyStore 例項。javax.net.ssl.KeyManager 和 javax.net.ssl.TrustManager 例項。javax.net.ssl.SSLContext 例項。在最低層,您可能需要信任庫和金鑰庫物件來將 SSL 應用於連線。這些可以使用 SslStoreBundle 介面訪問,如下所示
public interface SslStoreBundle {
KeyStore getKeyStore();
String getKeyStorePassword();
KeyStore getTrustStore();
}
KeyManager 和 TrustManager 例項可以從金鑰庫和信任庫派生。這些可以使用 SslManagerBundle 介面訪問
public interface SslManagerBundle {
KeyManager[] getKeyManagers();
KeyManagerFactory getKeyManagerFactory();
TrustManager[] getTrustManagers();
TrustManagerFactory getTrustManagerFactory();
}
最後,可以從 KeyManager 和 TrustManager 建立 SSLContext,並透過 createSslContext 工廠方法訪問。
綜合所有這些,我們有一個 SslBundle 介面,可以訪問各種不同的配置樣式
public interface SslBundle {
SslStoreBundle getStores();
SslManagerBundle getManagers();
SSLContext createSslContext() {
}
有關 SslBundle 中方法的完整列表,請參閱原始碼。
配置的 SslBundle 集合在 SslBundles bean 中可用,可以自動裝配到其他 Spring bean 中
public interface SslBundles {
SslBundle getBundle(String bundleName) throws NoSuchSslBundleException;
}
使用 SslBundles 檢索和應用 SSLContext 的示例可能如下所示
@Component
public class MyComponent {
public MyComponent(SslBundles sslBundles) {
SslBundle sslBundle = sslBundles.getBundle("client");
SSLContext sslContext = sslBundle.createSslContext();
// do something with the created sslContext
}
}
Spring Boot 3.1 中新增的令人興奮的 SSL 功能領域是 REST 客戶端的配置。Spring Boot 對自定義 RestTemplate 或 WebClient 的支援現在包括應用 SSL 捆綁包以保護客戶端和 REST 服務之間連線的能力。
RestTemplateBuilder 有一個新的 setSslBundle() 方法,它接受從自動配置的 SslBundles 檢索到的 SSL 捆綁包,如本例所示
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
this.restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build();
}
}
WebClientSsl 介面允許檢索 SSL 捆綁包並將其應用於 WebClient.Builder,如本例所示
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {
this.webClient = webClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
}
}
Spring Boot 可以輕鬆配置用於連線應用程式到資料服務的客戶端庫。這些客戶端庫是使用 Java 安全和 SSL API 的三個配置級別的良好示例。
在 3.1 之前,Spring Boot 提供自動配置的許多資料服務都提供了某種形式的 SSL 配置。然而,支援級別和用於配置的屬性在服務之間不一致。大多數資料服務自動配置屬性現在具有類似的 ssl 結構,在服務之間提供了更高的一致性
spring.cassandra.sslspring.couchbase.env.sslspring.elasticsearch.restclient.sslspring.data.mongodb.sslspring.data.redis.ssl大多數服務都有一個 *.ssl.enabled 屬性,它將使用 Java 執行時 cacerts 中包含的信任材料在客戶端庫中啟用 SSL 支援。*.ssl.bundle 屬性應用命名 SSL 捆綁包,以使用捆綁包中的自定義信任材料啟用客戶端庫 SSL 支援。這使得配置更加一致,並允許將相同的信任材料應用於多個連線,從而減少了屬性或 YAML 配置的數量。
為了提供這種程度的一致性,一些以前與 SSL 相關的屬性已被棄用。有關更多詳細資訊,請參閱配置屬性變更日誌。
JDBC 連線顯然被遺漏了。我們計劃在即將釋出的 Spring Boot 版本中將 SSL 捆綁包方法應用於 JDBC 連線。
Spring Boot 支援的所有嵌入式 Web 伺服器都可以透過使用 server.ssl.* 屬性配置 SSL 來保護傳入連線。Java 金鑰庫檔案自 Spring Boot 誕生以來一直受支援,而 PEM 編碼檔案自 2.7 版本以來一直受支援。
server.ssl 字首下的屬性數量隨著時間增長,缺乏結構使得難以判斷哪些屬性可以一起使用以及哪些是互斥的。以前的 server.ssl.* 屬性繼續受支援,但新的 server.ssl.bundle 屬性可用於將配置的 SSL 捆綁包應用於嵌入式 Web 伺服器。
以下兩個示例在功能上是相同的
server:
ssl:
key-alias: “server”
key-password: “keysecret”
key-store: "classpath:server.p12"
key-store-password: "storesecret"
client-auth: NEED
spring:
ssl:
bundle:
jks:
web-server:
key:
alias: "server"
password: “keysecret”
keystore:
location: "classpath:server.p12"
password: "storesecret"
server:
ssl:
bundle: “web-server”
client-auth: NEED
舊的結構更簡潔,但新的結構減少了錯誤配置的可能性,並允許將相同的 SSL 捆綁包用於多個連線。
management.server.ssl 和 spring.rsocket.server.ssl 屬性也進行了類似更改。
我們真的希望您發現 SSL 捆綁包是 Spring Boot 3.1 的一個有用功能。如果您發現任何其他您認為我們應該為其新增 SSL 支援的技術,請提出 GitHub 問題,我們將在未來的版本中考慮它。