[Spring Cloud] 3.2 Spring Cloud Config 配置 (第二部分)

3.2 Spring Cloud Config Server 配置服务

Spring为扩展配置服务,提供了一个基于HTTP的资源绑定的api。(键值对,或者YAML内容) 此服务能够经过@EnableConfigServer很是容易的整合进Spring Boot应用中。java

例如:ConfigServer.javamysql

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
  public static void main(String[] args) {
    SpringApplication.run(ConfigServer.class, args);
  }
}

默认状况下,和Spring Boot应用同样运行在8080端口,固然也有不少种方法修改此端口。最简单的方法,设置默认的配置资源库。 经过在jar中configserver.yml文件中配置spring.config.name=configserver;或者经过指定本身的configserver.ymlgit

例如:application.propertiesgithub

server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo

${user.home}/config-repo,是一个git资源。内容为YAML或者properties文件内容。正则表达式

例如:算法

$ cd $HOME
$ mkdir config-repo
$ cd config-repo
$ git init .
$ echo info.foo: bar > application.properties
$ git add -A .
$ git commit -m "Add application.properties"

注意: 以上使用本地文件只是为了测试。生产中应该使用远程服务提供的配置资源。spring

3.2.1 Environment Repository 环境资源

在Config Server中,对于配置数据你想要怎么样存储呢?存储策略由Environment 中的EnvironmentRepository来决定。同时多个Environment之间也容许复制配置项,甚至配置源propertySourcessql

Environment资源主要来自这三个参数:bootstrap

  • {application}对应着客户端的spring.application.name配置;
  • {profile}对应着客户端spring.profiles.active配置;
  • {label}这是一个服务端功能,标记着配置文件的版本。

资源实例一般表现和Srping Boot应用加载配置文件相似:spring.config.name相似于{application}参数;spring.profiles.active相似于{profiles}参数。 对于特定配置文件的优先级也是相似Spring Boot的规则:特定的配置会覆盖默认配置,而且若是指定了多个,那最后一个优先级最高。api

例如:一个客户端应用能够配置一下引导配置:

bootstrap.yml

spring:
  application:
    name: foo
  profiles:
    active: dev,mysql

普通Spring Boot应用也能够经过环境变量或者命令行方式配置以上信息

若是资源是基于文件方式的,那系统会从application.yml建立一个Environment共享给全部客户端,而且加载foo.yml进行覆盖。 若是YAML文件中有指定特定配置的话,那么这些特定配置比默认配置拥有着更高的优先级。 这些拥有更高优先级的配置文件在Environment以前,就逐个生成PropertySource并被加载。

3.2.1.1 Git Backend 基于GIT

默认状况下EnvironmentRepository是基于GIT的,这样很是方便管理更新、物理环境也方便对修改历史进行审计。 能够经过spring.cloud.config.server.git.uri配置属性修改Config Server的本地资源库(例如:在application.yml中修改)。 若是设置成file:前缀,那会从本地资源进行加载,这样方便你快速简易的启动服务。可是这样就是直接在本地资源库上进行操做,没有备份。(不过若是远程服务资源是不变得状况下,这种方式也无所谓。)

若是须要扩展Config Server使其具有高可用性,那你须要将全部的服务实例指向同一个资源,这样就工做在一个共享文件的环境下。在这个状况下最好使用ssh:协议去访问共享文件资源,这样能够备份资源同时可使用本地缓存提升效率。

资源实例会把HTTP资源中的{label}映射成git标签(commit id, branch name 或者 tag) 若是git分支或者标签名上有斜杠"/"那映射成HTTP URL时会自动替换成"_"。使用括号、空格时须要当心。(例如使用cmd时须要加上双引号)

3.2.1.1.1 Placeholders in Git URI :git uri 中的占位符

当须要时,Spring Cloud Config Server 支持在GIT URI中使用{application}{profile}{label}三个占位符,可是要记住{label}老是会映射成git的标签。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/myorg/{application}
3.2.1.1.2 Pattern Matching and Multiple Repositories 正则与多资源库

在应用配置文件与特定配置文件中能够同过正则表达式来支持更为复杂的状况。能够在{application}/{profile}中可使用通配符进行匹配,若是有多个值可使用逗号分隔。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          repos:
            simple: https://github.com/simple/config-repo
            special:
              pattern: special*/dev*,*special*/dev*
              uri: https://github.com/special/config-repo
            local:
              pattern: local*
              uri: file:/home/configsvc/config-repo

若是{application}/{profile}没有匹配到任何资源,则使用spring.cloud.config.server.git.uri配置的默认URI。

上面例子中pattern属性是一个YAML数组,也可使用YAML数组格式来定义。这样能够设置成多个配个配置文件。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          repos:
            development:
              pattern:
                - */development
                - */staging
              uri: https://github.com/development/config-repo
            staging:
              pattern:
                - */qa
                - */production
              uri: https://github.com/staging/config-repo

