搶先一步
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 Bundle 的概念,用於配置和使用自定義的 SSL 信任材料,例如金鑰庫、證書和私鑰。一旦配置完成,一個 bundle 可以透過配置屬性或 API 應用於一個或多個連線。
用於配置 SSL 信任材料的屬性位於 application.yaml
或 application.properties
檔案中的 spring.ssl.bundle
字首下。提供了兩個頂層分組,以反映配置不同型別信任材料所需的獨特資訊。
spring.ssl.bundle.jks
可用於使用 Java 金鑰庫檔案配置 bundle。spring.ssl.bundle.pem
可用於使用 PEM 編碼的文字檔案配置 bundle。可以配置每種型別的一個或多個 bundle,每個已配置的 bundle 都會被指定一個使用者提供的名稱。該名稱用於透過屬性應用 bundle 或透過 API 獲取 bundle。
以下的示例 application.yaml
檔案展示了兩個 SSL bundle 的配置。第一個名為 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 中,該 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 bundle 來保護客戶端和 REST 服務之間連線的能力。
RestTemplateBuilder
有一個新的 setSslBundle()
方法,它接受從自動配置的 SslBundles
中獲取的 SSL bundle,示例如下
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
this.restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build();
}
}
WebClientSsl
介面允許獲取 SSL bundle 並將其應用於 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.ssl
spring.couchbase.env.ssl
spring.elasticsearch.restclient.ssl
spring.data.mongodb.ssl
spring.data.redis.ssl
大多數服務都有一個 *.ssl.enabled
屬性,該屬性將使用 Java 執行時 cacerts
中包含的信任材料啟用客戶端庫中的 SSL 支援。*.ssl.bundle
屬性應用一個命名 SSL bundle,以使用 bundle 中的自定義信任材料啟用客戶端庫 SSL 支援。這使得配置更加一致,並允許將相同的信任材料應用於多個連線,從而減少了屬性或 YAML 配置的數量。
為了提供這種一致性,一些之前的 SSL 相關屬性已被棄用。有關更多詳細資訊,請參閱配置屬性變更日誌。
JDBC 連線顯然在此列表中有所遺漏。我們計劃在未來的 Spring Boot 版本中將 SSL bundle 方法應用於 JDBC 連線。
Spring Boot 支援的所有嵌入式 Web 伺服器都可以使用 server.ssl.*
屬性配置為使用 SSL 保護傳入連線。自 Spring Boot 問世以來就支援 Java 金鑰庫檔案,而 PEM 編碼的檔案自 2.7 版本起就已支援。
server.ssl
字首下的屬性數量隨著時間的推移不斷增加,缺乏結構使得難以區分哪些屬性可以一起使用以及哪些屬性是互斥的。以前的 server.ssl.*
屬性繼續受支援,但一個新的 server.ssl.bundle
屬性可用於將配置的 SSL bundle 應用於嵌入式 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 bundle。
management.server.ssl
和 spring.rsocket.server.ssl
屬性也進行了類似的更改。
我們真誠希望你發現 SSL bundle 是 Spring Boot 3.1 的一個有用功能。如果你發現任何其他你認為我們應該為其新增 SSL 支援的技術,請在 GitHub 上提交 issue,我們將在未來的版本中考慮。