安全保護
由于配置中心存儲的內(nèi)容比較敏感,做一定的安全處理是必要的。為配置中心實現(xiàn)安全保護的方式有很多,比如物理網(wǎng)絡(luò)限制,OAuth2
授權(quán)等。不過,由于我們的微服務(wù)應(yīng)用和配置中心都是構(gòu)建與springboot
基礎(chǔ)上的,所以與spring security
結(jié)合使用會更加方便。
加入spring-boot-starter-security
依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
默認(rèn)情況下,我們可以隨機獲得一個名為user的用戶,并且在配置中心啟動的時候,在日志中打印出隨機密碼,具體如下:
Using default security password: 8c374401-d37c-43fc-8f1e-cf6b09b75045
大多數(shù)情況下,我們并不會使用隨機生成的密碼的機制,可以在配置文件中指定用戶和密碼,比如:
security:
basic:
enabled: true
user:
name: user
password: root123456
由于我們已經(jīng)為config-server
設(shè)置了安全保護,如果這時候連接到配置中心的客戶端沒有設(shè)置對應(yīng)的安全信息,在獲取配置信息時會返回401錯誤,所以需要通過配置方法在客戶端加入安全校驗,
security:
basic:
enabled: true
user:
name: user
password: root123456
demo
config server加入spring-boot-starter-security依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
配置文件(application.yml):
security:
basic:
enabled: true
user:
name: user
password: root123456
spring:
application:
name: config-server-git
cloud:
config:
server:
git:
uri: http://git.oschina.net/zhihaomiao/{application}-config
username:
password:
server:
port: 9090
啟動之后訪問url驗證:
http://localhost:9090/master/order-service-pro.yml
客戶端怎么配置呢?
客戶端有二種配置方式,第一種:
通過uri的形式:
spring:
application:
name: order-service
cloud:
config:
uri: http://user:root123456@localhost:9090
profile: pro
label: master
server:
port: 6060
第二種方式,通過spring.cloud.config.username
和spring.cloud.config.password
二個屬性:
spring:
application:
name: order-service
cloud:
config:
uri: http://localhost:9090
username: user
password: root123456
profile: pro
label: master
server:
port: 6060
The spring.cloud.config.password and spring.cloud.config.username values override anything that is provided in the URI.
spring.cloud.config.password和spring.cloud.config.username的值會重寫掉URI的用戶名和密碼。
參考資料
Spring Cloud Config Server-Security
Spring Cloud Config Client-Security
加密解密
在微服務(wù)架構(gòu)中,我們通常會采用DevOps
的組織方式來降低因團隊間溝通造成的巨大成本,以加速微服務(wù)應(yīng)用的交付能力,這就使得原本運維團隊控制的線上信息將交由微服務(wù)所屬組織的成員自行維護,其中將會包含大量的敏感信息,比如數(shù)據(jù)庫的賬戶與密碼等。顯然,明文存儲是非常危險的。針對這個問題。 spring cloud config
提供了對屬性加密解密的功能,以保護配置文件中的信息安全,比如下面的列子:
spring.datasource.username=root
spring.datasource.password={cipher}dsafdsfsdf3r423rewfsdfsdfasdfasdfsadfsadfsadfsa
在spring cloud config
中通過屬性值前使用{cipher}
前綴來標(biāo)注該內(nèi)容是一個加密值,當(dāng)微服務(wù)客戶加載配置時,配置中心會自動為帶有{cipher}
前綴的值進行解密,通過該機制的實現(xiàn),運維團隊就可以將線上信息的加密資源給微服務(wù)團隊,而不擔(dān)心這些敏感信息遭到泄漏了。
使用前提
在使用spring cloud config
的加密解密功能時,為了啟動該功能,需要在配置中心環(huán)境安裝jce(Unlimited Strength Jurisdiction Policy)。雖然,jce時jdk自帶的,但是默認(rèn)使用的是有長度限制的版本。在oracle的官方網(wǎng)站下載它,下載地址:jce1.8版本
下載之后是一個壓縮包,里面有三個文件:
local_policy.jar
README.txt
US_export_policy.jar
我們需要將local_policy.jar
和US_export_policy.jar
兩個文件復(fù)制到$JAVA_HOME/jre/lib/security
目錄下。覆蓋之前的默認(rèn)內(nèi)容。
? echo $JAVA_HOME
? /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home
我在本地將其放入到了下面的路徑下了,
/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/security
相關(guān)端點
在完成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:查看加密功能狀態(tài)的端點。
- /key: 查看密鑰的端點。
- /encrypt: 對請求的body內(nèi)容進行加密的端點。
- /decrypt:對請求body內(nèi)容進行解密的端點
嘗試訪問/encrypt/status端點,
http://localhost:9090/encrypt/status
頁面顯示:
{
description: "No key was installed for encryption service",
status: "NO_KEY"
}
該返回信息說明當(dāng)前配置中心的加密功能還不能使用,因為還沒有配置對應(yīng)的密鑰。
配置密鑰
可以通過encrypt.key
屬性在配置文件中直接指定密鑰的信息(對稱性密鑰),比如:在application.yml中加入配置如下:
encrypt:
key: zhihao.miao
加入了上述服務(wù)配置信息之后,重啟配置中心,重新訪問http://localhost:9090/encrypt/status
端點
{
status: "OK"
}
此時,我們配置中心的加密解密功能就已經(jīng)可以使用了,訪問/encrypt
和/decrypt
端點來使用加密和解密的功能,二個都是post請求,加密和解密信息都需要通過請求體來發(fā)送。
? curl localhost:9090/encrypt -d zhihao.miao
af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c%
? curl localhost:9090/decrypt -d af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c
zhihao.miao%
百分號是結(jié)束符。
我們通過配置encrypt.key
參數(shù)來指定密鑰的實現(xiàn)方式采用了對稱性加密。這種方式實現(xiàn)起來比較簡單,只需要配置一個參數(shù)即可。另外,我們也可以使用環(huán)境變量ENCRYPT_KEY
來進行配置,讓密鑰信息外部化存儲。
demo
修改order-service服務(wù)的git倉庫的生產(chǎn)環(huán)境的配置(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
結(jié)果:
check:
uri: pro-1.0
spring:
datasource:
username: zhihao.miao
我們發(fā)現(xiàn)config-server-git服務(wù)自動解密了。
客戶端服務(wù)(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
打印結(jié)果如下:
username=zhihao.miao,check.uri===pro-1.0
發(fā)現(xiàn)顯示的也是解密的配置。
注意
如果配置文件時application而不是yml加密數(shù)據(jù)就寫成
spring.datasource.username={cipher}af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c
非對稱加密
spring cloud config
的配置中心不僅可以使用對稱性加密,也可以使用非對稱性加密(比如RSA密鑰對)。雖然非對象加密(比如RSA密鑰對)。雖然非對稱性加密的密鑰生成與配置相對復(fù)雜一些,但是它具有更高的安全性。
首先,需要通過keytool
工具來生成密鑰對。keytool
是jdk中的一個密鑰和證書的管理工具。它使用戶能夠管理自己的公鑰/私鑰及相關(guān)證書,用于(通過數(shù)字簽名)自我認(rèn)證(用戶向其他用戶,服務(wù)認(rèn)證自己)或數(shù)據(jù)完整性以及認(rèn)證服務(wù)。在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
在當(dāng)前目錄下生成server.jks文件(證書文件)
也可以這樣生成:
keytool -genkeypair -alias mytestkey -keyalg RSA \
-keypass changeme -keystore server.jks -storepass letmein
同樣也在當(dāng)前目錄下server.jks文件(證書文件)
demo
將生成的server.jks文件(證書文件)放到當(dāng)前的config server服務(wù)的項目路徑下,
配置配置文件(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%
參考資料
Creating a Key Store for Testing
java keytool證書工具使用小結(jié)