每一个资源库有一个可选的配置,用来指定扫描路径。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          searchPaths: foo,bar*

这样系统就会自动搜索foo的子目录,以及以bar开头的文件夹中的子目录。

默认状况下,当第一次请求配置时,系统复制远程资源库。系统也能够配置成一启动就复制远程资源库。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://git/common/config-repo.git
          repos:
            team-a:
                pattern: team-a-*
                cloneOnStart: true
                uri: http://git/team-a/config-repo.git
            team-b:
                pattern: team-b-*
                cloneOnStart: false
                uri: http://git/team-b/config-repo.git
            team-c:
                pattern: team-c-*
                uri: http://git/team-a/config-repo.git

上面的例子中team-a的资源库会在启动时就从远程资源库进行复制,其余的则等到第一次请求时才从远程资源库复制。

若是远程资源库设置了权限认证,则能够以下配置:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          username: trolley
          password: strongpassword

若是你不是用HTTPS和用户认证,可使用SSH uri 的格式。例如:git@github.com:configuration/cloud-configuration 这样你就须要先有SSH的key。 这种方式系统会使用JGit库进行访问,能够去查看相关文档。能够在~/.git/config中设置HTTPS代理配置,或者也能够经过JVM参数-Dhttps.proxyHost-Dhttps.proxyPort来配置代理。

提示: 当你不知道你的~/.git目录时,可使用git config --global来指定。例如:git config --global http.sslVerify false

3.2.1.1.3 Placeholders in Git Search Paths : GIT路径搜索中的占位符

Spring Cloud 的 Config Server 也支持在搜索路径中使用{application}{profile}{label}占位符配置。例如:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          searchPaths: '{application}'

3.2.1.2 File System Backend 基于文件系统

也有不使用git资源库的方式,那就是从本地classpath或者文件系统加载配置文件。这种方式能够经过spring.profiles.active=native开启。

使用file:前缀加载文件系统,不然从classpath中加载,也可使用${}样式的环境占位符。例如:file:///${user.home}/config-repo

searchLocations默认值与本地Spring Boot应用的扫描路径同样,都是:[classpath:/, classpath:/config, file:./, file:./config] 这样并不用担忧application.properties文件暴露给全部客户端,由于在发送给客户端以前就会被清理掉。

基于文件系统的配置服务对于测试和快速练手来讲是比较好的,若是用于生产环境,那就须要确保文件系统的可靠性,并容许共享访问。

路径搜索时可以包含{application}{profile}{label},这样方便你按照目录来管理你的配置文件。

若是在路径搜索时不使用占位符,那也会尝试自动的在HTTP资源中加上{label}后缀,那这样就会从不一样的路径加载到。所以,在默认状况下不使用占位符等价于在每个路径后添加了/{label}/。例如:file:/tmp/config 就等价于 file:/tmp/config,file:/tmp/config/{label}

3.2.1.3 Sharing Configuration With All Applications 应用共享配置

经过基于文件(svn,本地)资源,文件名为application*的资源将在全部的应用客户端中共享。(application.properties,application.yml,application-*.properties) 能够经过这种方式来定义一个全局的默认配置,若有必要应用可使用应用指定配置对其进行覆盖。

3.2.1.4 Property Overrides 属性覆盖

Config Server 有一个属性覆盖的特性,容许操做者经过提供一个配置属性去覆盖全部应用中的配置。经过普通的Spring Boot钩子方式来实现,所以应用不须要什么改变。

声明覆盖仅仅须要在spring.cloud.config.server.overrides中配置一个键值对。例如:

spring:
  cloud:
    config:
      server:
        overrides:
          foo: bar

这样会引发全部的应用客户端去读取foo=bar去覆盖本身的配置。(固然应用拿到新的数据后本身决定如何使用,所以,覆盖并非强制的,客户端能够自定义拿到新数据后的行为)

提示: 使用文件方式时,Spring环境中的占位符${}能够用""对"$"转义,例如:\${app.foo:bar} 。当使用YAML时,YAML自己会处理,所以不须要转义。

3.2.2 Health Indicator 健康指示器

Config Server 经过一个健康指示器来检测配置的EnvironmentRepository是否正常工做。 默认状况下会向EnvironmentRepository询问一个名字为app的应用配置,EnvironmentRepository实例回应default配置。

能够经过配置让健康指示器一块儿去检查多个应用的多个配置。例如:

spring:
  cloud:
    config:
      server:
        health:
          repositories:
            myservice:
              label: mylabel
            myservice-dev:
              name: myservice
              profiles: development

也能够经过配置spring.cloud.config.server.health.enabled=false去关闭此功能。

3.2.2 Security 安全

你能够按你本身的状况用任何方法对Config Server进行安全处理。(从物理网络安全到OAuth2受权token),不过经过Spring Security 结合Spring Boot能提供一种更好的方式。

