5. Spring Cloud Config 服务器

Spring Cloud Config Server 为外部配置(名称-值对或等效的 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(在 Config Server 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 和属性文件的 git 存储库。

Note

在 Windows 上,如果文件 URL 带有驱动器前缀(例如file:///${user.home}/config-repo)是绝对的,则在文件 URL 中需要一个额外的“ /”。

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

将本地文件系统用于 git 存储库仅用于测试。您应该使用服务器在生产环境中托管配置存储库。

Warning

如果仅在其中存储文本文件,则配置存储库的初始克隆可以快速有效。如果存储二进制文件(尤其是大文件),则可能会在首次配置请求时遇到延迟,或者在服务器中遇到内存不足错误。

5.1 环境存储库

您应该在哪里存储配置服务器的配置数据?控制此行为的策略是EnvironmentRepository,提供Environment对象。此Environment是 Spring Environment的域的浅表副本(包括propertySources作为主要 Feature)。 Environment资源由三个变量参数化:

  • {application},它 Map 到 Client 端的spring.application.name

  • {profile},它 Map 到 Client 端上的spring.profiles.active(以逗号分隔的列表)。

  • {label},这是服务器端功能,标记了一组“版本化”的配置文件。

仓库实现通常表现得像一个 Spring Boot 应用程序,从等于{application}参数的spring.config.name和等于{profiles}参数的spring.profiles.active加载配置文件。配置文件的优先级规则也与常规 Spring Boot 应用程序中的规则相同:Active配置文件优先于默认配置,如果有多个配置文件,则最后一个优先(类似于将条目添加到Map)。

以下示例 Client 端应用程序具有此引导程序配置:

bootstrap.yml.

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

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

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

您可以将 spring.cloud.config.server.accept-empty 设置为 false,以便如果找不到应用程序,则 Server 将返回 HTTP 404 状态。默认情况下,此标志设置为 true。

5.1.1 Git 后端

EnvironmentRepository的默认实现使用 Git 后端,这对于 Management 升级和物理环境以及审核更改非常方便。要更改存储库的位置,可以在 Config Server 中设置spring.cloud.config.server.git.uri配置属性(例如,在application.yml中)。如果使用file:前缀进行设置,则它应在本地存储库中运行,以便无需服务器即可快速轻松地开始使用。但是,在这种情况下,服务器无需克隆就可以直接在本地存储库上运行(它是否裸露并不重要,因为 Config Server 从不对“远程”存储库进行更改)。要扩展 Config Server 并使其高度可用,您需要使服务器的所有实例都指向同一存储库,因此仅共享文件系统可以工作。即使在那种情况下,最好对共享文件系统存储库使用ssh:协议,以便服务器可以克隆它并使用本地工作副本作为缓存。

此存储库实现将 HTTP 资源的{label}参数 Map 到 git 标签(提交 ID,分支名称或标签)。如果 git 分支或标记名称包含斜杠(/),则应使用特殊字符串(_)在 HTTP URL 中指定标签(以避免与其他 URL 路径产生歧义)。例如,如果标签为foo/bar,则替换斜杠将产生以下标签:foo(_)bar。特殊字符串(_)的包含内容也可以应用于{application}参数。如果使用 curl 之类的命令行 Client 端,请注意 URL 中的括号-应当使用单引号('')将其从 Shell 中移出。

跳过 SSL 证书验证

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

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

设置 HTTP 连接超时

您可以配置配置服务器将 await 获取 HTTP 连接的时间(以秒为单位)。使用git.timeout属性。

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

Git URI 中的占位符

Spring Cloud Config Server 支持带有{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下定义的默认 URI。在上面的示例中,对于“简单”存储库,模式为simple/*(在所有配置文件中仅匹配名为simple的一个应用程序)。 “本地”存储库与所有概要文件中以local开头的所有应用程序名称匹配(后缀/*自动添加到没有概要文件匹配器的任何模式中)。

Note

仅当要设置的唯一属性是 URI 时,才可以使用“简单”示例中使用的“单线”快捷方式。如果您需要设置其他任何内容(凭证,模式等),则需要使用完整表格。

存储库中的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

Spring Cloud 猜测包含不以*结尾的配置文件的模式意味着您实际上要匹配以该模式开头的配置文件列表(因此*/staging["*/staging", "*/staging,*"]的快捷方式,依此类推)。例如,这很普遍,例如,您需要在本地的“开发”配置文件中运行应用程序,而又需要在远程的“云”配置文件中运行应用程序。

每个存储库还可以选择将配置文件存储在子目录中,用于搜索这些目录的模式可以指定为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

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

Authentication

要在远程存储库上使用 HTTP 基本认证,请分别添加usernamepassword属性(不在 URL 中),如以下示例所示:

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

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

Tip

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

使用 AWS CodeCommit 进行身份验证

Spring Cloud Config Server 还支持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

aws-java-sdk-core jar 是可选的依赖项。如果aws-java-sdk-core jar 不在您的 Classpath 中,则无论 git 服务器 URI 如何,都不会创建 AWS Code Commit 凭证提供程序。

使用属性进行 Git SSH 配置

默认情况下,当通过 SSH URI 连接到 Git 存储库时,Spring Cloud Config Server 使用的 JGit 库使用 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: [email protected]: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 配置属性

Property NameRemarks
ignoreLocalSshSettings如果为true,请使用基于属性的 SSH 配置而不是基于文件的 SSH 配置。必须在存储库定义中设置为spring.cloud.config.server.git.ignoreLocalSshSettings,而不是**。
privateKey有效的 SSH 私钥。如果ignoreLocalSshSettings为 true 并且 Git URI 为 SSH 格式,则必须设置。
hostKey有效的 SSH 主机密钥。如果还设置了hostKeyAlgorithm,则必须设置。
hostKeyAlgorithmssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521之一。如果还设置了hostKey,则必须设置。
strictHostKeyCheckingtruefalse。如果为 false,请忽略主机密钥错误。
knownHostsFile自定义.known_hosts文件的位置。
preferredAuthentications覆盖服务器身份验证方法 Sequences。如果服务器在publickey方法之前具有键盘交互式身份验证,则这应允许规避登录提示。

Git 搜索路径中的占位符

Spring Cloud Config Server 还支持带有{application}{profile}(如果需要的话还有{label})占位符的搜索路径,如以下示例所示:

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

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

强制拉入 Git 存储库

如前所述,Spring Cloud Config Server 会克隆远程 git 存储库,以防本地副本变脏(例如,os 进程更改了文件夹内容),从而使 Spring Cloud Config Server 无法从远程存储库更新本地副本。

为了解决这个问题,有一个force-pull属性,如果本地副本是脏的,它会使 Spring Cloud Config Server 从远程存储库强制拉出,如以下示例所示:

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

force-pull属性的默认值为false

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

由于 Spring Cloud Config Server 在将分支检出到本地存储库后(例如通过标签获取属性)具有远程 git 存储库的克隆,因此它将永久保留该分支,直到下一个服务器重启(这将创建新的本地存储库)。因此,可能会删除远程分支,但仍可获取其本地副本。而且,如果 Spring Cloud Config ServerClient 端服务以--spring.cloud.config.label=deletedRemoteBranch,master开头,它将从deletedRemoteBranch本地分支而不是master获取属性。

为了使本地存储库分支保持整洁并保持远程状态-可以设置deleteUntrackedBranches属性。它将使 Spring Cloud Config Server force 从本地存储库中删除未跟踪的分支。例:

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

Note

deleteUntrackedBranches属性的默认值为false

Git 刷新率

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

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

Warning

使用基于 VCS 的后端(git,svn),检出文件或将其克隆到本地文件系统。默认情况下,它们以config-repo-的前缀放在系统临时目录中。例如,在 Linux 上,它可能是/tmp/config-repo-<randomid>。某些 os定期清理个临时目录。这可能导致意外的行为,例如缺少属性。为避免此问题,请通过将spring.cloud.config.server.git.basedirspring.cloud.config.server.svn.basedir设置为不在系统临时结构中的目录来更改 Config Server 使用的目录。

5.1.3 文件系统后端

Config Server 中还有一个“本机”配置文件,该配置文件不使用 Git,而是从本地 Classpath 或文件系统(您要使用spring.cloud.config.server.native.searchLocations指向的任何静态 URL)加载配置文件。要使用本机配置文件,请使用spring.profiles.active=native启动配置服务器。

Note

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

Warning

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

Tip

文件系统后端非常适合快速Starter和测试。要在生产环境中使用它,您需要确保文件系统可靠并且可以在 Config Server 的所有实例之间共享。

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

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

5.1.4 保管箱后端

Spring Cloud Config Server 还支持Vault作为后端。

Note

保管箱是用于安全访问机密的工具。Secret 是您要严格控制访问权限的所有内容,例如 API 密钥,密码,证书和其他敏感信息。保管箱提供了对任何机密信息的统一界面,同时提供了严格的访问控制并记录了详细的审核日志。

有关Vault的更多信息,请参见保管库快速Starter指南

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

默认情况下,配置服务器假定您的 Vault 服务器在http://127.0.0.1:8200上运行。它还假定后端的名称为secret,密钥为application。所有这些默认值都可以在配置服务器的application.properties中进行配置。下表描述了可配置的保管库属性:

NameDefault Value
host127.0.0.1
port8200
schemehttp
backendsecret
defaultKeyapplication
profileSeparator,
kvVersion1
skipSslValidationfalse
timeout5

Tip

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

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

Vault 0.10.0 引入了版本化的键值后端(k/v 后端版本 2),该后端公开了与早期版本不同的 API,它现在在安装路径和实际上下文路径之间需要data/,并将 Secret 包装在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/myAppsecret/application的所有属性。当myApp启用了dev配置文件时,将可以使用写入到上述所有路径的属性,列表中第一个路径中的属性优先于其他属性。

5.1.5 通过代理访问后端

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

下表描述了 HTTP 和 HTTPS 代理的代理配置属性。所有这些属性都必须以proxy.httpproxy.https作为前缀。

表 5.2. 代理配置属性

Property NameRemarks
host代理的主机。
port用于访问代理的端口。
nonProxyHosts配置服务器应在代理外部访问的所有主机。如果同时为proxy.http.nonProxyHostsproxy.https.nonProxyHosts提供了值,则将使用proxy.http值。
username用来验证代理的用户名。如果同时为proxy.http.usernameproxy.https.username提供了值,则将使用proxy.http值。
password用来验证代理的密码。如果同时为proxy.http.passwordproxy.https.password提供了值,则将使用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 与所有应用程序共享配置

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

基于文件的存储库

使用基于文件的(git,svn 和本机)存储库,所有 Client 端应用程序之间共享文件名为application*(application.propertiesapplication.ymlapplication-*.properties等)的资源。您可以使用具有这些文件名的资源来配置全局默认值,并在需要时使用特定于应用程序的文件来覆盖它们。

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

Tip

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

Vault Server

将 Vault 用作后端时,可以通过将配置放在secret/application中来与所有应用程序共享配置。例如,如果您运行以下 Vault 命令,则使用配置服务器的所有应用程序将具有对它们可用的属性foobaz

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

5.1.7 JDBC 后端

Spring Cloud Config Server 支持 JDBC(关系数据库)作为配置属性的后端。您可以通过将spring-jdbc添加到 Classpath 并使用jdbc概要文件或添加类型为JdbcEnvironmentRepository的 bean 来启用此功能。如果您在 Classpath 上包括正确的依赖项(有关更多详细信息,请参见用户指南),Spring Boot 会配置一个数据源。

数据库需要有一个名为PROPERTIES的表,该表具有名为APPLICATIONPROFILELABEL的列(通常具有Environment的含义),并为Properties样式的键和值对加上KEYVALUE。 Java 中所有字段的类型均为 String,因此您可以将它们设置为VARCHAR任意长度。属性值的行为方式与它们来自名为{application}-{profile}.properties的 Spring Boot 属性文件的行为相同,包括所有加密和解密,这些属性将作为后处理步骤应用(即,不直接在存储库实现中使用)。

5.1.8 CredHub 后端

Spring Cloud Config Server 支持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的所有 Client 端应用程序将具有以下属性:

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

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

使用的 UAAClientID 的范围应为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键下列出的 Sequences 确定。在上面的示例中,首先列出了 Subversion 存储库,因此在 Subversion 存储库中找到的值将覆盖在其中一个 Git 存储库中为相同属性找到的值。在walter Git 存储库中找到相同属性的值之前,将使用在rex 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属性为所有存储库指定优先级 Sequences。 order属性的数值越低,其优先级越高。存储库的优先级 Sequences 有助于解决包含相同属性值的存储库之间的任何潜在冲突。

Note

如果您的复合环境包括上一个示例中的 Vault 服务器,则在对配置服务器的每个请求中都必须包含 Vault 令牌。参见Vault Backend

Note

从环境存储库中检索值时,任何类型的故障都会导致整个组合环境的故障。

Note

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

自定义复合环境存储库

除了使用来自 Spring Cloud 的环境存储库之一之外,您还可以提供自己的EnvironmentRepository bean 作为复合环境的一部分。为此,您的 bean 必须实现EnvironmentRepository接口。如果要在复合环境中控制自定义EnvironmentRepository的优先级,则还应该实现Ordered接口并覆盖getOrdered方法。如果未实现Ordered接口,则EnvironmentRepository的优先级最低。

5.1.10 属性覆盖

Config Server 具有“替代”功能,使操作员可以为所有应用程序提供配置属性。应用程序使用常规的 Spring Boot 钩子不会意外更改重写的属性。要声明覆盖,请将名称/值对的 Map 添加到spring.cloud.config.server.overrides,如以下示例所示:

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

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

Note

配置系统不能强制应用程序以任何特定方式使用配置数据。因此,覆盖无法执行。但是,它们确实为 Spring Cloud ConfigClient 端提供了有用的默认行为。

Tip

通常,可以使用反斜杠(\)对${进行转义,以转义(并在 Client 端上解析)具有${}的 Spring 环境占位符。例如,\${app.foo:bar}解析为bar,除非应用程序提供自己的app.foo

Note

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

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

5.2 健康 Metrics

Config Server 带有运行状况指示器,用于检查配置的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 Security

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

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

5.4 加密和解密

Tip

要使用加密和解密功能,您需要在 JVM 中安装完整强度的 JCE(默认情况下不包括)。您可以从 Oracle 下载“ Java 密码学扩展(JCE)无限强度管辖权策略文件”,并按照安装说明进行操作(本质上,您需要用下载的 JRE lib/security 目录替换这两个策略文件)。

如果远程属性源包含加密的内容(值以{cipher}开头),则将其解密,然后再通过 HTTP 发送给 Client 端。此设置的主要优点是,当属性值处于“静止”状态时(例如,在 git 存储库中),不需要使用纯文本格式。如果无法解密某个值,则将其从属性源中删除,并使用相同的密钥但以invalid作为前缀的附加属性以及一个表示“不适用”的值(通常为<n/a>)添加。这在很大程度上是为了防止密文用作密码和意外泄漏。

如果为配置 Client 端应用程序设置远程配置存储库,则它可能包含类似于以下内容的application.yml

application.yml.

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

.properties 文件中的加密值不能用引号引起来。否则,该值不会解密。以下示例显示了有效的值:

application.properties.

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

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

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

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

Note

如果您加密的值中包含需要 URL 编码的字符,则应使用curl--data-urlencode选项以确保它们正确编码。

Tip

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

反向操作也可以通过/decrypt获得(前提是服务器配置了对称密钥或完整密钥对),如以下示例所示:

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

Tip

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

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

/encrypt/decrypt端点也都接受/*/{name}/{profiles}形式的路径,当 Client 端调用主环境资源时,可用于按应用程序(名称)和配置文件控制密码。

Note

要以这种精细的方式控制加密,还必须提供类型为TextEncryptorLocator@Bean,该@Bean会根据名称和配置文件创建不同的加密器。默认情况下不提供(所有加密使用相同的密钥)。

spring命令行 Client 端(安装了 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

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

5.5 密钥 Management

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

要配置对称密钥,您需要将encrypt.key设置为 Secret 字符串(或使用ENCRYPT_KEY环境变量将其保留在纯文本配置文件中)。

Note

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

要配置非对称密钥,请使用密钥库(例如,由 JDK 随附的keytoolUtil 创建的密钥库)。密钥库属性是encrypt.keyStore.**等于

PropertyDescription
encrypt.keyStore.location包含Resource个位置
encrypt.keyStore.password持有用于解锁密钥库的密码
encrypt.keyStore.alias标识 Store 中要使用的密钥

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

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文件放入 Classpath(例如),然后在bootstrap.yml中为 Config Server 创建以下设置:

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

5.7 使用多个键和旋转键

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

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

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

当密钥仅用于加密几个字节的配置数据时(也就是说,它们未在其他地方使用),从密码的角度讲,几乎不需要旋转密钥。但是,您有时可能需要更改密钥(例如,在发生安全漏洞时)。在这种情况下,所有 Client 端都需要更改其源配置文件(例如,在 git 中),并在所有密码中使用新的{key:…}前缀。请注意,Client 端需要首先检查 Config Server 密钥库中的密钥别名是否可用。

Tip

如果要让 Config Server 处理所有加密以及解密,则还可以将{name:value}前缀作为纯文本添加到/encrypt端点()中。

5.8 提供加密的属性

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