spring cloud config学习三:安全与加密解密

安全保护

由于配置中心存储的内容比较敏感,做一定的安全处理是必要的。为配置中心实现安全保护的方式有很多,比如物理网络限制,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

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

加密解密

在微服务架构中,我们通常会采用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.jarUS_export_policy.jar两个文件复制到$JAVA_HOME/jre/lib/security目录下。覆盖之前的默认内容。

➜ 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

相关端点

在完成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

发现显示的也是解密的配置。

注意
如果配置文件时application而不是yml加密数据就写成

spring.datasource.username={cipher}af9b9ea63ce1c027d78c1c3414b425ad6f0093c20c69ad144eacb5a8b4522e7c

非对称加密

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%

参考资料
Creating a Key Store for Testing
java keytool证书工具使用小结

本博客代码
代码地址
配置仓库
user服务配置仓库
order服务配置仓库

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容