Spring Cloud Config Server为外部配置提供基于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上运行,但你能够经过各类方式将其切换到更传统的端口8888。最简单的,也是设置默认配置存储库,是经过spring.config.name=configserver
启动它(Config Server jar中有一个configserver.yml
),另外一种方法是使用你本身的application.properties
,如如下示例所示:git
application.propertiesspring
server.port: 8888 spring.cloud.config.server.git.uri: file://${user.home}/config-repo
其中${user.home}/config-repo
是一个包含YAML和属性文件的git存储库。sql
在Windows上,若是文件URL是绝对的驱动器前缀,则须要额外的“/”(例如,file:///${user.home}/config-repo
)。bootstrap
如下清单显示了在前面的示例中建立git存储库的步骤:segmentfault
$ 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"
使用git存储库的本地文件系统仅用于测试,生产中你应该使用服务器托管配置存储库。
若是只保留文本文件,则配置存储库的初始克隆能够快速有效,若是存储二进制文件(尤为是大型文件),则第一次请求配置可能会出现延迟或服务器中遇到内存不足错误。
应该在哪里存储配置服务器的配置数据?管理此行为的策略是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配置:网络
bootstrap.yml
spring: application: name: foo profiles: active: dev,mysql
像一般同样,Spring Boot应用程序也能够经过环境变量或命令行参数来设置这些属性。
若是存储库是基于文件的,则服务器从application.yml
(在全部客户端之间共享)和foo.yml
(以foo.yml
优先)建立Environment
。若是YAML文件中包含指向Spring配置文件的文档,那么这些文档将以更高的优先级应用(按列出的配置文件的顺序)。若是存在特定配置文件的YAML(或属性)文件,则这些文件的优先级也高于默认值,较高的优先级转换为Environment
中先前列出的PropertySource
(这些相同的规则适用于独立的Spring Boot应用程序)。
你能够将spring.cloud.config.server.accept-empty
设置为false
,以便若是应用程序找不到,则Server返回HTTP 404状态,默认状况下,此标志设置为true
。
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
来禁用监控指示器。
你能够以对你有意义的任何方式保护你的Config Server(从物理网络安全到OAuth2承载令牌),由于Spring Security和Spring Boot为许多安全安排提供支持。
要使用默认的Spring Boot配置的HTTP Basic安全性,请在类路径中包含Spring Security(例如,经过spring-boot-starter-security
),默认值为user
的用户名和随机生成的密码,随机密码在实践中没有用,所以建议你配置密码(经过设置spring.security.user.password
)并对其进行加密(有关如何执行此操做的说明,请参阅下文)。
要使用加密和解密特性,你须要在JVM中安装完整的JCE(默认状况下不包括),你能够从Oracle下载“Java Cryptography Extension(JCE)Unlimited Strength Jurisdiction Policy Files”并按照安装说明进行操做(实际上,你须要将JRE lib/security
目录中的两个策略文件替换为你下载的策略文件)。
若是远程属性源包含加密内容(以{cipher}
开头的值),则在经过HTTP发送到客户端以前对它们进行解密,此设置的主要优势是,属性值在“静止”时没必要是纯文本格式(例如,在git存储库中)。若是某个值没法解密,则会从属性源中删除该值,并添加一个附加属性,该属性具备相同的键但前缀为invalid
,且值为“不适用”(一般为<n/a>
),这主要是为了防止密文被用做密码并意外泄露。
若是为配置客户端应用程序设置远程配置存储库,则它可能包含相似于如下内容的application.yml
:
spring: datasource: username: dbuser password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'
.properties
文件中的加密值不能用引号括起来,不然,该值不会被解密,如下示例显示了有效的值:
application.properties
spring.datasource.username: dbuser spring.datasource.password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ
你能够安全地将此纯文本推送到共享的git存储库,而且密码仍然受到保护。
服务器还公开/encrypt
和/decrypt
端点(假设这些端点是安全的而且只能由受权代理访问),若是编辑远程配置文件,则可使用Config Server经过POST到/encrypt
端点来加密值,如如下示例所示:
$ curl localhost:8888/encrypt -d mysecret 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
若是你加密的值中包含须要进行URL编码的字符,则应使用--data-urlencode
选项进行curl
以确保它们已正确编码。
请确保不要在加密值中包含任何
curl
命令统计信息,将值输出到文件能够帮助避免此问题。
经过/decrypt
也可使用反向操做(前提是服务器配置了对称密钥或完整密钥对),如如下示例所示:
$ curl localhost:8888/decrypt -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda mysecret
若是你用curl
测试,那么使用--data-urlencode
(替代-d
)或设置一个显式的Content-Type: text/plain
来确保curl
在有特殊字符时正确编码数据('+'特别棘手)。
获取加密值并添加{cipher}
前缀,而后再将其放入YAML或属性文件中,而后再提交并将其推送到远程(可能不安全)存储。
/encrypt
和/decrypt
端点也接受/*/{name}/{profiles}
形式的路径,当客户端调用主环境资源时,可用于在每一个应用程序(名称)和每一个配置文件的基础上控制加密。
要以这种精细的方式控制加密,你还必须提供类型为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+...
--key
参数是必需的(尽管有--
前缀)。
Config Server可使用对称(共享)密钥或非对称密钥(RSA密钥对),非对称选择在安全性方面更优越,但使用对称密钥一般更方便,由于它是在bootstrap.properties
中配置的单个属性值。
要配置对称密钥,须要将encrypt.key
设置为秘密字符串(或使用ENCRYPT_KEY
环境变量将其排除在纯文本配置文件以外)。
没法使用
encrypt.key
配置非对称密钥。
要配置非对称密钥,请使用密钥库(例如,由JDK附带的keytool
实用工具建立),密钥库属性是encrypt.keyStore.*
,*
等于:
属性 | 描述 |
---|---|
encrypt.keyStore.location |
包含Resource 的位置 |
encrypt.keyStore.password |
保存解锁密钥库的密码 |
encrypt.keyStore.alias |
标识要使用存储中的哪一个密钥 |
加密是使用公钥完成的,而且须要私钥进行解密,所以,原则上,若是只想加密(并准备使用私钥本地解密值),则只配置服务器中的公钥。实际上,你可能不但愿在本地进行解密,由于它会围绕全部客户端传播密钥管理过程,而不是将其集中在服务器中,另外一方面,若是你的配置服务器相对不安全且只有少数客户端须要加密属性,那么它多是一个有用的选项。
要建立用于测试的密钥库,可使用相似于如下内容的命令:
$ 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
中为Config Server建立如下设置:
encrypt: keyStore: location: classpath:/server.jks password: letmein alias: mytestkey secret: changeme
除了加密属性值中的{cipher}
前缀以外,Config Server还会在(Base64编码)密文开头以前查找零个或多个{name:value}
前缀,密钥传递给TextEncryptorLocator
,它能够执行为密文定位TextEncryptor
所需的任何逻辑。若是已配置密钥库(encrypt.keystore.location
),则默认定位器将查找具备key
前缀提供的别名的密钥,密文相似于如下内容:
foo: bar: `{cipher}{key:testkey}...`
定位器查找名为“testkey”的密钥,也能够经过在前缀中使用{secret:…}
值来提供秘密,可是,若是未提供,则默认使用密钥库密码(这是你在构建密钥库时未指定秘密),若是你提供秘密,你还应该使用自定义SecretLocator
加密秘密。
当密钥仅用于加密几个字节的配置数据时(也就是说,它们没有在其余地方使用),在加密方面几乎不须要密钥轮换。可是,你可能偶尔须要更改密钥(例如,在发生安全漏洞时),在这种状况下,全部客户端都须要更改其源配置文件(例如,在git中)并在全部密文中使用新的{key:…}
前缀,请注意,客户端须要首先检查Config Server密钥库中的密钥别名是否可用。
若是你想让Config Server处理全部加密和解密,{name:value}
前缀也能够做为纯文本添加发布到/encrypt
端点。
有时你但愿客户端在本地解密配置,而不是在服务器中执行此操做。在这种状况下,若是你提供encrypt.*
配置来定位密钥,你仍然能够拥有/encrypt
和/decrypt
端点,可是你须要经过在bootstrap.[yml|properties]
中放置spring.cloud.config.server.encrypt.enabled=false
来明确地关闭输出属性的解密,若是你不关心端点,那么若是你不配置密钥或启用标志,它应该能够工做。
环境端点的默认JSON格式很是适合Spring应用程序使用,由于它直接映射到Environment
抽象,若是你愿意,能够经过向资源路径添加后缀(“.yml”,“.yaml”或“.properties”)来使用与YAML或Java属性相同的数据,对于不关心JSON端点结构或它们提供的额外元数据的应用程序来讲,这可能颇有用(例如,不使用Spring的应用程序可能会受益于此方法的简单性)。
YAML和属性表示有一个额外的标志(做为名为resolvePlaceholders
的布尔查询参数提供),表示源文档中的占位符(在标准的Spring ${…}
形式)应该在渲染以前在输出中解析(在可能的状况),对于不了解Spring占位符约定的消费者而言,这是一个有用的特性。
使用YAML或属性格式存在限制,主要与元数据丢失有关。例如,JSON为属性源的有序列表结构,其名称与源相关,YAML和属性形式合并为单个映射,即便值的来源有多个源,而且原始源文件的名称丢失。此外,YAML表示不必定是支持存储库中YAML源的可靠表示,它由一个平面属性源列表构成,必须对键的形式进行假设。