[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。若是不關係端點訪問,那就既不要配置密鑰也不要開啓此配置。

相關文章
相關標籤/搜索