使用Spring Boot默认的基于HTTP安全方式,仅仅须要引入Spring Security依赖。(如:能够经过spring-boot-starter-security

默认状况使用一个用户名和一个随机产生的密码,这种方式并非很靠谱,所以,建议经过spring-boot-starter-security配置密码,并对其进行加密处理。

3.2.3 Encryption and Decryption 加解密

重要:要使用此特性,须要彻底的JCE受权,方法参见前文

若是远程资源是一个通过加密的内容(以{cipher}开头),在发送给客户端以前会被解密。 这样,配置内容就不用明文存放了。 当直接去替换一个没有解密的值时,会被标记为"invalid"(无效的)。 这基本上能够大部分的杜绝密钥泄露的发生。例如:

application.yml

spring:
  datasource:
    username: dbuser
    password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'

若是使用配置文件则加密数据不要加上双引号。例如:

application.properties

spring.datasource.username: dbuser
spring.datasource.password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ

这样就能够安全共享此文件,同时能够保护密钥。

这个服务经过/encrypt/decrypt端点向外暴露。这样就能够用过POST方式向/encrypt提交加密后的数据。例如:

$ curl localhost:8888/encrypt -d mysecret
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda

反过来也行,经过/decrypt安全提交数据。(前提是已经在服务端配置了相应的解密KEY)

$ curl localhost:8888/decrypt -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret

在提交以前,存放这些加密数据存在着潜在的不安全性。

/encrypt/decrypt 都接受一个路径/*/{name}/{profiles}用于分开控制每个应用的密码。

注意: 若是须要为每个应用使用不一样的密码,则须要一个@Bean产生一个TextEncryptorLocator对象来建立不一样的密钥对,并给它们赋予一个名字。固然这是可选的,默认不须要这样(全部应用使用相同的密钥)

Spring 命令行客户端(Spring Cloud CLI)也可使用加解密特性。例如:

$ spring encrypt mysecret --key foo
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret

可使用@来指定一个路径,包含一个存放加解密key 的文件。例如:

$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...

3.2.4 Key Management 密钥管理

Config Server 可使用对称/非对称加解密算法。使用非对称算法拥有更好的安全性,可是对称算法更方便。

配置对称算法的key,只须要设置encrypt.key就好了。(或者使用环境变量ENCRYPT_KEY

配置非对称算法key,你能够选择在encrypt.key中配置一个PEM编码的文本,也能够经过encrypt.keyStore.*配置使用一个密钥库。

encrypt.keyStore.*包括以下配置:

  • location 一个资源路径
  • password 密钥库密码
  • alias 被使用的密钥标识

经过公钥加密,私钥解密。所以,原则上能够在服务端只配置公钥。可是实践中可能不多这样作,密钥管理在所有客户端处理过程都会被包含,而不只仅是服务端。不过从另外一方面说,若是服务端 真的不安全,并且只有少数几个客户端须要加密处理,那这样配置也有必定的合理性。

3.2.4 Creating a Key Store for Testing 建立一个密钥库用于测试

能够经过以下配置来建立一个用于测试的密钥库:

$ 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文件放入classspath,而后在application.yml中进行如下配置:

encrypt:
  keyStore:
    location: classpath:/server.jks
    password: letmein
    alias: mytestkey
    secret: changeme

3.2.5 Using Multiple Keys and Key Rotation 使用多重密钥以及密钥轮换

经过添加{cipher}前缀来代表使用加密数据,系统会在对密文进行Base64解码以前寻找{name:value}前缀信息。密钥经过TextEncryptorLocator(不管哪一种)实例,最终使用TextEncryptor来完成加解密。 若是配置了密钥库(encrypt.keystore.location),那默认的执行器(locator)就会按照配置的alias去密钥库中查找相应的密钥。例如:

foo:
  bar: `{cipher}{key:testkey}...`

上例中执行器(locator)将会去查找一个叫作“testkey”的密钥。密钥库的密码能够经过{secret:…​}来指定,可是如非必要通常不指定。若是想使用密钥库密码,那建议使用定制SecretLocator对其加密处理。

若是只是对不多的配置数据进行加密的话,密钥轮换基本上没有必要。 可是,偶还仍是会有需求去修改密钥的场景。在这种状况下,全部的客户端都须要改变源配置文件(如:git)来使用新的{key:…​},最好还要事先检查密钥库中的密钥。

提示: {name:value}也能够在/encrypt数据请求时使用。

3.2.5 Serving Encrypted Properties 提供加密属性

有的时候须要客户端对配置数进行解密,而不是在服务端解密。这种状况下,仍然能够经过/encrypt/decrypt端点访问。那就须要明确指定配置数据在服务端发出时不解密:spring.cloud.config.server.encrypt.enabled=false。若是不关系端点访问,那就既不要配置密钥也不要开启此配置。

相关文章
相关标签/搜索