使用 SSL 套裝組合保護 Spring Boot 3 應用程式
一、簡介
管理 Spring Boot 應用程式中的安全通訊通常涉及處理複雜的配置。挑戰通常始於處理信任資料,例如憑證和私鑰,這些資料採用各種格式,如 JKS、PKCS #12 或 PEM。對於如何處理這些格式,每種格式都有自己的一套要求。
幸運的是,Spring Boot 3.1 引入了 SSL Bundles,這項功能旨在簡化這些複雜性。在本教程中,我們將探討什麼是 SSL 捆綁包以及它們如何簡化 Spring Boot 應用程式的 SSL 設定任務。
2. Spring Boot SSL 捆綁包
通常,一旦我們獲得了信任材料,我們需要將其轉換為應用程式可以使用的 Java 物件。這通常意味著處理諸如用於存儲密鑰材料的java.security.KeyStore
、用於管理此密鑰材料javax.net.ssl.KeyManager
以及用於創建安全套接字連接javax.net.ssl.SSLContext
之類的類別。
每個類別都需要另一層理解和配置,使得過程繁瑣且容易出錯。各種 Spring Boot 元件可能還需要深入研究不同的抽象層來應用這些設置,從而為任務增加了另一層難度。
SSL 捆綁包將所有信任材料和組態設定(例如金鑰庫、憑證和私密金鑰)封裝到一個易於管理的單元中。配置 SSL 捆綁包後,即可將其應用於一個或多個網路連接,無論它們是傳入還是傳出。
SSL 捆綁包的設定屬性位於application.yaml
或application.properties
設定檔中的spring.ssl.bundle
前綴下。
讓我們從 JKS 捆綁包開始。我們使用spring.ssl.bundle.jks
來設定使用 Java Keystore 檔案的套件:
spring:
ssl:
bundle:
jks:
server:
key:
alias: "server"
keystore:
location: "classpath:server.p12"
password: "secret"
type: "PKCS12"
對於 PEM 捆綁包,我們使用spring.ssl.bundle.pem
來使用 PEM 編碼的文字檔案配置捆綁包:
spring:
ssl:
bundle:
pem:
client:
truststore:
certificate: "classpath:client.crt"
配置這些捆綁包後,它們可以跨微服務應用 - 無論是需要安全存取資料庫的庫存服務、需要安全 API 呼叫的用戶身份驗證服務,還是與支付網關安全通訊的支付處理服務。
Spring Boot 根據 SSL Bundle 配置自動建立 Java 對象,如KeyStore
、 KeyManager
和SSLContext
。這消除了手動建立和管理這些物件的需要,使過程更加簡單且不易出錯。
3. 使用 SSL 捆綁包保護RestTemplate
讓我們從在使用RestTemplate
bean 的同時利用 SSL 捆綁包開始。為此,我們將使用範例 Spring Boot 應用程序,但首先,我們需要產生將用作 SSL 捆綁包的金鑰。
我們將使用openssl
二進位(通常與 git 一起安裝)透過從專案根目錄執行以下命令來產生金鑰:
$ openssl req -x509 -newkey rsa:4096 -keyout src/main/resources/key.pem -out src/main/resources/cert.pem -days 365 -passout pass:FooBar
現在,讓我們將此金鑰轉換為 PKCS12 格式:
$ openssl pkcs12 -export -in src/main/resources/cert.pem -inkey src/main/resources/key.pem -out src/main/resources/keystore.p12 -name secure-service -passin pass:FooBar -passout pass:FooBar
因此,我們擁有配置 SSL 捆綁包的一切;讓我們在application.yml
檔案中定義一個名為“secure-service”
的套件:
spring:
ssl:
bundle:
jks:
secure-service:
key:
alias: "secure-service"
keystore:
location: "classpath:keystore.p12"
password: "FooBar"
type: "PKCS12"
接下來,我們可以透過呼叫setSslBundle()
方法在RestTemplate
上設定捆綁包:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
return restTemplateBuilder.setSslBundle(sslBundles.getBundle("secure-service")).build();
}
最後,我們可以使用配置好的RestTemplate
bean 來呼叫 API:
@Service
public class SecureServiceRestApi {
private final RestTemplate restTemplate;
@Autowired
public SecureServiceRestApi(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String fetchData(String dataId) {
ResponseEntity<String> response = restTemplate.exchange(
"https://secure-service.com/api/data/{id}",
HttpMethod.GET,
null,
String.class,
dataId
);
return response.getBody();
}
}
Spring Boot 應用程式中的 SSL Bundle 用於驗證secure-service
的證書,確保加密且安全的通訊通道。但是,這並不限制我們在 API 端使用客戶端憑證進行身份驗證。稍後我們將看到如何取得SSLContext
來配置自訂客戶端。
4.利用 Spring Boot 的自動設定SSLBundles
在 Spring Boot 的 SSL Bundles 之前,開發人員通常會使用支援 SSL 配置的經典 Java 類別:
-
java.security.KeyStore
:這些實例用作金鑰庫和信任庫,有效地充當加密金鑰和憑證的安全儲存庫。 -
javax.net.ssl.KeyManager
和javax.net.ssl.TrustManager
:這些實例分別管理 SSL 通訊期間的金鑰和信任決策。 -
javax.net.ssl.SSLContext
:這些實例充當SSLEngine
和SSLSocket
物件的工廠,協調 SSL 配置在運行時的實作方式。
Spring Boot 3.1 引進了分為 Java 介面的結構化抽象層:
-
SslStoreBundle
:提供通往包含加密金鑰和可信任憑證的KeyStore
物件的閘道。 -
SslManagerBundle
:協調並提供管理KeyManager
和TrustManager
物件的方法。 -
SslBundle
:作為一站式商店,將所有這些功能聚合到與 SSL 生態系統的統一互動模型中。
隨後,Spring Boot 自動配置SslBundles
bean。因此,我們可以方便地將SslBundle
實例注入任何 Spring Bean 中。這對於為舊程式碼庫和自訂 REST 用戶端配置安全通訊非常有用。
例如,讓我們考慮自訂安全HttpClient
需要自訂SSLContext
:
@Component
public class SecureRestTemplateConfig {
private final SSLContext sslContext;
@Autowired
public SecureRestTemplateConfig(SslBundles sslBundles) throws NoSuchSslBundleException {
SslBundle sslBundle = sslBundles.getBundle("secure-service");
this.sslContext = sslBundle.createSslContext();
}
@Bean
public RestTemplate secureRestTemplate() {
SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create().setSslContext(this.sslContext).build();
HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(sslSocketFactory).build();
HttpClient httpClient = HttpClients.custom().setConnectionManager(cm).evictExpiredConnections().build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
}
在上面的程式碼中,我們將SslBundles
實例注入到Autowired
建構子中。實際上, SslBundles
為我們提供了對所有配置的 SSL 捆綁包的存取。因此,我們檢索secure-service
包並建立上下文。稍後,我們使用SSLContext
實例建立自訂HttpClient
並應用它來建立RestTemplate
bean。
5. 將 SSL 捆綁包與資料服務結合使用
不同的資料服務具有不同程度的 SSL 配置選項,從而在配置過程中造成複雜性。
SSL Bundles 引入了一種更統一的方法來跨各種資料服務進行 SSL 配置:
- 卡桑德拉:
spring.cassandra.ssl
- 沙發底座:
spring.couchbase.env.ssl
- Elasticsearch:
spring.elasticsearch.restclient.ssl
- MongoDB:
spring.data.mongodb.ssl
- Redis:
spring.data.redis.ssl
現在,大多數這些服務都支援*.ssl.enabled
屬性。此屬性啟動客戶端庫中的 SSL 支持,利用 Java 運行時的cacerts
中找到的信任材料。
此外, *.ssl.bundle
屬性允許我們應用命名的 SSL 捆綁包來自訂信任材料,從而實現跨多個服務連接的一致性和可重複使用性。
對於此範例,我們假設有一個名為mongodb-ssl-bundle
的 SSL 套件。此捆綁包包含必要的信任材料,以確保與 MongoDB 實例的連線安全。
讓我們定義application.yml
檔案:
spring:
data:
mongodb:
ssl:
enabled: true
bundle: mongodb-ssl-bundle
只要新增這些屬性,Spring Boot 應用程式中的 MongoDB 用戶端程式庫就會自動使用mongodb-ssl-bundle
中指定的 SSL 上下文和信任材質。
6. 將 SSL 捆綁包與嵌入式伺服器一起使用
使用 SSL 套裝組合還可以簡化在 Spring Boot 中管理嵌入式 Web 伺服器的 SSL 設定。
傳統上, server.ssl.*
屬性用於設定每個單獨的 SSL 配置。透過 SSL 捆綁包,可以將配置分組在一起,然後在多個連接之間重複使用,從而減少出錯的可能性並簡化整體管理。
首先,讓我們探討一下傳統的個人財產方法:
server:
ssl:
key-alias: "server"
key-password: "keysecret"
key-store: "classpath:server.p12"
key-store-password: "storesecret"
client-auth: NEED
另一方面,SSL Bundle 方法允許封裝相同的配置:
spring:
ssl:
bundle:
jks:
web-server:
key:
alias: "server"
password: "keysecret"
keystore:
location: "classpath:server.p12"
password: "storesecret"
現在,我們可以使用定義的套件來保護我們的 Web 伺服器:
server:
ssl:
bundle: "web-server"
client-auth: NEED
雖然這兩種方法都可以保護嵌入式 Web 伺服器,但 SSL 捆綁方法對於設定管理來說更有效。此功能也可用於其他配置,例如management.server.ssl
和spring.rsocket.server.ssl
。
七、結論
在本文中,我們探索了 Spring Boot 中新的 SSL Bundles 功能,該功能可以簡化和統一配置信任材料的過程。
與傳統的server.ssl.*
屬性相比,SSL 捆綁包提供了一種結構化的方式來管理金鑰庫和信任庫。這對於減少錯誤配置風險和提高跨多個服務管理 SSL 的效率特別有利。
此外, SSL 捆綁包非常適合集中管理,允許在應用程式的不同部分重複使用同一個捆綁包。
透過合併 SSL 套裝組合,開發人員不僅可以簡化設定流程,還可以提升 Spring Boot 應用程式中嵌入式 Web 伺服器的安全性。
與往常一樣,整個程式碼範例可以在 GitHub 上找到。