Spring Cloud配置快速入門
1.概述
**Spring Cloud Config
**是Spring的客戶端/服務器方法,用於跨多個應用程序和環境存儲和提供分佈式配置。
理想情況下,此配置存儲在Git
版本控制下進行版本控制,並且可以在應用程序運行時進行修改。儘管它非常適合使用所有受支持的配置文件格式以及諸如Environment
, PropertySource or @Value
類的結構的Spring應用程序,但是它可以在運行任何編程語言的任何環境中使用。
在本文中,我們將重點關註一個示例,該示例如何設置由Git
支持的配置服務器,如何在簡單的REST
應用程序服務器中使用它以及如何設置包括加密屬性值的安全環境。
2.項目設置和依賴關係
為了準備編寫一些代碼,我們首先創建兩個新的Maven
項目。服務器項目依賴於spring-cloud-config-server模塊以及spring-boot-starter-security和spring-boot-starter-web啟動程序包:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
但是對於客戶端項目,我們只需要spring-cloud-starter-config和spring-boot-starter-web modules :
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.配置服務器實現
該應用程序的主要部分是配置類-更具體地說是@SpringBootApplication
通過auto-configure
批註@EnableConfigServer:
提取所有必需的設置@EnableConfigServer:
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
public static void main(String[] arguments) {
SpringApplication.run(ConfigServer.class, arguments);
}
}
現在,我們需要配置服務器正在偵聽的服務器port
和一個Git
-url,它提供我們版本控制的配置內容。後者可與http
, ssh
等協議或本地文件系統上的簡單file
一起使用。
提示:如果計劃使用指向同一配置存儲庫的多個配置服務器實例,則可以配置服務器以將您的存儲庫克隆到本地臨時文件夾中。但是請注意具有兩因素身份驗證的私有存儲庫,它們很難處理!在這種情況下,將它們克隆到本地文件系統上並使用副本會更容易。
還有一些placeholder variables and search patterns
用於配置可用的repository-url
。但這超出了本文的範圍。如果您有興趣,可以從官方文檔開始。
我們還需要在application.properties
為Basic-Authentication
設置用戶名和密碼,以避免在每次應用程序重啟時自動生成密碼:
server.port=8888
spring.cloud.config.server.git.uri=ssh://localhost/config-repo
spring.cloud.config.server.git.clone-on-start=true
spring.security.user.name=root
spring.security.user.password=s3cr3t
4. Git存儲庫作為配置存儲
為了完成我們的服務器,我們必須在配置的url下初始化一個Git
存儲庫,創建一些新的屬性文件,並使用一些值來普及它們。
配置文件的名稱像普通的Spring application.properties
一樣組成,但不是單詞“ application”而是配置的名稱,例如,使用客戶端的屬性'spring.application.name'
的值,後跟一個破折號和有效的個人資料。例如:
$> git init
$> echo 'user.role=Developer' > config-client-development.properties
$> echo 'user.role=User' > config-client-production.properties
$> git add .
$> git commit -m 'Initial config-client properties'
故障排除:如果遇到與ssh
相關的身份驗證問題,請仔細檢查ssh服務器上的~/.ssh/known_hosts
和~/.ssh/authorized_keys
!
5.查詢配置
現在我們可以啟動服務器了。我們的服務器提供的Git
支持的配置API可以使用以下路徑查詢:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
其中{label}
佔位符引用Git分支, {application}
引用客戶端的應用程序名稱, {profile}
引用客戶端的當前活動應用程序配置文件。
因此,我們可以通過以下方式檢索在分支master
服務器中的開發配置文件下運行的計劃配置客戶端的配置:
$> curl http://root:s3cr3t@localhost:8888/config-client/development/master
6.客戶端實現
接下來,讓我們看一下客戶端實現。這將是一個非常簡單的客戶端應用程序,由具有一個GET
方法的REST
控制器組成。
為了獲取服務器的配置,必須將其放置在名為bootstrap.application
的資源文件中,因為該文件(如名稱所示)將在應用程序啟動時很早加載:
@SpringBootApplication
@RestController
public class ConfigClient {
@Value("${user.role}")
private String role;
public static void main(String[] args) {
SpringApplication.run(ConfigClient.class, args);
}
@GetMapping(
value = "/whoami/{username}",
produces = MediaType.TEXT_PLAIN_VALUE)
public String whoami(@PathVariable("username") String username) {
return String.format("Hello!
You're %s and you'll become a(n) %s...\n", username, role);
}
}
除了應用程序名稱,我們還將活動配置文件和連接詳細信息放在bootstrap.properties
:
spring.application.name=config-client
spring.profiles.active=development
spring.cloud.config.uri=http://localhost:8888
spring.cloud.config.username=root
spring.cloud.config.password=s3cr3t
為了進行測試,如果從服務器正確接收了配置,並且role value
被注入到控制器方法中,我們只需在啟動客戶端后捲曲它:
$> curl http://localhost:8080/whoami/Mr_Pink
如果響應如下,則我們的Spring Cloud Config Server
及其客戶端目前可以正常工作:
Hello! You're Mr_Pink and you'll become a(n) Developer...
7.加密和解密
要求:要將強密碼密鑰與Spring加密和解密功能一起使用,您需要在JVM.
安裝'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files'
JVM.
這些可以例如從Oracle下載。按照下載中包含的說明進行安裝。一些Linux發行版還通過其軟件包管理器提供了可安裝的軟件包。
由於配置服務器支持屬性值的加密和解密,因此您可以使用公共存儲庫來存儲用戶名和密碼等敏感數據。如果服務器配置為使用對稱密鑰或密鑰對,則加密值以字符串{cipher}
為前綴,並且可以通過對路徑'/encrypt'
的REST調用生成。
也可以使用要解密的端點。兩個端點都接受一個包含佔位符的路徑,該路徑包含應用程序的名稱及其當前配置文件: '/*/{name}/{profile}'
。這對於控制每個客戶端的加密特別有用。但是,在它們變得有用之前,您必須配置一個加密密鑰,這將在下一部分中進行。
提示:如果您使用curl來調用en- / decryption API,最好使用–data-urlencode
選項(而不是–data/-d
),或者將“ Content-Type”標頭設置為'text/plain'
。這樣可以確保正確處理加密值中的特殊字符,例如“ +”。
如果在通過客戶端提取值時無法自動將其解密,則將其key
重命名為名稱本身,並以單詞“ invalid”作為前綴。例如,這應防止使用加密值作為密碼。
提示:設置包含YAML文件的存儲庫時,必須用單引號將加密和前綴的值括起來!對於“屬性”,情況並非如此。
7.1。 CSRF
默認情況下,Spring Security為發送到我們應用程序的所有請求啟用CSRF保護。
因此,為了能夠使用/encrypt
和/decrypt
端點,讓我們為它們禁用CSRF:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf()
.ignoringAntMatchers("/encrypt/**")
.ignoringAntMatchers("/decrypt/**");
super.configure(http);
}
}
7.2。密鑰管理
默認情況下,配置服務器啟用以對稱或非對稱方式加密屬性值。
要使用對稱加密,只需要將application.properties
的屬性'encrypt.key'
設置為您選擇的秘密.
或者,您可以傳入環境變量ENCRYPT_KEY
。
對於非對稱密碼,可以將'encrypt.key'
設置為PEM
編碼的字符串值,或配置要使用的keystore
。
因為我們需要為我們演示服務器高度安全的環境中,我們選擇了後者選項,並生成一個新的密鑰庫,包括RSA
密鑰對,首先使用Java keytool
:
$> keytool -genkeypair -alias config-server-key \
-keyalg RSA -keysize 4096 -sigalg SHA512withRSA \
-dname 'CN=Config Server,OU=Spring Cloud,O=Baeldung' \
-keypass my-k34-s3cr3t -keystore config-server.jks \
-storepass my-s70r3-s3cr3t
之後,我們將創建的密鑰庫添加到服務器的bootstrap.properties
然後重新運行它:
encrypt.keyStore.location=classpath:/config-server.jks
encrypt.keyStore.password=my-s70r3-s3cr3t
encrypt.keyStore.alias=config-server-key
encrypt.keyStore.secret=my-k34-s3cr3t
下一步,我們可以查詢加密端點並將響應作為值添加到存儲庫中的配置:
$> export PASSWORD=$(curl -X POST --data-urlencode d3v3L \
http://root:s3cr3t@localhost:8888/encrypt)
$> echo "user.password={cipher}$PASSWORD" >> config-client-development.properties
$> git commit -am 'Added encrypted password'
$> curl -X POST http://root:s3cr3t@localhost:8888/refresh
為了測試,如果我們的設置正確運行,我們將修改ConfigClient
類並重新啟動客戶端:
@SpringBootApplication
@RestController
public class ConfigClient {
...
@Value("${user.password}")
private String password;
...
public String whoami(@PathVariable("username") String username) {
return String.format("Hello!
You're %s and you'll become a(n) %s, " +
"but only if your password is '%s'!\n",
username, role, password);
}
}
如果正確解密了我們的配置值,則對客戶的最終查詢將向我們顯示:
$> curl http://localhost:8080/whoami/Mr_Pink
Hello! You're Mr_Pink and you'll become a(n) Developer, \
but only if your password is 'd3v3L'!
7.3。使用多個鍵
如果要使用多個密鑰進行加密和解密,例如:每個服務的應用程序專用一個密鑰,則可以在{cipher}
前綴和BASE64
編碼的屬性值之間以{cipher}
{name:value}
的形式添加另一個前綴。 。
配置服務器幾乎可以立即使用{secret:my-crypto-secret}
或{key:my-key-alias}
類的前綴。後一個選項需要在application.properties
配置密鑰庫。在此密鑰庫中搜索匹配的密鑰別名。例如:
user.password={cipher}{secret:my-499-s3cr3t}AgAMirj1DkQC0WjRv...
user.password={cipher}{key:config-client-key}AgAMirj1DkQC0WjRv...
對於沒有密鑰庫的方案,您必須實現@Bean
類型的TextEncryptorLocator
,該TextEncryptorLocator
處理查找並為每個密鑰返回TextEncryptor
-Object。
7.4。提供加密的屬性
如果要禁用服務器端加密並在本地處理屬性值的解密,可以將以下內容放入服務器的application.properties
:
spring.cloud.config.server.encrypt.enabled=false
此外,您可以刪除所有其他“ encrypt。*”屬性以禁用REST
端點。
8.結論
現在,我們可以創建一個配置服務器,以從Git
存儲庫向客戶端應用程序提供一組配置文件。使用這種服務器還可以做其他一些事情。
例如:
- 以
YAML
或“Properties
格式(而不是JSON –
還解決了佔位符。在非配置環境未直接映射到PropertySource
非Spring環境中使用時,這很有用。 - 提供純文本配置文件-依次選擇使用解析的佔位符。例如,這對於提供環境相關的日誌記錄配置很有用。
- 將配置服務器嵌入到一個應用程序中,在該應用程序中它從
Git
存儲庫中進行自我配置,而不是作為為客戶端提供服務的獨立應用程序運行。因此,必須設置一些引導程序屬性和/或必須刪除@EnableConfigServer
批註,具體取決於用例。 - 使配置服務器在Spring Netflix Eureka服務發現中可用,並在配置客戶端中啟用自動服務器發現。如果服務器沒有固定的位置或它在其位置中移動,則這很重要。
最後,您可以[on Github](https://github.com/eugenp/tutorials/tree/master/spring-cloud/spring-cloud-config)
找到本文的源代碼。