Spring Cloud配置快速入門

1.概述

**Spring Cloud Config**是Spring的客戶端/服務器方法,用於跨多個應用程序和環境存儲和提供分佈式配置。

理想情況下,此配置存儲在Git版本控制下進行版本控制,並且可以在應用程序運行時進行修改。儘管它非常適合使用所有受支持的配置文件格式以及諸如EnvironmentPropertySource or @Value類的結構的Spring應用程序,但是它可以在運行任何編程語言的任何環境中使用。

在本文中,我們將重點關註一個示例,該示例如何設置由Git支持的配置服務器,如何在簡單的REST應用程序服務器中使用它以及如何設置包括加密屬性值的安全環境。

2.項目設置和依賴關係

為了準備編寫一些代碼,我們首先創建兩個新的Maven項目。服務器項目依賴於spring-cloud-config-server模塊以及spring-boot-starter-securityspring-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-configspring-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,它提供我們版本控制的配置內容。後者可與httpssh等協議或本地文件系統上的簡單file一起使用。

提示:如果計劃使用指向同一配置存儲庫的多個配置服務器實例,則可以配置服務器以將您的存儲庫克隆到本地臨時文件夾中。但是請注意具有兩因素身份驗證的私有存儲庫,它們很難處理!在這種情況下,將它們克隆到本地文件系統上並使用副本會更容易。

還有一些placeholder variables and search patterns用於配置可用的repository-url 。但這超出了本文的範圍。如果您有興趣,可以從官方文檔開始。

我們還需要在application.propertiesBasic-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)找到本文的源代碼。