【大咖連載】服務設計與實現

  • 2019 年 10 月 5 日
  • 筆記

服務設計會影響到業務需求是否被正確、高效地實現,良好的服務設計能夠幫助領域專家與開發人員之間,以及團隊內部進行高效、準確的溝通。良好的實現則能縮短服務上線的周期,並提升可擴展性及可維護性。

在微服務架構設計的過程中,架構設計、介面設計需要和程式碼庫一樣,使用版本化機制管理起來。同時,作為獨立的服務,應該能夠在本地運行,並且要有完善並且容易理解的文檔,方便團隊成員快速上手。在本書的第3章中,筆者已經闡述了服務劃分、服務內部實現、通訊機制等內容,在本節中,我們將重點探討服務設計與實現過程中的相關實踐。

5.3.1 架構即程式碼

當探索整個系統的服務設計時,我們總會求助於它的架構圖。單體應用架構下,功能以組件/模組化的形式存在,比較容易在一張架構圖上體現出來。而在微服務架構下,服務數量多,很難以一種完整的狀態體現在架構圖上。

另外,系統的架構圖通常都是使用Visio等類似的二進位工具繪製而成的,保存為二進位文件,維護起來不太方便。

在筆者的微服務實踐中,通常的思路是使用Graphviz工具,基於dot語言來描述架構圖,並將其保存為SVG、PNG,或者PDF之類的格式。同時,這些dot語言程式碼可以放在微服務的程式碼庫中,以版本化的方式保存起來,任何的架構變動都能有效地反映到程式碼庫中。Graphviz的安裝非常簡單,在Mac系統下通過brew install graphviz安裝,在Windows系統下可以下載軟體包安裝。

譬如,假設我們現在需要為一個社交網站繪製架構圖,前端的Web應用通過API Gateway請求照片、聊天、朋友服務,則其程式碼實現如下,架構示意圖如圖5-4所示。

