Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

第 13 章 多維度架構之微服務

目錄

13.1. 微服務安全嗎?
13.1.1. 配置中心的隱患
13.1.2. 註冊中心的隱患
13.1.3. Eureka 客戶端
13.1.4. 最終總結
13.2. 熔斷器解決了什麼問題?
13.3. 微服務的性能
13.3.1. 微服務的開銷
13.4. 多維度架構之微服務拆分
13.4.1. 分散式事務之路
13.4.2. 微服務拆分法則
13.4.2.1. 基于工作流拆分服務
13.4.2.2. 服務池的概念
13.4.3. 最後總結
13.5. 介面安全
13.5.1. Restful 安全問提
13.5.2. 第一個階段採用 HTTP Basic Auth
13.5.3. 第二階段 HTTP Basic Auth + SSL
13.5.4. 第三階段 HTTP2 + HTTP Basic Auth + Oauth2
13.5.5. 第三階段,終極版誕生,HTTP2 + HTTP Basic Auth + Oauth2 + Jwt

13.1. 微服務安全嗎?

微服務安全嗎?其實存在很多隱患,常規的做法是將微服務置於私有區域網路中,通過網關報漏服務。如果破壞者一旦進入了你的私有區域網路中,微服務是及其危險的。

13.1.1. 配置中心的隱患

配置中心的安全隱患

配置中心有以下幾種安全隱患

  1. 配置中心報漏在公網IP之下
  2. 配置中心沒有做用戶驗證
  3. 配置檔案中存在敏感信息
  4. 明文傳輸內容

配置有泄漏敏感信息的隱患,你的配置中心是不是也這樣?

			
iMac:workspace neo$ curl http://localhost:8888/netkiller-dev-master.json
{"sms":{"gateway":{"url":"https://sms.netkiller.cn/v1","username":"netkiller","password":"123456"}}}
			
			

給配置中心增加SSL和HTTP認證,可以讓配置中心更安全。

			
iMac:resources neo$ curl -i -k https://config:s3cr3t@localhost:8888/netkiller-dev.json
HTTP/2 200 
set-cookie: JSESSIONID=9E77660C8DC7669121C8D122A48D8737; Path=/; Secure; HttpOnly
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
strict-transport-security: max-age=31536000 ; includeSubDomains
x-frame-options: DENY
content-type: application/json
content-length: 100
date: Mon, 07 Sep 2020 08:24:39 GMT

{"sms":{"gateway":{"url":"https://sms.netkiller.cn/v1","username":"netkiller","password":"123456"}}}	
			
			

我們將 HTTP2 SSL 應用在配置中心後,就不擔心配置檔案被嗅探器抓到。

13.1.2. 註冊中心的隱患

註冊中心一不小心就被公網IP報漏出去,甚至有被惡意註冊的風險。

註冊中心有以下幾種安全隱患

  1. 註冊中心沒有做用戶驗證,任何人都能訪問
  2. 註冊中心報漏在公網IP之下,被惡意註冊的風險。
  3. 從openfeign 訪問 euerka server 明文傳輸內容

你的註冊中心是不是這樣的?

			
iMac:workspace neo$ curl http://localhost:8761/eureka/apps
<applications>
  <versions__delta>1</versions__delta>
  <apps__hashcode>UP_1_</apps__hashcode>
  <application>
    <name>WEBFLUX</name>
    <instance>
      <instanceId>192.168.3.85:webflux</instanceId>
      <hostName>192.168.3.85</hostName>
      <app>WEBFLUX</app>
      <ipAddr>192.168.3.85</ipAddr>
      <status>UP</status>
      <overriddenstatus>UNKNOWN</overriddenstatus>
      <port enabled="true">8080</port>
      <securePort enabled="false">443</securePort>
      <countryId>1</countryId>
      <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
      </dataCenterInfo>
      <leaseInfo>
        <renewalIntervalInSecs>30</renewalIntervalInSecs>
        <durationInSecs>90</durationInSecs>
        <registrationTimestamp>1599106511367</registrationTimestamp>
        <lastRenewalTimestamp>1599106931380</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1599106511367</serviceUpTimestamp>
      </leaseInfo>
      <metadata>
        <management.port>8080</management.port>
      </metadata>
      <homePageUrl>http://192.168.3.85:8080/</homePageUrl>
      <statusPageUrl>http://192.168.3.85:8080/actuator/info</statusPageUrl>
      <healthCheckUrl>http://192.168.3.85:8080/actuator/health</healthCheckUrl>
      <vipAddress>webflux</vipAddress>
      <secureVipAddress>webflux</secureVipAddress>
      <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
      <lastUpdatedTimestamp>1599106511368</lastUpdatedTimestamp>
      <lastDirtyTimestamp>1599106511299</lastDirtyTimestamp>
      <actionType>ADDED</actionType>
    </instance>
  </application>
