5. Spring Cloud Config 服务

Spring Cloud Config 服务提供了用于外部配置(名称-值对或等效的 YAML 内容)的基于 HTTP 资源的 API。服务器可以通过使用 @EnableConfigServer 注解嵌入到 Spring Boot 应用程序中。因此,下面的应用程序是配置服务器:

ConfigServer.java. 

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

像所有 Spring Boot 应用程序一样,默认情况下它在端口 8080上 运行,但是你可以以各种方式将其切换到更传统的端口 8888。设置默认配置存储库最简单的方法是使用 spring.config.name=configserver(配置服务器 jar 中有一个 configserver.yml)启动它。另一种方法是使用你自己的 application.properties,如下面的示例所示:

application.properties. 

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

其中 ${user.home}/config-repo 是一个包含 YAML 和 properties 文件的 git 存储库。

[Note] Note

在 Windows 上,如果文件 URL 具有驱动器前缀(例如,file:///${user.home}/config-repo),则需要在该文件 URL 中添加额外的 "/"。

[Tip] Tip

下面的列展示了在前面示例中创建 git 存储库的配方:

$ 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"
[Warning] Warning

使用 git 存储库的本地文件系统仅用于测试。你应该使用服务器来在生产中承载配置库。

[Warning] Warning

如果只保存文本文件,则配置库的初始克隆可以快速高效。如果存储二进制文件,尤其是大文件,则可能会遇到服务器上第一次配置请求或遇到内存错误的延迟。

5.1 环境存储库

你应该在哪里存储配置服务器的配置数据?管理这种行为的策略是 EnvironmentRepository,即服务 Environment 对象。此 Environment 是来自 Spring Environment 的域的浅拷贝(包括 propertySources 作为主要特征)。Environment 资源通过三个变量进行参数化:

  • {application},它映射到客户端上的 spring.application.name。
  • {profile},它映射到客户端上的 spring.profiles.active(逗号分隔列表)。
  • {label},它是一个服务器端特性,标记一个版本化的配置文件集。

存储库实现的行为通常类似于 Spring Boot 应用程序,从 spring.config.name 加载与 {application} 参数相等的配置文件,以及 spring.profiles.active 加载与 {profiles} 参数相等的配置文件。配置组的优先级规则也与常规 Spring Boot 应用程序中的相同:激活的配置组优先于默认配置,如果有多个配置组,则最后一个配置组胜出(类似于向 Map 添加条目)。

下面的示例客户端应用程序具有这种引导配置:

bootstrap.yml. 

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

(与通常的 Spring Boot 应用一样,这些属性也可以由环境变量或命令行参数设置)。

如果存储库是基于文件的,则服务器从 application.yml(在所有客户端之间共享)和 foo.yml(foo.yml 优先)创建一个 Environment。如果 YAML 文件中包含指向 Spring 配置组的文件,则这些文件将具有更高的优先级(按照列出的配置组的顺序)。如果有配置组特定的 YAML(或 properties)文件,这些文件的应用优先级也高于默认值。更高的优先级转换为在 Environment 中更早列出的 PropertySource。(这些规则适用于独立的 Spring Boot 应用程序。)

你可以将 spring.cloud.config.server.accept-empty 设置为 false,这样如果找不到应用,服务器将返回 HTTP 404 状态。

5.1.1 Git 后台

EnvironmentRepository 的默认实现使用 Git 后台,这非常方便管理升级和物理环境以及审计更改。要更改存储库的位置,你可以在配置服务器中设置 spring.cloud.config.server.git.uri 配置属性(例如,在 application.yml 中)。如果你使用 file: 前缀设置它,那么它应该在本地存储库中工作,这样你就可以在没有服务器的情况下快速轻松地启动。但是,在这种情况下,服务器直接在本地存储库上操作,而不对其进行克隆(如果不是单独的,这无关紧要,因为配置服务器从不对远程存储库进行更改)。为了扩展配置服务器并使其高度可用,你需要让服务器的所有实例指向相同的存储库,因此只有共享文件系统才能工作。即使在这种情况下,最好为共享文件系统存储库使用 ssh: 协议,以便服务器可以克隆它并使用本地工作副本作为缓存。

此存储库实现将 HTTP 资源的 {label} 参数映射到 git 标签(提交 id、分支名称或标签)。如果 git 分支或标记名包含斜杠 (/),那么 HTTP URL 中的标签应该改为使用特殊字符串 (_) 指定(以避免与其他 URL 路径产生歧义)。例如,如果标签为 foo/bar,则替换斜杠的结果是以下标签:foo(_)bar。特殊字符串 (_) 的包含也可以应用于 {application} 参数。如果使用命令行客户端(如 curl),则要小心使用 URL 中的括号 — 应该使用单引号 ('') 将它们从 shell 中转义。

跳过 SSL 证书验证

通过将 git.skipSslValidation 属性设置为 true(默认为 false),可以禁用配置服务器对 Git 服务器的 SSL 证书的验证。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          skipSslValidation: true

设置 HTTP 连接超时

你可以配置配置服务器等待获取 HTTP 连接的时间,以秒为单位。使用 git.timeout 属性。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          timeout: 4

Git URI 中的占位符

Spring Cloud Config 服务器支持带有 {application} 和 {profile}(以及 {label} 占位符的 git 存储库 URL,如果你需要的话,请记住,标签是作为 git 标签应用的)。因此,你可以通过使用与以下类似的结构来支持“每个应用程序一个存储库”策略:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/myorg/{application}

你还可以使用类似的模式支持“每个配置组一个存储库”策略,但是使用 {profile}。

此外,使用 {application} 参数中的特殊字符串 "(_)" 可以支持多个组织,如下面的示例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/{application}

{application} 在请求时以以下格式提供:organization(_)application。

模式匹配与多个存储库

Spring Cloud Config 还包括对应用程序和配置组名称进行模式匹配的更复杂需求的支持。模式格式是带有通配符的 {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。在上面的示例中,对于 “simple” 存储库,模式是 simple/*(它只匹配一个在所有配置组中名为 simple 的应用)。“local” 存储库匹配所有配置组中以 local 开头的所有应用名称(将 /* 后缀自动添加到没有配置组匹配器的任何模式中)。

[Note] Note

只有在要设置的唯一属性是 URI 时,才能使用 “simple” 示例中使用的 “one-liner” 快捷方式。如果需要设置其他内容(凭据、模式等),则需要使用完整的表单。

repo 中的 pattern 属性实际上是一个数组,因此可以使用 YAML 数组(或属性文件中的 [0]、[1] 等后缀)绑定到多个模式。如果要运行具有多个配置文件的应用程序,可能需要这样做,如下面的示例所示:

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
[Note] Note

Spring Cloud 猜测一种模式包含的一个配置组不会以 * 结尾,这意味着你实际上是想匹配一组以该模式开头的配置组(因此 */staging 是 ["*/staging", "*/staging,*"] 等的快捷方式)。这种情况很常见,例如,你需要在 “development” 配置组中本地运行应用程序,但也需要在 “cloud” 配置组中远程运行应用程序。

每个存储库还可以选择性地将配置文件存储在子目录中,并且搜索这些目录的模式可以指定为 searchPaths。下面的示例展示了顶层的配置文件:

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 的 config-repo,然后接受任何请求。在请求来自存储库的配置之前,不会克隆所有其他存储库。

[Note] Note

在 Config Server 启动时设置要克隆的存储库可以帮助在 Config Server 启动时快速识别配置错误的配置源(例如无效的存储库 URI)。在配置源未启用 cloneOnStart 的情况下,Config Server 可能以配置错误或无效的配置源成功启动,并且直到应用程序请求来自该配置源的配置时才检测到错误。

认证

要在远程存储库上使用 HTTP 基本身份验证,请分别添加 username 和 password 属性(不在 URL 中),如下面的示例所示:

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

如果不使用 HTTPS 和用户凭证,则在默认目录(~/.ssh)中存储密钥,并且 URI 指向 SSH 位置(如 git@github.com:configuration/cloud-configuration。Git 服务器的条目必须出现在 ~/.ssh/known_hosts 文件中,并且是 ssh-rsa 格式的。不支持其他格式(例如 ecdsa-sha2-nistp256)。为了避免意外,你应该确保 Git 服务器的 known_hosts 文件中只存在一个条目,并且它与你提供给配置服务器的 URL 相匹配。如果在 URL 中使用主机名,则需要在 known_hosts 文件中完全使用主机名(而不是 IP)。通过使用 JGit 访问存储库,因此你找到的任何文档都应该适用。HTTPS 代理设置可以在 ~/.git/config 中设置,或者(以与任何其他 JVM 进程相同的方式)使用系统属性(-Dhttps.proxyHost 和 -Dhttps.proxyPort)设置。

[Tip] Tip

如果不知道 ~/.git 目录在哪里,可以使用 git config --global 来操作设置(例如,git config --global http.sslVerify false)。

使用 AWS CodeCommit 进行认证

Spring Cloud Config 服务还支持 AWS CodeCommit 认证。当从命令行使用 Git 时,AWS CodeCommit 使用认证助手。此助手不与 JGit 库一起使用,因此如果 Git URI 与 AWS CodeCommit 模式匹配,则创建用于 AWS CodeCommit 的 JGit CredentialProvider。AWS CodeCommit URI 遵循以下模式://git-codecommit.${AWS_REGION}.amazonaws.com/${repopath}。

如果使用 AWS CodeCommit URI 提供用户名和密码,则它们必须是提供对存储库访问的 AWS accessKeyId 和 secretAccessKey。如果没有指定用户名和密码,则使用 AWS 默认凭证提供程序链检索 accessKeyId 和 secretAccessKey。

如果 Git URI 与 CodeCommit URI 模式匹配(如前所示),则必须在用户名和密码中或在默认凭证提供程序链支持的位置之一中提供有效的 AWS 凭证。AWS EC2 实例可以为 EC2 实例使用 IAM 角色。

[Note] Note

aws-java-sdk-core jar 是一个可选的依赖项。如果 aws-java-sdk-core jar 不在类路径上,则不创建 AWS 代码提交凭据提供程序,而不管 GIT 服务器 URI。

使用属性配置 Git SSH

默认情况下,Spring Cloud Config 服务使用的 JGit 库在使用 SSH URI 连接到 Git 存储库时使用 SSH 配置文件,如 ~/.ssh/known_hosts 和 /etc/ssh/ssh_config。在云环境(如 Cloud Foundry)中,本地文件系统可能是短暂的或者不容易访问的。对于这些情况,可以使用 Java 属性设置 SSH 配置。为了激活基于属性的 SSH 配置,必须将 spring.cloud.config.server.git.ignoreLocalSshSettings 属性设置为 true,如下面的示例所示:

  spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true
            hostKey: someHostKey
            hostKeyAlgorithm: ssh-rsa
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----

下表描述了 SSH 配置属性。

表格 5.1. SSH 配置属性

属性名称 评论

ignoreLocalSshSettings

如果为 true,则使用基于属性的而不是基于文件的 SSH 配置。必须设置为 spring.cloud.config.server.git.ignoreLocalSshSettings,而不是在存储库定义中。

privateKey

有效的 SSH 私钥。如果 ignoreLocalSshSettings 为 true,Git URI 为 SSH 格式,则必须进行设置。

hostKey

有效的 SSH 主机密钥。如果还设置了 hostKeyAlgorithm,则必须进行设置。

hostKeyAlgorithm

ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521 之一。如果还设置了 hostKey,则必须设置。

strictHostKeyChecking

true 或者 false。如果为 false,则使用 host 键忽略错误。

knownHostsFile

自定义 .known_hosts 文件的位置。

preferredAuthentications

重写服务器认证方法顺序。如果服务器在 publickey 方法之前具有键盘交互式身份验证,则应该允许避免登录提示。


Git 搜索路径中的占位符

Spring Cloud Config 服务还支持 {application} 和 {profile}(以及 {label} 的搜索路径,如果需要的话),如下面的示例所示:

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

前面的清单在存储库中搜索与目录(以及顶层)同名的文件。通配符在具有占位符的搜索路径中也是有效的(搜索中包括任何匹配的目录)。

强制拉取 Git 存储库

如前所述,在本地副本变脏(例如,OS 进程更改文件夹内容)的情况下,Spring Cloud Config 服务对远程 git 存储库进行克隆,使得 Spring Cloud Config 服务无法从远程存储库更新本地副本。

为了解决此问题,有一个 force-pull 属性,如果本地副本是脏的,则使 Spring Cloud Config 服务从远程存储库强制拉取,如下面的示例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          force-pull: true

如果具有多个存储库配置,则可以配置每个存储库的 force-pull 属性,如下面的示例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://git/common/config-repo.git
          force-pull: true
          repos:
            team-a:
                pattern: team-a-*
                uri: http://git/team-a/config-repo.git
                force-pull: true
            team-b:
                pattern: team-b-*
                uri: http://git/team-b/config-repo.git
                force-pull: true
            team-c:
                pattern: team-c-*
                uri: http://git/team-a/config-repo.git
[Note] Note

force-pull 属性的默认值是 false。

删除 Git 存储库中未跟踪的分支

由于 Spring Cloud Config 服务在将分支签出到本地 repo(例如通过标签获取属性)之后具有远程 git 存储库的克隆,因此它将永远保留这个分支或者直到下一次服务器重新启动(创建新的本地 repo)。因此,可能存在远程分支被删除但本地副本仍然可用于获取的情况。如果 Spring Cloud Config 服务客户端服务以 --spring.cloud.config.label=deletedRemoteBranch,master 开始,则主服务器将从 deletedRemoteBranch 本地分支而不是从 master 获取属性。

为了保持本地存储库分支的整洁以及从远程更新 - 可以设置 deleteUntrackedBranches 属性。它将使 Spring Cloud Config 服务强制从本地存储库中删除未跟踪的分支。例如:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          deleteUntrackedBranches: true
[Note] Note

deleteUntrackedBranches 属性的默认值是 false。

Git 刷新频率

可以使用 spring.cloud.config.server.git.refreshRate 控制配置服务器从 Git 后台获取更新的配置数据的频率。此属性的值以秒为单位指定。默认情况下,值为 0,这意味着配置服务器将在每次请求 Git repo 时从 Git repo 获取更新的配置。

5.1.2 版本控制后台文件系统的使用

[Warning] Warning

使用基于 VCS 的后台(git、svn),文件被签出或克隆到本地文件系统。默认情况下,它们放在系统临时目录中,前缀为 config-repo-。例如,在 linux 上,它可以是 /tmp/config-repo-<randomid>。一些操作系统通常清除临时目录。这可能导致意外的行为,例如缺少属性。为了避免这个问题,通过将 spring.cloud.config.server.git.basedir 或 spring.cloud.config.server.svn.basedir 设置为不驻留在系统临时结构中的目录,来更改配置服务使用的目录。

5.1.3 文件系统后台

配置服务中还有一个 “native” 配置组,它不使用 Git,而是从本地类路径或文件系统(你想要用 spring.cloud.config.server.native.searchLocations 指向的任何静态 URL)加载配置文件。要使用本地配置文件,请使用 spring.profiles.active=native 启动配置服务。

[Note] Note

记住为文件资源使用 file: 前缀(没有前缀的默认值通常是类路径)。与任何 Spring Boot 配置一样,你可以嵌入 ${} 样式的环境占位符,但请记住,Windows 中的绝对路径需要额外的 /(例如,file:///${user.home}/config-repo)。

[Warning] Warning

searchLocations 的默认值与本地 Spring Boot 应用程序(即,[classpath:/, classpath:/config, file:./, file:./config])相同。这不会将 application.properties 从服务器公开给所有客户端,因为服务器中存在的任何属性源在发送给客户端之前都被删除。

[Tip] Tip

文件系统后台非常适合快速启动和测试。为了在生产中使用它,你需要确保文件系统是可靠的,并且跨配置服务的所有实例共享。

搜索位置可以包含 {application}、{profile} 和 {label} 的占位符。通过这种方式,你可以分离路径中的目录,并选择对你有意义的策略(例如每个应用程序的子目录或每个配置文件的子目录)。

如果在搜索位置中不使用占位符,则此存储库还将 HTTP 资源的 {label} 参数附加到搜索路径上的后缀,以便从每个搜索位置加载属性文件,并从子目录加载具有与标签相同名称的属性文件(在 Spring 环境中标记的属性优先)。因此,没有占位符的默认行为与添加以 /{label}/ 结尾的搜索位置相同。例如,file:/tmp/config 与 file:/tmp/config,file:/tmp/config/{label} 相同。可以通过设置 spring.cloud.config.server.native.addLabelLocations=false 来禁用此行为。

5.1.4 Vault 后台

Spring Cloud Config 服务还支持 Vault 作为后台。

Vault 是一种安全访问机密的工具。机密是你想要严格控制访问的任何内容,例如 API 密钥、密码、证书和其他敏感信息。Vault 提供对任何机密的统一接口,同时提供严格的访问控制和记录详细的审计日志。

有关 Vault 的更多详细信息,请参阅 Vault 快速入门指南。

要使配置服务器能够使用 Vault 后台,可以使用 vault 配置组运行配置服务。例如,在配置服务的 application.properties 中,可以添加 spring.profiles.active=vault。

默认情况下,配置服务假定你的 Vault 服务器在 http://127.0.0.1:8200 上运行。它还假设后台的名称是 secret 的,而值是 application。可以在配置服务的 application.properties 中配置所有这些默认设置。下表描述可配置的 Vault 属性:

名称 默认值

host

127.0.0.1

port

8200

scheme

http

backend

secret

defaultKey

application

profileSeparator

,

kvVersion

1

skipSslValidation

false

timeout

5

[Important] 重点

前面表格中的所有属性都必须以 spring.cloud.config.server.vault 作为前缀。

所有可配置的属性都可以在 org.springframework.cloud.config.server.environment.VaultEnvironmentRepository 中找到。

Vault 0.10.0 引入了版本化的键值后台(k/v backend version 2),与早期版本相比,它公开了不同的 API,现在它需要在挂载路径和实际上下文路径之间提供 data/ 并将机密封装在 data 对象中。设置 kvVersion=2 将考虑这一点。

在运行配置服务之后,你可以向服务发出 HTTP 请求,以便从 Vault 后台检索值。为此,你需要 Vault 服务器的令牌。

首先,将一些数据放入 Vault,如下面的示例所示:

$ vault kv put secret/application foo=bar baz=bam
$ vault kv put secret/myapp foo=myappsbar

其次,向配置服务器发出 HTTP 请求以检索这些值,如下面的示例所示:

$ curl -X "GET" "http://localhost:8888/myapp/default" -H "X-Config-Token: yourtoken"

你应该会看到类似于以下内容的响应:

{
   "name":"myapp",
   "profiles":[
      "default"
   ],
   "label":null,
   "version":null,
   "state":null,
   "propertySources":[
      {
         "name":"vault:myapp",
         "source":{
            "foo":"myappsbar"
         }
      },
      {
         "name":"vault:application",
         "source":{
            "baz":"bam",
            "foo":"bar"
         }
      }
   ]
}

多个属性源

使用 Vault 时,可以为应用程序提供多个属性源。例如,假设你已经将数据写入了 Vault 中的以下路径:

secret/myApp,dev
secret/myApp
secret/application,dev
secret/application

写入到 secret/application 的属性可用于使用配置服务的所有应用程序。名称为 myApp 的应用程序将具有写入 secret/myApp 和 secret/application的任何属性。当 myApp 启用了 dev 配置组时,写入上述所有路径的属性都可用,列表中第一路径中的属性优先于其他路径。

5.1.5 通过代理访问后台

配置服务器可以通过 HTTP 或 HTTPS 代理访问 Git 或 Vault 后台。通过 proxy.http 和 proxy.https 下的设置来控制 Git 或 Vault 的这种行为。这些设置是针对每个存储库的,因此如果使用复合环境存储库,则必须为复合中的每个后台分别配置代理设置。如果使用需要单独的 HTTP 和 HTTPS URL 代理服务器的网络,则可以为单个后台配置 HTTP 和 HTTPS 代理设置。

下表描述了 HTTP 和 HTTPS 代理的代理配置属性。所有这些属性必须以 proxy.http 或 proxy.https。

表格 5.2. 代理配置属性

属性名称 讨论

host

代理的主机。

port

访问代理的端口。

nonProxyHosts

配置服务在代理外部访问的任何主机。如果同时为 proxy.http.nonProxyHosts 和 proxy.https.nonProxyHosts 提供值,则将使用 proxy.http 的值。

username

用于向代理进行身份验证的用户名。如果同时为 proxy.http.nonProxyHosts 和 proxy.https.nonProxyHosts 提供值,则将使用 proxy.http 的值。

password

用于向代理进行身份验证的密码。如果同时为 proxy.http.nonProxyHosts 和 proxy.https.nonProxyHosts 提供值,则将使用 proxy.http 的值。


以下配置使用 HTTPS 代理访问 Git 存储库。

spring:
  profiles:
    active: git
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          proxy:
            https:
              host: my-proxy.host.io
              password: myproxypassword
              port: '3128'
              username: myproxyusername
              nonProxyHosts: example.com

5.1.6 与所有应用程序共享配置

所有应用程序之间的共享配置根据所采用的方法而不同,如以下主题所述:

  • 名为 “基于文件的存储库” 的部分
  • 名为 “Vault 服务” 的部分

基于文件的存储库

使用基于文件的(git、svn 和本地)存储库,所有客户端应用程序之间共享具有 application*(application.properties、application.yml、application-*.properties 等)文件名中的资源。可以使用具有这些文件名的资源来配置全局缺省值,并根据需要让应用程序特定的文件覆盖它们。

#_property_overrides[property overrides] 特性还可以用于设置全局默认值,允许使用占位符以便应用程序在本地覆盖它们。

[Tip] Tip

对于 “native” 配置组(本地文件系统后台),应该使用不属于服务器自身配置的显式搜索位置。否则,默认搜索位置中的 application* 资源将被删除,因为它们是服务器的一部分。

Vault 服务

当使用 Vault 作为后台时,可以通过将配置置于 secret/application 中来与所有应用程序共享配置。例如,如果运行以下 Vault 命令,则使用配置服务器的所有应用程序都将具有可用于它们的属性 foo 和 baz:

$ vault write secret/application foo=bar baz=bam

5.1.7 JDBC 后台

Spring Cloud Config 服务支持 JDBC(关系数据库)作为配置属性的后台。可以通过将 spring-jdbc 添加到类路径并使用 jdbc 配置组或通过添加 JdbcEnvironmentRepository 类型的 bean 来启用该特性。如果在类路径中包括正确的依赖项(有关此的更多详细信息,请参阅用户指南),Spring Boot 将配置数据源。

数据库需要有一个名为 PROPERTIES 的表,其中有称为 APPLICATION、PROFILE 和 LABEL 的列(具有通常的 Environment 含义),以及 Properties 样式中的键和值对的 KEY 和 VALUE。所有字段都是 Java 中的 String 类型,因此你可以将它们按需要长度指定为 VARCHAR。如果属性值来自名为 {application}-{profile}.properties 的 Spring Boot 属性文件,包括所有加密和解密,则这些属性值以相同的方式工作,这些加密和解密将作为后处理步骤(即,不直接在存储库实现中)应用。

5.1.8 CredHub 后台

Spring Cloud Config 服务支持 CredHub 作为配置属性的后台。你可以通过向 Spring CredHub 添加依赖项来启用该特性。

pom.xml. 

<dependencies>
	<dependency>
		<groupId>org.springframework.credhub</groupId>
		<artifactId>spring-credhub-starter</artifactId>
	</dependency>
</dependencies>

以下配置使用共用 TLS 访问 CredHub:

spring:
  profiles:
    active: credhub
  cloud:
    config:
      server:
        credhub:
          url: https://credhub:8844

这些属性应该存储为 JSON,例如:

credhub set --name "/demo-app/default/master/toggles" --type=json
value: {"toggle.button": "blue", "toggle.link": "red"}
credhub set --name "/demo-app/default/master/abs" --type=json
value: {"marketing.enabled": true, "external.enabled": false}

所有名为 spring.cloud.config.name=demo-app 的客户端应用程序都将具有以下可用属性:

{
    toggle.button: "blue",
    toggle.link: "red",
    marketing.enabled: true,
    external.enabled: false
}
[Note] Note

当没有指定配置组时,将使用 default,当没有指定标签时,将使用 master 为默认值。

OAuth 2.0

可以使用 UAA 作为提供者使用 OAuth 2.0 进行身份验证。

pom.xml. 

<dependencies>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-oauth2-client</artifactId>
	</dependency>
</dependencies>

以下配置使用 OAuth 2.0 和 UAA 访问 CredHub:

spring:
  profiles:
    active: credhub
  cloud:
    config:
      server:
        credhub:
          url: https://credhub:8844
          oauth2:
            registration-id: credhub-client
  security:
    oauth2:
      client:
        registration:
          credhub-client:
            provider: uaa
            client-id: credhub_config_server
            client-secret: asecret
            authorization-grant-type: client_credentials
        provider:
          uaa:
            token-uri: https://uaa:8443/oauth/token
[Note] Note

使用的 UAA client-id 应该具有 credhub.read 作为范围。

5.1.9 复合环境存储库

在某些情况下,你可能希望从多个环境存储库中提取配置数据。为此,可以在配置服务器的应用程序属性或 YAML 文件中启用 composite 配置组。例如,如果希望从 Subversion 存储库以及两个 Git 存储库中提取配置数据,可以为配置服务器设置以下属性:

spring:
  profiles:
    active: composite
  cloud:
    config:
      server:
        composite:
        -
          type: svn
          uri: file:///path/to/svn/repo
        -
          type: git
          uri: file:///path/to/rex/git/repo
        -
          type: git
          uri: file:///path/to/walter/git/repo

使用此配置,优先级由 composite 键下列出存储库的顺序决定。在上面的示例中,首先列出了 Subversion 存储库,因此在 Subversion 存储库中找到的值将覆盖其中一个 Git 存储库中为同一属性找到的值。在 rex Git 存储库中找到的值将在为 walter Git 存储库中的相同属性找到的值之前使用。

如果只想从存储库中获取配置数据,这些存储库是各种不同类型的,那么可以在配置服务器的应用程序属性或 YAML 文件中启用相应的配置文件,而不是 composite 配置组。例如,如果希望从单个 Git 存储库和单个 HashiCorp Vault 服务器提取配置数据,可以为配置服务器设置以下属性:

spring:
  profiles:
    active: git, vault
  cloud:
    config:
      server:
        git:
          uri: file:///path/to/git/repo
          order: 2
        vault:
          host: 127.0.0.1
          port: 8200
          order: 1

使用此配置,优先级可以由 order 属性确定。可以使用 order 属性指定所有存储库的优先顺序。order 属性的数值越低,其优先级越高。存储库的优先级顺序有助于解决包含相同属性值的存储库之间的任何潜在冲突。

[Note] Note

如果复合环境像前面的示例那样包含 Vault 服务器,则必须在向配置服务器发出的每个请求中包括 Vault 令牌。参见 Vault 后台。

[Note] Note

当从环境存储库检索值时,任何类型的失败都会导致整个复合环境的失败。

[Note] Note

当使用复合环境时,所有存储库都包含相同的标签非常重要。如果你的环境与前面示例中的环境类似,并且使用 master 标签请求配置数据,但是 Subversion 存储库不包含名为 master 的分支,则整个请求失败。

自定义复合环境存储库

除了使用 Spring Cloud 的环境存储库之一,你还可以提供你自己的 EnvironmentRepository bean 作为复合环境的一部分被包含。为此,你的 bean 必须实现 EnvironmentRepository 接口。如果希望在复合环境中控制自定义 EnvironmentRepository 的优先级,还应该实现 Ordered 接口并重写 getOrdered 方法。如果不实现 Ordered 接口,则 EnvironmentRepository 具有最低的优先级。

5.1.10 属性重写

配置服务有一个 “overrides” 特性,允许操作员向所有应用程序提供配置属性。使用普通 Spring Boot 勾子的应用程序不能意外更改重写的属性。要声明重写,请向 spring.cloud.config.server.overrides 添加 name-value 的映射,如下面的示例所示:

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

前面的示例使所有配置客户端的应用程序读取 foo=bar,这与它们自己的配置无关。

[Note] Note

配置系统不能强制应用程序以任何特定方式使用配置数据。因此,重写是不可执行的。然而,它们确实为 Spring Cloud Config 客户端提供了有用的默认行为。

[Tip] Tip

通常,${} 的 Spring 环境占位符可以通过使用反斜杠(\)来转义 $ 或 {。例如,\${app.foo:bar} 解析为 bar,除非应用程序提供自己的 app.foo。

[Note] Note

在 YAML 中,你不需要转义反斜杠本身。但是,在属性文件中,在配置服务器上的重写时,确实需要转义反斜杠。

可以通过在远程存储库中设置 spring.cloud.config.overrideNone=true 标志(默认为false),将客户端中所有重写的优先级更改为更像默认值,让应用程序在环境变量或系统属性中提供自己的值。

5.2 健康指标

配置服务附带了一个健康指标,用于检查配置的 EnvironmentRepository 是否工作。默认情况下,它向 EnvironmentRepository 请求名为 app 的应用程序、default 配置组和 EnvironmentRepository 实现提供的默认标签。

你可以配置健康指标来检查更多应用程序,以及自定义配置组和自定义标签,如下面的示例所示:

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

可以通过设置 spring.cloud.config.server.health.enabled=false 禁用健康指标。

5.3 安全性

你可以以对你有意义的任何方式(从物理网络安全到 OAuth2 承载令牌)来保护配置服务,因为 Spring Security 和 Spring Boot 提供了对许多安全安排的支持。

要使用默认的 Spring Boot 配置的 HTTP 基本安全性,在类路径中包括 Spring Security(例如,通过 spring-boot-starter-security)。默认值是用户的用户名和随机生成的密码。在实践中,随机密码是没有用的,因此我们建议你配置密码(通过设置 spring.security.user.password)并对其进行加密(有关如何执行此操作的说明,请参阅下文)。

5.4 加密和解密

[Important] 重点

要使用加密和解密特性,你需要在 JVM 中安装全强度 JCE(默认情况下不包括它)。你可以从 Oracle 下载 “Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files” 并遵循安装说明(基本上,你需要用 JRE lib/security 目录中的两个策略文件替换所下载的文件)。

如果远程属性源包含加密的内容(以 {cipher} 开始的值),则在通过 HTTP 发送给客户端之前对其进行解密。这种设置的主要优点是,当属性值 “atrest”(例如,在 git 存储库中)时,它们不需要是纯文本。如果某个值不能被解密,则从属性源中删除该值,并且添加附加的属性具有相同的密钥,但前缀为 invalid,并且该值表示 “不适用”(通常 <n/a>)。这主要是为了防止密码文本被用作密码并意外泄漏。

如果为配置客户机应用程序设置远程配置存储库,那么它可能包含类似于以下内容的 application.yml:

application.yml. 

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

.properties 文件中的加密值不能用引号包装。否则,该值不被解密。下面的示例展示了可以工作的值:

application.properties. 

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

可以将此纯文本安全地推送到共享 git 存储库,并且保密密码仍然受到保护。

服务器还公开 /encrypt 和 /decrypt 端点(假设这些端点是安全的,并且仅由授权代理访问)。如果编辑远程配置文件,则可以使用配置服务通过 POSTing 到 /encrypt 端点来加密值,如下面的示例所示:

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

如果加密的值中有需要 URL 编码的字符,则应该使用 --data-urlencode 选项进行 curl 以确保正确编码。

[Tip] Tip

确保加密值中不包含任何 curl 命令统计信息。将值输出到文件可以帮助避免这个问题。

逆操作也可以通过 /decrypt(如果服务器被配置为对称密钥或全密钥对)得到,如下面的示例所示:

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

如果使用 curl 进行测试,则使用 --data-urlencode(而不是 -d)或设置显式的 Content-Type: text/plain 以确保当有特殊字符('+' 特别棘手)时,curl 正确地编码数据。

在将 {cipher} 前缀放入 YAML 或 properties 文件之前,以及提交之前,获取加密值并添加它,并将其推送到远程(可能不安全)存储。

/encrypt 和 /decrypt 端点还接受 /*/{name}/{profiles} 形式的路径,当客户端调用主环境资源时,这些路径可用于根据每个应用程序(名称)和每个配置组控制加密。

[Note] Note

为了以这种粒度的方式控制加密,还必须提供一个 TextEncryptorLocator 类型的 @Bean,它为每个名称和配置组创建不同的加密器。默认情况下提供的加密不会这样做(所有加密都使用相同的密钥)。

spring 命令行客户端(安装了 Spring Cloud CLI 扩展)也可以用于加密和解密,如下面的示例所示:

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

若要在文件中使用密钥(例如用于加密的 RSA 公钥),请在密钥值前面加上 "@",并提供文件路径,如下面的示例所示:

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

--key 参数是强制性的(尽管有 -- 前缀)。

5.5 密钥管理

配置服务器可以使用对称(共享)密钥或非对称密钥(RSA 密钥对)。非对称选择在安全性方面是优越的,但是使用对称密钥通常更方便,因为它是在 bootstrap.properties 中配置的单个属性值。

要配置对称密钥,你需要将 encrypt.key 设置为 secret String(或者使用 ENCRYPT_KEY 环境变量使其不受纯文本配置文件的影响)。

[Note] Note

不能使用 encrypt.key 配置非对称密钥。

要配置非对称密钥,可以使用密钥存储库(例如,由 JDK 附带的 keytool 实用程序创建)。keystore 属性是 encrypt.keyStore.* 的 *

属性 描述

encrypt.keyStore.location

包含 Resource 的位置

encrypt.keyStore.password

保存解锁密钥库的密码。

encrypt.keyStore.alias

标识要在存储区中使用的密钥

加密用公钥完成,解密需要私钥。因此,原则上,如果仅希望加密(并且准备使用私钥在本地解密值),则只能配置服务器中的公钥。在实践中,你可能不想在本地进行解密,因为它将密钥管理过程分散在所有客户端周围,而不是将其集中在服务器中。另一方面,如果你的配置服务器相对不安全,并且只有少数客户端需要加密的属性,那么它可以是一个有用的选项。

5.6 创建用于测试的密钥存储

要创建用于测试的密钥存储库,可以使用以下命令:

$ 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 文件放在类路径中(例如),然后在 bootstrap.yml 中,为配置服务创建以下设置:

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

5.7 使用多个密钥及循环密钥

除了加密属性值中的 {cipher} 前缀外,配置服务器还会在(Base64 编码)密码文本开始之前查找零个或多个 {name:value} 前缀。密钥被传递给一个 TextEncryptorLocator,它可以做任何需要的逻辑来定位密码的 TextEncryptor。如果已配置密钥库(encrypt.keystore.location),默认定位器将查找具有 key 前缀提供的别名的密钥,其密码文本类似于以下内容:

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

定位器查找名为 "testkey" 的密钥。也可以通过在前缀中使用 {secret:…​} 值来提供秘密。但是,如果没有提供,则默认使用密钥存储库密码(这是构建密钥存储库时获得的密码,并且不指定机密)。如果确实提供了机密,还应该使用自定义 SecretLocator 对机密进行加密。

当密钥仅用于对配置数据的几个字节进行加密时(也就是说,它们不在别处使用),基于密码学的理由,密钥循环几乎从来都不是必需的。但是,你可能偶尔需要更改密钥(例如,在安全性被破坏的情况下)。在这种情况下,所有客户端将需要更改它们的源配置文件(例如,在 git 中),并在所有密码中使用新的 {key:…​} 前缀。注意,客户端需要首先检查密钥别名在配置服务密钥存储区中是否可用。

[Tip] Tip

如果想让配置服务处理所有加密和解密,还可以将 {name:value} 前缀作为纯文本添加到 /encrypt 端点。

5.8 服务加密属性

有时你希望客户端在本地解密配置,而不是在服务器中进行配置。在这种情况下,如果提供 encrypt.* 配置来定位密钥,仍然可以拥有 /encrypt 和 /decrypt 端点,但是需要通过将 spring.cloud.config.server.encrypt.enabled=false 放入 bootstrap.[yml|properties] 显式地关闭传出属性的解密。如果不关心端点,当你不配置键或启用标志,则应该可以正常工作。