安全保护
由于配置中心存储的内容比较敏感,做一定的安全处理是必要的。为配置中心实现安全保护的方式有很多,比如物理网络限制,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.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
加密解密
在微服务架构中,我们通常会采用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
目录下。覆盖之前的默认内容。
➜ 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服务配置仓库