</applications>			
			
			

經過安全加固後

Eureka Web 界面進入需要輸入用戶名和密碼,HTTP2 SSL 加密傳輸頁面內容。

https://localhost:8761

			
iMac:resources neo$ curl -k https://eureka:s3cr3t@localhost:8761/eureka/apps
<applications>
  <versions__delta>1</versions__delta>
  <apps__hashcode>UP_2_</apps__hashcode>
  <application>
    <name>MICROSERVICE-RESTFUL</name>
    <instance>
      <instanceId>192.168.3.85:microservice-restful:8081</instanceId>
      <hostName>192.168.3.85</hostName>
      <app>MICROSERVICE-RESTFUL</app>
      <ipAddr>192.168.3.85</ipAddr>
      <status>UP</status>
      <overriddenstatus>UNKNOWN</overriddenstatus>
      <port enabled="true">8081</port>
      <securePort enabled="false">443</securePort>
      <countryId>1</countryId>
      <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
      </dataCenterInfo>
      <leaseInfo>
        <renewalIntervalInSecs>30</renewalIntervalInSecs>
        <durationInSecs>90</durationInSecs>
        <registrationTimestamp>1599532959290</registrationTimestamp>
        <lastRenewalTimestamp>1599533499404</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1599532959290</serviceUpTimestamp>
      </leaseInfo>
      <metadata>
        <management.port>8081</management.port>
      </metadata>
      <homePageUrl>http://192.168.3.85:8081/</homePageUrl>
      <statusPageUrl>http://192.168.3.85:8081/actuator/info</statusPageUrl>
      <healthCheckUrl>http://192.168.3.85:8081/actuator/health</healthCheckUrl>
      <vipAddress>microservice-restful</vipAddress>
      <secureVipAddress>microservice-restful</secureVipAddress>
      <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
      <lastUpdatedTimestamp>1599532959291</lastUpdatedTimestamp>
      <lastDirtyTimestamp>1599532959204</lastDirtyTimestamp>
      <actionType>ADDED</actionType>
    </instance>
  </application>
  <application>
    <name>OPENFEIGN</name>
    <instance>
      <instanceId>192.168.3.85:openfeign:8088</instanceId>
      <hostName>192.168.3.85</hostName>
      <app>OPENFEIGN</app>
      <ipAddr>192.168.3.85</ipAddr>
      <status>UP</status>
      <overriddenstatus>UNKNOWN</overriddenstatus>
      <port enabled="true">8088</port>
      <securePort enabled="false">443</securePort>
      <countryId>1</countryId>
      <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
      </dataCenterInfo>
      <leaseInfo>
        <renewalIntervalInSecs>30</renewalIntervalInSecs>
        <durationInSecs>90</durationInSecs>
        <registrationTimestamp>1599533216972</registrationTimestamp>
        <lastRenewalTimestamp>1599533517001</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1599533216972</serviceUpTimestamp>
      </leaseInfo>
      <metadata>
        <management.port>8088</management.port>
      </metadata>
      <homePageUrl>http://192.168.3.85:8088/</homePageUrl>
      <statusPageUrl>http://192.168.3.85:8088/actuator/info</statusPageUrl>
      <healthCheckUrl>http://192.168.3.85:8088/actuator/health</healthCheckUrl>
      <vipAddress>openfeign</vipAddress>
      <secureVipAddress>openfeign</secureVipAddress>
      <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
      <lastUpdatedTimestamp>1599533216972</lastUpdatedTimestamp>
      <lastDirtyTimestamp>1599533216920</lastDirtyTimestamp>
      <actionType>ADDED</actionType>
    </instance>
  </application>
</applications>			
			
			

13.1.3. Eureka 客戶端

Eureka Client 的安全配置與Eureka Server/Config Server 類似

Eureka 客戶端有以下幾種安全隱患

  1. 服務報漏在公網IP之下,任何人都不經過 Eureka Server 和 Openfeign 繞開後直接訪問服務
  2. 明文傳輸內容