digraph architecture {    rankdir=LR;    ... # 節點定義如api_gateway、photo等,形狀設置、填充顏色等    subgraph front_app {        front -> {api_gateway};    }    subgraph api_gateway {        api_gateway ->{photo, chat, friend};    }    subgraph microservices {        photo -> {database};        chat -> {database,cache};        friend -> {database,weibo_api};    }   subgraph dbs {      cache -> database;    }  }

圖5-4 用Graphviz生產的架構圖

使用Graphviz實現架構圖,程式碼很容易理解。也可以直接使用GraphvizGUI的工具,實時看到修改的結果,非常方便。類似的工具還有Mermaid(https://github.com/knsv/mermaid),其也是一個類似的工具,而DSL更加簡潔一些。除此之外,有些在線工具,如draw.io、gliffy,也都是不錯的繪製微服務架構圖的工具。

5.3.2 介面即程式碼

當接觸一個新的服務時,我們往往要花一些時間去學習服務提供的 API,並通過案例了解用法。通常這樣的API介面介紹,都是記錄在文檔中,而這樣的文檔往往得不到很好的更新與維護。在微服務架構下,隨著服務數量增加,介面變化頻繁,對應的介面管理也變得更加困難。

在筆者實現微服務的過程中,通常是通過Swagger這種工具可視化REST API的規範。通過SwagerEditor,能方便地定義API的詳細資訊、HTTP請求方法,以及請求響應等內容,如圖5-5所示。

圖5-5 Swagger案例

另外,可以將Swagger生成的YAML保存在微服務的程式碼庫中,其相當於將介面的文檔以版本化的方式管理起來;如果是使用Java實現的服務,也可以引入swagger-springmvc插件,其內嵌了Swagger-UI,直接訪問即可查看服務的API介面資訊。

在本書的實戰篇中,筆者將介紹ServiceComb框架,它支援通過類Swagger的契約文件定義介面,使用方便,同時也達到了將介面定義版本化管理的目的。

5.3.3 本地運行服務

開發人員可以直接將單體應用在本地運行起來,進行端到端的功能驗證。在微服務架構下,服務雖然能獨立啟動,但是要在本地進行端到端的驗證,可能需要啟動依賴的服務、資料庫等。同時,微服務可能採用不同的技術實現,準備和維護這些服務的運行環境也有一定的時間成本。筆者通常會使用Docker/docker-compose的方式,結合自動化的腳本來解決微服務在本地運行的問題。

對於純前端的工程,可以使用如npmstart這樣的方式直接啟動服務,依賴的服務可以配置為測試環境或者預生產環境,如果沒有寫操作,甚至都可以使用生產環境。如果服務不支援跨站請求,那麼可能需要利用Docker/docker-compose在本地啟動依賴的微服務、修改配置,並支援跨站請求。

對於後端工程,在本地運行服務的需求主要有兩個,一個是在IDE中調試程式碼,還有一個就是驗證開發的功能是否滿足需求。有時在本地運行端到端的測試,也需要在本地啟動微服務以及關聯的服務。比如在一個 Java 的微服務開發過程中,筆者為團隊準備了兩個docker-compose的YAML文件來組織服務在本地的構建與運行,分別用於為IDE調試和本地功能自驗。比如下面的debug.yml文件,用來組織微服務依賴的註冊中心、資料庫和redis的環境:

version:"2"  services:    servicecenter:      image:service-center     network_mode:"host"      logging:        driver:"none"    redis:      image: redis:4.0.2-alpine     network_mode:"host"    postgre:      image: postgres:9.3-alpine     network_mode:"host"

這裡直接的容器都直接使用了host網路模型,從而避免了額外的link配置。啟動包含本地程式碼修改的微服務的compose.yml文件如下:

version:"2"  services:     application:      build:        context: ./        environment:          ...     network_mode:"host"    servicecenter:      image: service-center     network_mode:"host"      logging:        driver:"none"    redis:      image: redis:4.0.2-alpine     network_mode:"host"    postgre:      image: postgres:9.3-alpine     network_mode:"host"

用兩個簡單的shell腳本包裝,用來啟動調試環境的腳本:

#!/bin/bash  #debug.sh  docker stop $(docker ps -q)  docker-compose -f debug.yml up -d

本地啟動所有相關服務的腳本:

#!/bin/bash  #compose.sh  docker stop $(docker ps -q)  docker-compose -f compose.yml up -d

通過在本地啟動調試和自驗的環境,可以很方便的在本地調試、驗證功能,以及在本地運行端到端的測試,讓開發人員可以及早自測功能,保證實現以滿足需求。

5.3.4 OnePage文檔

採用微服務意味著擁抱快速變化,這種快速變化反映在技術棧、架構、人員的變化,如何提升這種變化的可見性,如何讓新人或者不熟悉服務的人能快速了解、上手微服務,也是微服務實施面臨的一個挑戰。

通過將服務相關的開發、測試、環境的基本資訊記錄在文檔中,並和服務的程式碼庫保存在一起,降低微服務的學習成本。通常筆者將這類文檔稱為「OnePage文檔」。

OnePage文檔的內容通常包括如下部分:

  • 服務綜述。包括服務的名稱、服務提供的基本功能,服務的消費者以及服務提供的API。同時,記錄服務的維護者資訊,包括姓名、郵箱、電話號碼等,確保能在服務出現異常時第一時間聯繫到維護者。
  • 服務SLA。描述服務的可用性,明確提示不可用的時間段。如周一至周五(6:00~23:59)
  • 與架構相關。描述服務依賴的組件、其他服務、資料庫等,同時也體現數據的流向。一般筆者使用Grapviz工具完成這些依賴的表示。
  • 運行環境。描述環境相關資訊。如測試環境、預生產環境、生產環境等的訪問地址以及訪問的方式,如登錄秘鑰的獲取方式。
  • 與開發相關。描述開發相關資訊。如何配置開發環境、本地啟動、調試、基本開發流程等。
  • 與測試相關。描述測試相關資訊。如測試的策略、如何運行測試、覆蓋率標準等。
  • 流水線相關。描述持續交付相關資訊。如持續集成地址、構建包存儲地址等資訊。
  • 與部署相關。描述部署相關的資訊,通常包括但不限於如何部署到不同環境、部署後的功能驗證方式。
  • 與運維相關。如監控、報警訪問地址,不同環境的日誌搜索的索引、監控面板、部署的工程、伺服器訪問的SSH資訊、健康檢查的介面等。同時也可以包括如何實施災備的指導。
  • 常見的問題鏈接。系統存在一些已知的問題,短時間內無法或者沒有計劃修復,可以列出來。

通常筆者會用MarkDown格式來記錄這樣的文檔,並以README.md的形式保存在微服務的程式碼庫中。這樣任何人訪問程式碼庫時都可以快速了解該服務完整的資訊。

組織良好、內容充實的OnePage文檔,可以幫助我們快速上手一個新的系統,並且以最短的時間找到解決問題的思路和方法。另外,由於程式碼與文檔在同一程式碼庫中,對於像介面、架構等變更,也能有效保證程式碼與文檔同步更新,較低維護成本。

5.3.5 前後端分離

系統有時需要提供介面完成與用戶的交互,那麼當後台服務化後,用戶介面的部分如何處理呢?常見的處理機制有兩種:

  • 由服務實現介面,返回HTML/CSS。系統通過IFrame嵌套,JavaScript獲取HTML,並以動態渲染的方式完成頁面的集成。這種方式能讓團隊負責端到端的業務實現,包括UI的維護等,但它存在一些缺點:
    • 難以保證介面的統一性。由於介面的不同部分來自於不同的服務,需要團隊協作來保持樣式的一致。
    • 難以實現複雜的交互。對於複雜的交互,如搜索框輸入後自動刷新,服務端很難在UI片段中提供這種能力。
    • 難以支援多客戶端。對於多元化的客戶端,這些UI片段無法直接重用,即使是採用混合的方式在原生應用中嵌入HTML,也很難保證良好的用戶體驗和兼容性。

微服務中包含UI的方式也稱作微前端(MicroFrontends),ThoughtWorks在2016年的技術雷達中首次提出了這個術語,不過目前仍處於評估階段,因此只建議綜合評估後再決定是否使用。

  • 採用前後端分離,後端微服務負責業務或數據介面,前端的頁面請求各個後端服務API,聚合數據並展現,完成交互邏輯。

前後端分離綜述

前後端分離的優點有以下幾個:

  • 職責清晰。前端負責介面渲染、交互及用戶體驗。後端負責提供數據介面,許可權控制等。由於前後端需要使用的資源等級不一致,後端可能需要更多的計算資源,可以在系統運行時對後端獨立進行伸縮。
  • 維護成本降低。對於前端來說,由於只包含HTML、CSS或JavaScripts部署只是文件的替換。通過目前主流的前端框架,可以非常快速地定位及發現問題的所在,客戶端的問題不再需要後台人員參與及調試,程式碼重構及可維護性增強。
  • 開發效率提升。可以採用優秀的框架,提高開發效率,後端只關注介面設計及邏輯開發,無須關注頁面渲染。
  • 性能提升。前端頁面不再通過伺服器渲染返回,而是直接通過文件伺服器返回,速度更快。同時,通過前端路由的配置,可以實現頁面的按需載入。筆者曾經對一家互聯網企業的主站做前後端分離,頁面載入速度從耗時12秒,降低到了3秒。

在使用前後端分離時,需要注意以下問題:

  • 適配不同客戶端。通過BFF(Backend for Frontends)的模式,為不同客戶端提供不同形式的介面。
  • 前後端協作。可以使用Mock介面,為前端提供數據,也可以使用契約測試,保證前後端的介面一致。
  • 跨域問題。可以在後端統一配置跨域規則,降低前端跨域請求帶來的複雜度。
  • SEO問題。把SEO需要的內容放在前端的HTML中,後端微服務只返回數據。

前後端分離案例

筆者經歷的一個前後端分離的案例:系統需要增加一個單獨的頁面來收集用戶資訊,在具體實現時採用了前後端分離的策略,前端提供交互,後端提供數據。其中前端採用Grunt作為構建框架,Karma作為單元測試框架,Phantomjs作為功能測試框架,同時引入了契約測試來保證API的一致性。後端微服務基於Twitter的開源框架Finagle實現。其前端工程的基本架構如圖5-6所示。

  • 前端直接以靜態文件的方式部署在S3上。部署非常方便,直接通過Nodejs的aws-sdk即可完成。不過需要注意的是,保證index.html最後上傳,CSS/JavaScript等資源文件先上傳,以防止index.html載入時資源文件還沒有上傳。
  • 通過Nagios做可用性檢查。因為S3是文件伺服器,無法在上面部署agent提供監控數據。在前端工程的對應文件路徑/diangnostic/status/nagios下加入供Nagios檢查的JSON文件,Nagios檢查訪問該路徑就可以知道網站的是否可用,如果出錯則推送錯誤消息到PagerDuty,再由PageDuty推送到值班的運維。

圖5-6 部署在S3上的前端工程基本架構

  • 前端的訪問日誌上傳到Splunk。S3的訪問日誌會保存到另一個S3存儲桶中,通過Splunk可以從該存儲桶中讀取到相關的訪問日誌,方便統計和問題追蹤。
  • 使用CDN。使用Akamai快取前端頁面和靜態資源文件,提升頁面載入速度。
  • 後端的API架構是典型的在EC2上部署的架構,即「ELB+EC2+ASG」,這裡不再贅述。

上面的例子將前端程式碼部署在AWSS3文件伺服器上,也可以選擇將其部署在其他公有雲的文件服務中(如華為雲的OBS服務)。自建機房可以選擇在Nginx、Haproxy等HTTP伺服器上部署前端程式碼。

5.3.6 微服務與安全

當越來越多的個人數據保存在伺服器端、雲服務上時,這些數據的安全就變得尤為重要。對於企業來說,出現安全問題除了會造成經濟損失,也會對業務穩定性和用戶信心造成重大打擊。相比單體應用,微服務架構下的安全更加重要,因為它面臨著更多新的挑戰,除了身份認證與鑒權之外,還包括如下兩方面的挑戰:

  • 微服務本身的安全。比如在API設計時如何有效地防止資訊泄露、密碼策略等。
  • 基礎設施的安全。分散式系統的網路更加複雜,對應的網路安全保護難度增大,比如如何防止DDoS攻擊,防止惡意的網站數據竊取等。系統規模增長對應會帶來伺服器數量的增長,修復作業系統的漏洞的維護挑戰很大。

除此之外,微服務的交付過程通常採用持續集成,也需要考慮在這個過程中的安全,還有在自動化部署、配置管理等方面也需要注意安全。

微服務實現時的安全

在世界品質報告(WorldQuality Report)中曾提到,大部分(約80%)的安全問題都出現在應用層。所以微服務在設計實現的時候,要特別注意安全方面的問題,尤其是在OWASPTop 10中提到的常見安全問題。

2017年最新的OWASP Top 10中最常見的應用安全問題包括注入、失效的身份認證、敏感資訊泄露、XML外部實體(XXE)、失效的訪問控制、安全配置錯誤、跨站腳本(XSS)、不安全的反序列化、使用含有已知漏洞的組件以及不足的日誌記錄和監控。

很多微服務開發框架,都提供了與安全相關的組件或者功能,比如在SpringSecurity、Rails中集成了CSRF防範的功能,通過引入這些組件或者功能,可以對微服務起到最基本的保護作用。

除利用框架支援的功能外,在微服務設計實現還可以採取以下措施來增強安全性:

  • 通過prepared statement來減少SQL注入的風險。
  • API的返回內容要做到資訊量最少,不要返回額外的資訊,防止被別人利用。
  • 對於有資源從屬關係的請求,比如/students/60/classes/10,需要注意檢查學生和班級的從屬關係,保證訪問沒有失去控制。
  • 通過添加一些HTTP響應中的安全header來提升安全性,如X-Frame-OpKons:deny來防止點擊劫持,X-XSS-ProtecKon: 1;mode=block激活瀏覽器自己的XSS防禦功能等。
  • 編碼實現時,遵從統一的安全編碼規範。

保證第三方依賴安全

微服務的技術異構性給我們帶來了技術選擇的自由,使用不同語言(Java、Python、Nodejs、Ruby)和框架來實現服務。而其帶來的一個問題是各種不同的第三方依賴迅速膨脹,任一依賴出現安全問題都會威脅服務本身的安全。所以,掌握微服務都有哪些第三方依賴很重要,這樣才能在發現安全漏洞時及時找到使用該類庫的微服務並更新以解決漏洞。

筆者曾經針對不同的語言訂製過依賴收集的插件(如Java、Scala的Maven插件、Nodejs模組等),將它們引入到微服務的依賴中,並在持續集成流水線上執行對應的任務,將依賴以JSON的形式導出並發布到文件存儲服務中。這些JSON文件會包含微服務的資訊,以及第三方依賴列表、版本號等。實際上利用了語言的構建工具列舉依賴的功能,如 mvndependency:tree,解決並循環依賴可能導致的性能問題,合入微服務相關資訊即可。

這樣的好處在於,當有第三方類庫出現安全漏洞時,可以迅速地從這些JSON文件中找到微服務是否用到這些類庫,目前的版本是否存在問題。如果需要更新,哪個微服務需要更新,1 分鐘內就可以做出決策。然後將升級的任務劃分到團隊中,提交程式碼、自動化部署之後就可以完成漏洞的更新。

密碼策略

最近幾年中國出現了好幾次拖庫事件,因為網站未對用戶的密碼加密,導致用戶資訊泄露。這種情況下,用戶得知資訊泄露的時間滯後,很難在利益受損前更新密碼。

一種應對的策略是採用加密哈希函數(CryptographicHash Function)加密用戶密碼後保存到資料庫。比如MySQL的PASSWORD函數就採用了md5/sha-1(和MySQL的版本相關)的單向散列函數進行密碼加密。好處是即便資料庫被拖庫,採用暴力破解或者字典攻擊的方式很難或者需要花費比較長的時間才能獲得用戶的明文密碼,這就給用戶爭取了重新設置密碼的時間,修復安全問題。

當然,攻擊者可以加密哈希函數預先計算值並生成彩虹表(RainbowTable)。攻擊者如果猜到了哈希函數的演算法,比如MySQL用md5或者sha-1,黑客就可以以空間換時間的方式,先計算出密碼的哈希值,然後反查密碼,隨著這個表的增長,破解的難度可能會降低,時間也會減少,最快可以在O(1)的時間複雜度內破解密碼。

要增加破解的難度,讓我們能在密碼泄露時多爭取點時間,其中的一種方式是給密碼中加點「鹽」(salt),在生成密碼的哈希值時,加入一個隨機的字元串,然後保存在資料庫中。這樣對於相同的密碼而言,在資料庫中的保存的記錄也是不同的。對於使用彩虹表破解的攻擊者來說,因為需要猜測混合salt的演算法,破解的成本很高。同樣,暴力破解也變得不太可能。

在密碼比較時,計算用戶輸入的哈希值,然後和資料庫中去掉salt的部分記錄比較,就可以驗證是否是合法用戶了。我們以Python下的bcrypt為例:

>>> hashed_password = bcrypt.hashpw("password",bcrypt.gensalt())  >>> print hashed_password  $2b$12$K947InrSXM6XvNoErbAcj.K5YQ/OSVvJ802MxSWNgXdrjmru8Grs2

這是用Blowfish密碼生成的哈希值字元串再進行base64編碼的結果,共分為4個部分,第一部分$2b$表明這是bcrypt格式的哈希;第二部分是成本(cost)值,默認是12;第三部分是22位的字元串,也就是salt的值;剩下的部分就是密碼哈希後的base64編碼的值。在比較的時候,只需要把哈希後的密碼當作salt傳進去就可以了。

Blowfish是一個symmetric-key塊分組密碼,對稱性key的意思用同樣的加密秘鑰去加密解密,就像諜戰片中用相同的密碼本解密消息。塊分組的意思就是將明文分為固定長度的塊,用秘鑰分別加密後再拼起來,並且密文應該和明文的長度相同。

另外一種加強密碼的強度的方式是給密碼撒一把「胡椒」(pepper),簡單來說就是在微服務中配置特殊的字元串,將用戶的密碼和這個字元串一起哈希,這樣可以變相地增強簡單密碼的強度,如下所示:

>>> bcrypt.hashpw("password*{abcd&",bcrypt.gensalt())  '$2b$12$2dVYv2o5vw6uMYe2IT9V9uWfIR2zdkpKDagNRZ8eFOpS4nyNHJuz.'

*{abcd&就是pepper,它以配置的形式保存在伺服器上,主要針對的場景是資料庫暴露,但是應用伺服器安全,可以拖延字典攻擊的時間,給用戶爭取足夠的時間更改密碼。

這裡筆者使用Python程式碼介紹了如何在密碼中以「撒鹽」和「胡椒」的方式進行操作,實際上主流的語言,如Java等都有這些演算法的實現,可以直接使用。

保證微服務基礎設施的安全

在基礎設施方面,與微服務安全相關的主要是網路、伺服器以及容器安全。網路方面主要是做好隔離和訪問控制,伺服器的安全方面是需要主動監測並且及時修復漏洞,容器方面主要考慮許可權、資源控制。

網路安全:

  1. 通過CDN防護攻擊。通常我們會使用CDN做快取靜態資源,但是一些CDN提供了安全方面的功能,比如Akamai提供了WAF和Site Shield的功能。WAF可以幫助識別一些攻擊,如SQL注入等,但是價格不便宜。Site Shield可以告訴Akamai快取的邊緣節點的IP地址,這樣在微服務前面的負載均衡器中可以將這些IP地址加入到白名單中,也就是說只允許來自這些邊緣伺服器的tcp請求。同時,在負載均衡器上可以阻止所有的UDP請求,這樣可以防止黑客直接攻擊源伺服器,而CDN有足夠多的資源來抵擋黑客的攻擊。通過基礎設施即程式碼,可以比較方便地以自動化的方式更新這個白名單。這些邊緣節點的IP地址的變化比較小,所以整體的維護成本也不高。
  2. 做好網路隔離。比如將微服務的實例運行在私有網路中(可以通過NAT訪問外網),而負載均衡器運行在公有網路中。不同團隊、業務的微服務,劃分到不同的網路中。
  3. 全站HTTPS。雖然HTTPS會造成性能下降,但是目前軟硬體優化的手段已經很成熟了,比如硬體加速、TLS會話恢復、TCP Fast Open、TLS壓縮等。2010年Google的Gmail已經開始默認使用HTTPS,SSL/TLS計算只佔CPU不到1%的負載,以及不到2%的網路資源,沒有使用硬體加速。
  4. PKI管理。全站HTTPS的一個難點是PKI的管理,因為對於不同的微服務,我們會使用不同的證書(IntermediateCA)。而對於需要雙向驗證的場景,還需要客戶端的證書(ClientSide Certificate)。筆者所在的團隊最早使用運維提供的腳本來統一生成證書,同時版本化管理生成的程式碼,通過RatticDB來管理密鑰。後來為了降低維護成本,採用了AWS提供商的證書服務Certificate Manager。如果不使用雲提供商的服務,還可以考慮使用如Vault這樣的工具來做PKI和密鑰的管理。此外,必須對每個微服務證書的有效性進行檢查。

伺服器的安全:

可以通過主動掃描、入侵檢測、做好SSH密鑰管理等方式來保證。

  1. 漏洞掃描。使用諸如SecurityCenter這樣的工具來掃描伺服器,查看作業系統是否存在安全漏洞,如果出現漏洞,在基礎鏡像中修復該漏洞,並通知負責微服務的團隊,採用在「5.7.5不可變部署」介紹的方式更新。
  2. 主動安全檢測。如使用OSSEC進行入侵檢測,通過日誌採集工具收集檢測的日誌,並在日誌伺服器上配置報警規則,當檢測到入侵時發出警報,然後啟動安全應對流程。
  3. 密鑰管理。對於部署不同微服務的伺服器,使用不同的SSH密鑰去訪問,防止一個伺服器被入侵,影響其他的伺服器。密鑰可以通過專門的工具管理起來,如RatticDB或者Vault,這些系統對接LDAP後,可以以比較小的代價實現對密鑰的訪問控制。如果採用了在「5.7部署管理實踐」中提到的好的實踐,甚至可以不需要SSH到伺服器上就能獲取想了解的內容,比如日誌資訊等,所以SSH服務並非必須的服務,可以關閉,這樣節省了密鑰管理的成本。

容器安全:

  1. 容器中運行的微服務進程不要使用root用戶啟動。
  2. 容器運行時可設置為對宿主機的文件系統只讀。容器運行時,如果需要通過掛載的方式讀取宿主機的文件,在掛載時設置為只讀。對於需要寫到文件系統的內容如日誌,可以通過事件流發送到日誌轉發工具中。
  3. 限制容器運行能使用的資源,防止它佔用過多資源影響宿主機上運行的其他容器。
  4. 在宿主機上通過Selinux或者AppArmor做更嚴格的訪問許可權控制。
  5. 加強DockerRegistry的安全,可以參考「通過安全加固的Docker Registry去管理鏡像」中實現的方式。

其他安全方面的實踐

鑒於安全的重要性,應當在微服務的整個生命周期中都嵌入對安全的考量。比如在微服務的設計過程中,需要安全專家的參與,考慮架構的安全性,在實現的過程中也需要考慮編碼的安全性,此外還有測試、部署維護等方面。這樣的實踐也被稱為安全內建(BuildSecurity In)。

做到安全內建,除了上面介紹的部分,還需要在以下方面考慮安全問題:

  1. 開發過程。通過LDAP、OKTA等工具做統一身份驗證,既給予開發人員足夠但有限的許可權,同時定時更換密碼(如一個月一次)。
  2. 測試過程。可以將安全測試作為自動化測試的一部分集成到持續集成流水線中。比如用Zap、Brakeman等工具對微服務的程式碼進行掃描,看看程式碼是否存在安全漏洞,如SQL注入漏洞等。
  3. 部署過程。加密,諸如密碼等關鍵配置,只有在伺服器上部署前才解密,並且過程不可見。
  4. 生產環境運行過程。通過主動掃描,或者付費給第三方的白帽子組織掃描,發現應用的安全風險,並在黑客找到漏洞之前修復。

在微服務架構下,安全是需要重點考慮的因素。在處理安全問題時,要兼顧業務交付的速度,合理地安排安全問題修復的優先順序,通過良好的實踐,如不可變部署、基於鏡像部署等方式,降低安全問題修復的成本。從而實現業務交付和安全的雙贏。