spring cloud config學(xué)習(xí)三:安全與加密解密

安全保護

由于配置中心存儲的內(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.usernamespring.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.jarUS_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é)

本博客代碼
代碼地址
配置倉庫
user服務(wù)配置倉庫
order服務(wù)配置倉庫

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容