Spring Cloud第十篇 | 分布式配置中心Config

本文是Spring Cloud专栏的第十篇文章,了解前九篇文章内容有助于更好的理解本文:html

  1. Spring Cloud第一篇 | Spring Cloud前言及其经常使用组件介绍概览git

  2. Spring Cloud第二篇 | 使用并认识Eureka注册中心spring

  3. Spring Cloud第三篇 | 搭建高可用Eureka注册中心数据库

  4. Spring Cloud第四篇 | 客户端负载均衡Ribbonbootstrap

  5. Spring Cloud第五篇 | 服务熔断Hystrix浏览器

  6. Spring Cloud第六篇 | Hystrix仪表盘监控Hystrix Dashboard安全

  7. Spring Cloud第七篇 | 声明式服务调用Feign服务器

  8. Spring Cloud第八篇 | Hystrix集群监控Turbin网络

  9. Spring Cloud第九篇 | 分布式服务跟踪Sleuth架构

1、介绍

    Spring Cloud Config是Spring Cloud团队建立的一个全新项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端(config server)与客户端(config client)两个部分。其中服务端也称为分布式配置中心,它是一个独立的微服务应用,用来链接配置仓库并为客户端提供获取配置信息、加密/解密信息等访问接口,而客户端则是微服务架构中的各个微服务应用或基础设施,它们经过指定的配置中心来管理应用资源与业务相关的配置内容, 并在启动的时候从配置中心获取和加载配置信息。Spring Cloud Config实现了对服务端和客户端中环境变量和属性配置的抽象映射,因此它除了适用于Spring构建的应用程序以外, 也能够在任何其余语言运行的应用程序中使用。因为Spring Cloud Config实现的配置中心默认采用Git来存储配置信息,因此使用Spring Cloud Config构建的配置服务器,自然就支持对微服务应用配置信息的版本管理,而且能够经过Git客户端工具来方便地管理和访问配置内容。固然它也提供了对其余存储方式的支持,好比SVN仓库、本地化文件系统。 

2、构建Config Server

一、添加依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-server</artifactId>
</dependency>

二、在启动类上添加注解@EnableConfigServer

三、在application.yml文件中添加配置

spring:
  application:
    name: springcloud-config-server
  cloud:
    config:
      server:
        git:
          #配置git仓库地址
          uri: https://gitee.com/coding-farmer/config-center
          #配置仓库路径
          search-paths: "{profile}"
          #访问git仓库的用户名
          username:
          #访问git仓库的密码
          password:
          #配置中心经过git从远程git库,有时本地的拷贝被污染,
          #这时配置中心没法从远程库更新本地配置,设置force-pull=true,则强制从远程库中更新本地库
          force-pull: true
          #默认从git仓库克隆下载的在C:/Users/<当前用户>/AppData/Local/Temp
          #basedir:

server:
  port: 8888

    若是Git仓库为公开仓库,能够不填写用户名和密码,若是是私有仓库须要填写,本案例使用的是码云公开仓库。

四、配置中心仓库目录结构为:按环境拆分

    远程码云仓库https://gitee.com/coding-farmer/config-center中有3个文件夹,分别是dev,prod,test,里面存放着相应环境的配置文件

五、测试返回数据

http请求地址和资源文件映射以下:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

    此时启动咱们的配置中心,经过/{application}/{profile}/[{label}]就能访问到咱们的配置文件了,其中application表示配置文件的名字,对应咱们上面的配置文件就是config;profile表示环境,咱们有dev、test、prod还有默认,label表示分支,默认咱们都是放在master分支上

访问:http://localhost:8888/configclient/dev,默认分支为master分支

以下图则证实配置服务中心能够从远程程序获取配置信息:

    从浏览器上能够看到咱们放在仓库中的配置文件信息。JSON中的name表示配置文件名application的部分,profiles表示环境部分,label表示分支,多了一个version,实际上就是咱们码云上提交信息时产生的版本号,当咱们访问成功后,咱们还能够看到控制台打印了以下日志:

INFO 6600 --- [nio-8888-exec-1] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5c4fca8a: startup date [Thu Aug 15 15:12:07 CST 2019]; root of context hierarchy
INFO 6600 --- [nio-8888-exec-1] o.s.c.c.s.e.NativeEnvironmentRepository  : Adding property source: file:/C:/Users/Administrator/AppData/Local/Temp/config-repo-6372945341655107732/dev/configclient-dev.yml
INFO 6600 --- [nio-8888-exec-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5c4fca8a: startup date [Thu Aug 15 15:12:07 CST 2019]; root of context hierarchy

    其实是配置中心经过git clone命令将配置文件在本地保存了一份,这样能够确保在git仓库挂掉的时候咱们的应用还能够继续运行,当微服务A/B尝试去从Config Server中加载配置信息的时候,Config Server会先经过git clone命令克隆一份配置文件保存到本地,此时咱们断掉网络,再访问http://localhost:8888/configclient/dev同样还能够拿到数据,此时的数据就是从本地获取的。

    若是有两个前缀名相同文件,例如一个configclient.yml,一个configclient-dev.yml。那么在访问相同前缀的文件时,config-server会对这两个文件进行一个合并。例如configclient.yml有一段配置是configclient-dev.yml没有的,理应访问configclient-dev.yml的时候是没有那段配置的,但最终的访问的结果倒是它俩合并以后的内容,即configclient-dev.yml会拥有configclient.yml里所配置的内容。

    到此config server构建完成。

3、构建Config Client

    Config Client也就是你的微服务应用例如(springcloud-service-consumer、springcloud-service-feign、springcloud-service-provider等等,这些模块相对于Config Server来讲都是Config Client),可是为了保持其余案例模块的纯洁干净,这里就单独构建一个Config Client命名为:springcloud-config-client

一、引入依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-client</artifactId>
</dependency>

二、新建bootstrap.yml

    不了解bootstrap.yml能够参考,SpringCloud入门之经常使用的配置文件application.yml和 bootstrap.yml区别:https://www.cnblogs.com/BlogNetSpace/p/8469033.html

spring:
  application:
    name: springcloud-config-client
  cloud:
    config:
      #uri则表示配置中心的地址
      uri: http://localhost:8888
      #注:config 客户端在没有 spring.cloud.config.name属性的时候,服务端{application} 获取的是客户端
      #spring.application.name的值,不然,获取的是 spring.cloud.config.name的值。
      #1)、当没有spring.cloud.config.name时,客户端获取的是spring.application.name 所对应的git库中的文件,而且只能获取一个文件
      #2)、当一个项目中有需求要获取多个文件时,就须要用到spring.cloud.config.name这个属性,以逗号分割
      name: configclient
      profile: dev
      #label对应了label部分
      label: master
server:
  port: 8881

三、编写Controller

@RestController
public class MyController {

    //配置中内心面配置的env属性
    @Value("${env}")
    private String env;

    @RequestMapping("/index")
    public String env(){
        return env;
    }
}

四、访问http://localhost:8881/index

4、安全保护

    开发环境中咱们的配置中心确定是不能随随便便被人访问的,咱们能够加上适当的保护机制,因为微服务是构建在Spring Boot之上,因此整合Spring Security是最方便的方式。

一、添加依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

二、默认状况下,咱们能够得到一个名为user的用户,而且在配置中心启动的时候,在日志中打印出该用户的随机密码

Using generated security password: 9ca37d4c-c786-44be-8919-1825a0baaadb

    大多数状况下,咱们并不会使用随机生成密码的机制,咱们能够在配置中心服务端application.yml文件中指定用户名密码

spring:
  security:
    user:
      name: coding-farmer
      password: 123456

    当再次访问http://localhost:8888/configclient/dev配置中心服务端的时候须要输入密码,显示以下图

三、因为咱们已经为config server设置了安全保护,若是咱们这个时候链接到配置中心的客户端中没有设置响应对应的安全信息,在获取配置信息时会返回401错误,因此须要经过配置的方式在客户端中加入安全信息来经过校验,好比:

spring:
  cloud:
    config:
      username: coding-farmer
      password: 123456

5、加密解密

一、对称加密

    在微服务架构中,咱们一般会采用DevOps的组织方式来下降因团队间沟通形成的巨大成本,以加速微服务应用的交付能力。这就使得本来由运维团队控制的线上信息将交由微服务所属组织的成员自行维护,其中将会包括大量的敏感信息,好比数据库的帐户与密码等。显然,若是咱们直接将敏感信息以明文的方式存储于微服务应用的配置文件中是很是危险的。针对这个问题, Spring Cloud Config提供了对属性进行加密解密的功能,以保护配置文件中的信息安全。好比下面的例子

spring.datasource.username=root
spring.datasource.password={cipher}22fedb745505ffcd1dec962bee3c1f0f3af8a3e6b6930eee9afb8659b16a0c630fd256a181319704b806df90f38e7371

    在Spring Cloud Config中经过在属性值前使用{cipher)前缀来标注该内容是一个加密值,当微服务客户端加载配置时,配置中心会自动为带有{cipher}前缀的值进行解密。经过该机制的实现,运维团队就能够放心地将线上信息的加密资源给到微服务团队,而不用担忧这些敏感信息遭到泄漏的风险。

1-一、使用前提

    在使用 Spring Cloud Config的加密解密功能时,有一个必要的前提须要咱们注意。为了启用该功能,咱们须要在配置中心的运行环境中安装不限长度的JCE版本(Unlimited Strength Java Cryptography Extension)。虽然,JCE功能在JRE中自带,可是默认使用的是有长度限制的版本。咱们能够从 Oracle的官方网站下载到它,它是一个压缩包,解压后能够看到下面三个文件:

    咱们须要将local_policy.jar和US_export_policy.jar两个文件复制到%JAVA_HOME%\jre\lib\security目录下,覆盖原来的默认内容。注意:我这里使用的是JDK8,应该下载对应版本的JCE

1-二、相关端点

    在完成了JCE的安装后,能够尝试启动配置中心。在控制台中,将会输出一些配置中心特有的端点,主要包括以下几个

  • /encrypt/status:查看加密功能状态的端点。

  • /key:查看密钥的端点。

  • /encrypt:对请求的body内容进行加密的端点。

  • /decrypt:对请求的body内容进行解密的端点。

能够尝试经过GET请求访问/encrypt/status端点,咱们将获得以下内容

    该返回信息说明当前配置中心的加密功能还不能使用,由于没有为加密服务配置对应的密钥。

1-三、配置秘钥

    咱们能够经过encrypt.key属性在bootstrap.yml(为何要写bootstrap.yml文件里查看,关于spring cloud config加密EncryptionTooWeakException异常说明:https://www.iteye.com/blog/357029540-2433259)配置文件中直接指定密钥信息(对称性密钥),好比:

encrypt:
  key: coding-farmer

加入上述配置信息后,重启配置中心,再访问/encrypt/status端点,咱们将获得 以下内容:

    此时,咱们配置中心的加密解密功能就已经可使用了,不妨尝试访问一下/encrypt 和/decrypt端点来使用加密和解密的功能。注意,这两个端点都是POST请求,加密和解密信息须要经过请求体来发送。

1-四、使用postman进行加密:http://localhost:8888/encrypt

 

1-五、使用postman解密:http://localhost:8888/decrypt

 

1-六、把加密的内容复制到你的配置文件中,提交到仓库便可

    以下图,加密内容前面要有{cipher}开头表示该值是一个加密字符,配置中心config-server在获取到这个值以后会先对值进行解密,解密以后才会返回给客户端使用,若是是yml文件key=value,value值要加单引号

1-七、访问:http://localhost:8888/configclient/dev,显示以下则加密成功

二、非对称加密

    Spring Cloud Config的配置中心不只可使用对称性加密,也可使用非对称性加密 (好比RSA密钥对)。虽然非对称性加密的密钥生成与配置相对复杂一些,可是它具备更高的安全性。下面,咱们来具体介绍一下如何使用非对称加密

    首先,须要经过keytool工具来生成密钥对。keytool是JDK中的一个密钥和证书管理工具。它使用户可以管理本身的公钥/私钥对及相关证书,用于(经过数字签名)自我认证(用户向其余用户/服务认证本身)或数据完整性以及认证服务。在JDK1.4之后的版本中都包含了这一工具,它的位置在%JAVA_HOME%\bin\keytool.exe。

    生成密钥的具体命令以下所示,在DOS窗口输入:

keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore
C:\Program Files\Java\jdk1.8.0_101\bin>keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore
输入密钥库口令: 123456
再次输入新口令: 123456
您的名字与姓氏是什么?
  [Unknown]:  coding-farmer
您的组织单位名称是什么?
  [Unknown]:  company
您的组织名称是什么?
  [Unknown]:  organization
您所在的城市或区域名称是什么?
  [Unknown]:  city
您所在的省/市/自治区名称是什么?
  [Unknown]:  province
该单位的双字母国家/地区代码是什么?
  [Unknown]:  china
CN=coding-farmer, OU=company, O=organization, L=city, ST=province, C=china是否正确?
  [否]:  y

输入 <config-server> 的密钥口令
        (若是和密钥库口令相同, 按回车): 456789
再次输入新口令: 456789

    另外,若是不想逐步输入那些提示信息,可使用-dname来直接指定,而秘钥库口令可以使用-storepass和-keypass来直接指定。因此,咱们能够经过下面命令直接建立与上述命令同样的秘钥库。

keytool -genkeypair -alias config-server -keyalg RSA \
 -dname "CN=coding-farmer, OU=company, O=organization, L=city, ST=province,C=china" \
 -storepass 123456 \
 -keystore config-server.keystore \
 -keypass 456789 \

    默认状况下,使用上述命令创键的秘钥只有90天有效期,若是想要调整它的有效期,能够经过增长-validity参数来实现,好比咱们能够经过下面的命令,让秘钥的有效期延长到一年:

 keytool -genkeypair -alias config-server -keyalg RSA \
 -dname "CN=coding-farmer, OU=company, O=organization, L=city, ST=province, C=china" \
 -storepass 123456 \
 -keystore config-server.keystore \
 -keypass 456789 \
 -validity 365 \

    上述的三种命令生成方式,最终都会在命令的当前执行目录下生成一个config-server. keystore文件。下面,咱们须要将它保存在配置中心的文件系统中的某个位置, 好比将该文件拷贝到config-server的src\main\resources目录下,而后在配置中心中加入相关的配置信息

encrypt:
  key-store:
    location: config-server.keystore
    alias: config-server
    password: 123456
    secret: 456789

非对称加密的配置信息也能够经过环境变量的方式进行配置,它们对应的具体变量名以下:

ENCRYPT_KEY_STORE_LOCATION
ENCRYPT_KEY_STORE_ALIAS
ENCRYPT_KEY_STORE_PASSWORD
ENCRYPT_KEY_STORE_SECRET

测试方式和对称加密的测试方式一致

 

详细参考案例源码:https://gitee.com/coding-farmer/spirngcloud-learn

 

相关文章
相关标签/搜索