springcloud系列—Config—第6章-3: Spring Cloud Config 高可用配置、安全與加密解密
資料參考:《Spring Cloud 微服務實戰》
目錄
安全保護
由於配置中心儲存的內容比較敏感,做一定的安全處理是必要的。為配置中心實現安全保護的方式有很多,比如物理網路限制,OAuth2
授權等。不過,由於我們的微服務應用和配置中心都是構建與springboot
基礎上的,所以與spring security
結合使用會更加方便。
加入spring-boot-starter-security
依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
預設情況下,我們可以隨機獲得一個名為user的使用者,並且在配置中心啟動的時候,在日誌中打印出隨機密碼,具體如下:
Using default security password: 8c374401-d37c-43fc-8f1e-cf6b09b75045
大多數情況下,我們並不會使用隨機生成的密碼的機制,可以在配置檔案中指定使用者和密碼,比如:
security:
basic:
enabled: true
user:
name: user
password: root123456
由於我們已經為config-server
設定了安全保護,如果這時候連線到配置中心的客戶端沒有設定對應的安全資訊,在獲取配置資訊時會返回401錯誤,所以需要通過配置方法在客戶端加入安全校驗,
security:
basic:
enabled: true
user:
name: user
password: root123456
加密解密
在微服務架構中,我們通常會採用DevOps
的組織方式來降低因團隊間溝通造成的巨大成本,以加速微服務應用的交付能力,這就使得原本運維團隊控制的線上資訊將交由微服務所屬組織的成員自行維護,其中將會包含大量的敏感資訊,比如資料庫的賬戶與密碼等。顯然,明文儲存是非常危險的。針對這個問題。 spring cloud config
提供了對屬性加密解密的功能,以保護配置檔案中的資訊保安,比如下面的列子:
spring.datasource.username=root spring.datasource.password={cipher}dsafdsfsdf3r423rewfsdfsdfasdfasdfsadfsadfsadfsa
在spring cloud config
中通過屬性值前使用{cipher}
字首來標註該內容是一個加密值,當微服務客戶載入配置時,配置中心會自動為帶有{cipher}
字首的值進行解密,通過該機制的實現,運維團隊就可以將線上資訊的加密資源給微服務團隊,而不擔心這些敏感資訊遭到洩漏了。
使用前提
在使用spring cloud config
的加密解密功能時,為了啟動該功能,需要在配置中心環境安裝jce(Unlimited Strength Jurisdiction Policy)。雖然,jce時jdk自帶的,但是預設使用的是有長度限制的版本。在oracle的官方網站下載它,下載地址:jce1.8版本
下載之後是一個壓縮包,裡面有三個檔案:
local_policy.jar
README.txt
US_export_policy.jar
我們需要將local_policy.jar
和US_export_policy.jar
兩個檔案複製到$JAVA_HOME/jre/lib/security
目錄下。覆蓋之前的預設內容。到這裡準備工作完成了。
相關端點
在完成jce的安裝後,可以嘗試啟動配置中心。在控制檯中,將會輸出一些配置中心特有的端點,
08-18 14:04:43.238 INFO 53689 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/encrypt],methods=[POST]}" onto public java.lang.String org.springframework.cloud.config.server.encryption.EncryptionController.encrypt(java.lang.String,org.springframework.http.MediaType)
2017-08-18 14:04:43.238 INFO 53689 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/encrypt/{name}/{profiles}],methods=[POST]}" onto public java.lang.String org.springframework.cloud.config.server.encryption.EncryptionController.encrypt(java.lang.String,java.lang.String,java.lang.String,org.springframework.http.MediaType)
2017-08-18 14:04:43.238 INFO 53689 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/decrypt/{name}/{profiles}],methods=[POST]}" onto public java.lang.String org.springframework.cloud.config.server.encryption.EncryptionController.decrypt(java.lang.String,java.lang.String,java.lang.String,org.springframework.http.MediaType)
2017-08-18 14:04:43.238 INFO 53689 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/decrypt],methods=[POST]}" onto public java.lang.String org.springframework.cloud.config.server.encryption.EncryptionController.decrypt(java.lang.String,org.springframework.http.MediaType)
2017-08-18 14:04:43.238 INFO 53689 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/encrypt/status],methods=[GET]}" onto public java.util.Map<java.lang.String, java.lang.Object> org.springframework.cloud.config.server.encryption.E
- /encrypt/status:檢視加密功能狀態的端點。
- /key: 檢視金鑰的端點。
- /encrypt: 對請求的body內容進行加密的端點。
- /decrypt:對請求body內容進行解密的端點
嘗試訪問/encrypt/status端點,http://localhost:9090/encrypt/status,頁面顯示:
{
description: "No key was installed for encryption service",
status: "NO_KEY"
}
該返回資訊說明當前配置中心的加密功能還不能使用,因為還沒有配置對應的金鑰。
配置金鑰
可以通過encrypt.key
屬性在配置檔案中直接指定金鑰的資訊(對稱性金鑰),比如:在application.yml中加入配置如下:
encrypt:
key: zhihao.miao
加入了上述服務配置資訊之後,重啟配置中心,重新訪問http://localhost:9090/encrypt/status
端點
{
status: "OK"
}
此時,我們配置中心的加密解密功能就已經可以使用了,訪問/encrypt
和/decrypt
端點來使用加密和解密的功能,二個都是post請求,加密和解密資訊都需要通過請求體來發送。
➜ curl localhost:9090/encrypt -d zhihao.miao
af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c%
➜ curl localhost:9090/decrypt -d af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c
zhihao.miao%
百分號是結束符。
我們通過配置encrypt.key
引數來指定金鑰的實現方式採用了對稱性加密。這種方式實現起來比較簡單,只需要配置一個引數即可。另外,我們也可以使用環境變數ENCRYPT_KEY
來進行配置,讓金鑰資訊外部化儲存。
demo
修改order-service服務的git倉庫的生產環境的配置(application-pro.yml):
spring:
datasource:
username: '{cipher}af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c'
check:
uri: pro-1.0
貼一下配置中心config-server-git的配置(application.yml):
spring:
application:
name: config-server-git
cloud:
config:
server:
git:
uri: http://git.oschina.net/zhihaomiao/{application}-config
username: zhihao.miao
password: 13579qwertyu
server:
port: 9090
encrypt:
key: zhihao.miao
通過url地址訪問:
http://localhost:9090/master/order-service-pro.yml
結果:
check:
uri: pro-1.0
spring:
datasource:
username: zhihao.miao
我們發現config-server-git服務自動解密了。
客戶端服務(order-service)進行解密,配置檔案(bootstrap.yml):
spring:
application:
name: order-service
cloud:
config:
uri: http://localhost:9090
profile: pro
label: master
server:
port: 6060
定義了OrderController:
@RestController
@RequestMapping("/order")
public class OrderController {
private Logger log = LoggerFactory.getLogger(getClass());
@Value("${spring.datasource.username}")
private String username;
@Value("${check.uri}")
private String checkurl;
@GetMapping("/index")
public String index(){
log.info("username="+username+",check.uri=="+username);
return "username="+username+",check.uri==="+checkurl;
}
}
url地址訪問驗證:
http://localhost:6060/order/index
列印結果如下:
username=zhihao.miao,check.uri===pro-1.0
發現顯示的也是解密的配置。
非對稱加密
spring cloud config
的配置中心不僅可以使用對稱性加密,也可以使用非對稱性加密(比如RSA金鑰對)。雖然非物件加密(比如RSA金鑰對)。雖然非對稱性加密的金鑰生成與配置相對複雜一些,但是它具有更高的安全性。
首先,需要通過keytool
工具來生成金鑰對。keytool
是jdk中的一個金鑰和證書的管理工具。它使使用者能夠管理自己的公鑰/私鑰及相關證書,用於(通過數字簽名)自我認證(使用者向其他使用者,服務認證自己)或資料完整性以及認證服務。在jdk1.4以後的版本中都包含了這一工具,位置在$JAVA_HOME/bin/keytool
echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home
我自己本地在/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/bin
下。
生成證書檔案:
keytool -genkeypair -alias mytestkey -keyalg RSA \
-dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US" \
-keypass changeme -keystore server.jks -storepass letmein
在當前目錄下生成server.jks檔案(證書檔案)
也可以這樣生成:
keytool -genkeypair -alias mytestkey -keyalg RSA \
-keypass changeme -keystore server.jks -storepass letmein
同樣也在當前目錄下server.jks檔案(證書檔案)
demo
將生成的server.jks檔案(證書檔案)放到當前的config server服務的專案路徑下,
配置配置檔案(application.yml):
spring:
application:
name: config-server-git
cloud:
config:
server:
git:
uri: http://git.oschina.net/zhihaomiao/{application}-config
username: zhihao.miao
password: 13579qwertyu
server:
port: 9090
encrypt:
keyStore:
location: classpath:/server.jks
password: letmein
alias: mytestkey
secret: changeme
訪問加密解密的端點
➜ curl localhost:9090/encrypt -d zhihao.miao
AQArpt0MuLQ4V5/BC/1YkZlUIL72o4M4VEwreFnBXXLGD7iut6KTqTItA9fkjn+XkrHBOuPp2sR7rL8gCaNROE7kqSbxhqclAM7FQv8wy1x5/TZg+QUY/WMkDas4OZmleEZbt+JpZoV/m7n+V8tJwHfgV6zoWCbMwiMjGCzlmfTqsikb0T1t4V2n3JmnAgUtZi0Ot5Gbu1HpsJ2b/YFEH0mcoM/hgJhZNoemxXWiG+vlKCk6edozv/gPm7cz+mCHOsBPf8wQt/4HDEWJPPBIGsBs/OZVi+tEaWchBzSr2CMEdzNCG9OgD/CZneAOwBl/OCCQk83edL7uviko0E9VNlWkIvSXx6TuMCRN8EIwuK6nWPY1fwZXv+GbM17DYPw4dRA=%
➜ curl localhost:9090/decrypt -d AQArpt0MuLQ4V5/BC/1YkZlUIL72o4M4VEwreFnBXXLGD7iut6KTqTItA9fkjn+XkrHBOuPp2sR7rL8gCaNROE7kqSbxhqclAM7FQv8wy1x5/TZg+QUY/WMkDas4OZmleEZbt+JpZoV/m7n+V8tJwHfgV6zoWCbMwiMjGCzlmfTqsikb0T1t4V2n3JmnAgUtZi0Ot5Gbu1HpsJ2b/YFEH0mcoM/hgJhZNoemxXWiG+vlKCk6edozv/gPm7cz+mCHOsBPf8wQt/4HDEWJPPBIGsBs/OZVi+tEaWchBzSr2CMEdzNCG9OgD/CZneAOwBl/OCCQk83edL7uviko0E9VNlWkIvSXx6TuMCRN8EIwuK6nWPY1fwZXv+GbM17DYPw4dRA=
zhihao.miao%
高可用配置
當要將配置中心部署到生產環境時,與服務註冊一樣,需要時高可用的應用。spring cloud config實現服務端的高可用。spring cloud config實現服務端的高可用非常簡單,主要有以下兩種方式:
- 傳統方式:不需要為這些服務端做任何額外的配置,遵循一個規則,將所有的config server都指向同一個git倉庫,這樣所有的配置內容就通過統一的共享檔案系統來維護。而客戶端在指定config server位置時,只需要配置config server上層的負載均衡設定地址即可。(此時要藉助nginx等服務了)
- 服務模式: 將
config server
作為一個普通的微服務應用,納入到eureka
的服務治理體系中。這樣我們的微服務應用就可以通過配置中心的服務名來獲取配置資訊,這種方式比起傳統的實現模式來說更加有利於維護,因為對於服務端的負載均衡配置和客戶端的配置中心制定都通過服務治理機制一併解決了,即實現了高可用,也實現了自維護。
git地址:https://github.com/servef-toto/SpringCloud-Demo/tree/master/config-server-file/git-config