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源的可靠表示,它由一個平面屬性源列表構成,必須對鍵的形式進行假設。