我們給 Eureka Client 增加 HTTP/2 SSL 然後再註冊到 Eureka Server,我通常會關閉 Eureka Client 連接埠,只保留 SSL 連接埠。

			
iMac:Architect neo$ curl -k https://eureka:s3cr3t@localhost:8761/eureka/apps 
<applications>
  <versions__delta>1</versions__delta>
  <apps__hashcode>UP_2_</apps__hashcode>
  <application>
    <name>MICROSERVICE-RESTFUL</name>
    <instance>
      <instanceId>192.168.3.85:microservice-restful:8081</instanceId>
      <hostName>192.168.3.85</hostName>
      <app>MICROSERVICE-RESTFUL</app>
      <ipAddr>192.168.3.85</ipAddr>
      <status>UP</status>
      <overriddenstatus>UNKNOWN</overriddenstatus>
      <port enabled="false">8081</port>
      <securePort enabled="true">8081</securePort>
      <countryId>1</countryId>
      <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
      </dataCenterInfo>
      <leaseInfo>
        <renewalIntervalInSecs>30</renewalIntervalInSecs>
        <durationInSecs>90</durationInSecs>
        <registrationTimestamp>1599547853553</registrationTimestamp>
        <lastRenewalTimestamp>1599548033559</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1599547853554</serviceUpTimestamp>
      </leaseInfo>
      <metadata>
        <management.port>8081</management.port>
      </metadata>
      <homePageUrl>http://192.168.3.85:8081/</homePageUrl>
      <statusPageUrl>http://192.168.3.85:8081/actuator/info</statusPageUrl>
      <healthCheckUrl>http://192.168.3.85:8081/actuator/health</healthCheckUrl>
      <secureHealthCheckUrl>https://192.168.3.85:8081/actuator/health</secureHealthCheckUrl>
      <vipAddress>microservice-restful</vipAddress>
      <secureVipAddress>microservice-restful</secureVipAddress>
      <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
      <lastUpdatedTimestamp>1599547853554</lastUpdatedTimestamp>
      <lastDirtyTimestamp>1599547853483</lastDirtyTimestamp>
      <actionType>ADDED</actionType>
    </instance>
  </application>
  <application>
    <name>OPENFEIGN</name>
    <instance>
      <instanceId>192.168.3.85:openfeign:8088</instanceId>
      <hostName>192.168.3.85</hostName>
      <app>OPENFEIGN</app>
      <ipAddr>192.168.3.85</ipAddr>
      <status>UP</status>
      <overriddenstatus>UNKNOWN</overriddenstatus>
      <port enabled="true">8088</port>
      <securePort enabled="true">8088</securePort>
      <countryId>1</countryId>
      <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
        <name>MyOwn</name>
      </dataCenterInfo>
      <leaseInfo>
        <renewalIntervalInSecs>30</renewalIntervalInSecs>
        <durationInSecs>90</durationInSecs>
        <registrationTimestamp>1599547953476</registrationTimestamp>
        <lastRenewalTimestamp>1599547953476</lastRenewalTimestamp>
        <evictionTimestamp>0</evictionTimestamp>
        <serviceUpTimestamp>1599547953476</serviceUpTimestamp>
      </leaseInfo>
      <metadata>
        <management.port>8088</management.port>
      </metadata>
      <homePageUrl>http://192.168.3.85:8088/</homePageUrl>
      <statusPageUrl>http://192.168.3.85:8088/actuator/info</statusPageUrl>
      <healthCheckUrl>http://192.168.3.85:8088/actuator/health</healthCheckUrl>
      <secureHealthCheckUrl>https://192.168.3.85:8088/actuator/health</secureHealthCheckUrl>
      <vipAddress>openfeign</vipAddress>
      <secureVipAddress>openfeign</secureVipAddress>
      <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
      <lastUpdatedTimestamp>1599547953476</lastUpdatedTimestamp>
      <lastDirtyTimestamp>1599547953435</lastDirtyTimestamp>
      <actionType>ADDED</actionType>
    </instance>
  </application>
</applications>			
			
			

從上面配置中可以看到 port 已經禁用,也就意味着無法再通過 http:// 訪問,securePort 是啟用狀態,只接受 https:// 訪問。

			
      <port enabled="false">8081</port>
      <securePort enabled="true">8081</securePort>			
			
			

最好還要設置防火牆,只允許 Eureka Server 才能訪問 Eureka Client。防止通過其他服務做為跳板,進入區域網路,直接訪問 Eureka Client。

13.1.4. 最終總結

為了防止不小心 公網IP保留微服務,我們需要將實例與區域網路IP地址綁定,這樣服務只能從區域網路IP訪問,即使伺服器映射了公網IP地址也不用擔心。

禁用 HTTP 訪問,全部改為 HTTPS 訪問

			
H5 / App 
    ^
    |
 HTTP2 ssl
    |
    V		
Openfeign <--- HTTP2 ssl ---> Eureka Server
                                  ^
                                  |
                                  |
                              HTTP2 ssl
                                  |
                                  |
                                  V
                             Eureka Client  <--- HTTP2 ssl ---> Config Server
			
			

如果可以,儘量為節點增加用戶認證。