論微服務安全

每一個人都在討論微服務,每一個人也都但願可以實現微服務架構,而微服務安全也日漸成爲你們關注的重要問題。今天小數與你們分享的文章,就從應用層面深刻探討了應對微服務安全挑戰的方案,爲微服務安全提供了新的思路。緩存

面向服務架構(簡稱SOA)引入了一類設計規範,其核心思路在於採用高度解耦式服務部署,其中各項服務可經過一套標準信息格式經由網絡實現彼此通訊。這套方案與具體技術無關,即不考慮各項服務具體是如何實現的。每項服務都擁有一個明肯定義,用於發佈服務描述或者服務接口。在實踐當中,這類信息格式經過SOAP實現標準化——即由W3C於2000年初推出的一項標準——同時亦基於XML——其中服務描述由WSDL(另外一項W3C標準)進行標準化,而服務發現標準由UDDI(一樣爲W3C標準)實現。這一切正是基於SOAP的Web服務的實現基礎,甚至使得Web服務在必定程度上成了SOA的代名詞。不過這種實現方式在架構模式層面也有着本身的缺陷。SOA的基本原則正被時代所逐步淘汰,現在由OASIS提供的WS-*堆棧(包括WS-Security, WS-Policy, WS-Security Policy,WS-Trust, WS-Federation, WS-Secure Conversation, WS-Reliable Messaging, WS-Atomic Transactions, WS-BPEL等等)令SOA的複雜性不斷提升,這也直接致使不少普通開發者發現本身很難對其加以駕馭。安全

多年以後,現在咱們得以再次開啓這段通往SOA基本原則的旅途——但這一次它有了新的名號,即微服務。微服務可以爲應用程序設計提供一種更具針對性、範圍性與模塊性的實現方案。服務器

微服務可謂當下一大熱門詞彙之一,與之並駕齊驅的則包括物聯網、容器化與區塊鏈。「微服務」一詞最初於2011年5月亮相於威尼斯軟件架構師研討會。這個詞彙用於解釋一類常見的架構類型。網絡

你們已經意識到微服務並不只僅是作對了的SOA,它也不僅是一種架構模式——而是一種圍繞架構模式展開的全新文化。其由主要目標做爲驅動力,旨在實現快速部署與快速生產。架構

在保護微服務安全時,須要從如下幾個角度入手:框架

  • 保護開發生命週期與測試自動化機制:微服務背後的核心驅動力在於提高投付生產的速度。咱們須要向服務當中引入變動,加以測試然後當即將成果部署至生產環境。爲了確保在代碼層面中不存在安全漏洞,咱們須要制定規劃以進行靜態代碼分析與動態測試——更重要的是,這些測試應當成爲持續交付流程的組成部分。任何安全漏洞都須要在早期開發週期內被發現,另外反饋週期也必須儘量獲得縮短。分佈式

  • DevOps安全:微服務部署模式可謂多種多樣——但其中使用最爲普遍的當數每主機服務模式。其中的主機指定的並不必定是物理設備——也極可能屬於容器(Docker)。咱們須要對容器層面的安全進行關注。咱們該如何確保各容器之間獲得有效隔離,又該在容器與主機操做系統之間採起怎樣的隔離水平?ide

  • 應用級別安全:咱們該如何驗證用戶身份並對其微服務訪問操做進行控制,又要怎樣保障不一樣微服務之間的通訊安全?微服務

在今天的文章中,咱們將提供一整套安全模式,旨在解決應用層級所面臨的各種微服務安全保護挑戰。性能

單體應用VS微服務

在總體型應用程序中,全部服務都被部署在同一應用服務器當中,而該應用服務器自己則提供會話管理功能。其中不一樣服務間的接口爲本地調用,且所有服務皆可共享用戶的邏輯狀態。每項服務(或者組件)不須要對用戶進行驗證。驗證工做集中由攔截器處理,其攔截全部服務調用並審查其是否能夠放行。驗證完成以後,其會在不一樣平臺上的不一樣服務(或者組件)間發送用戶登陸憑證。如下示意圖解釋了總體應用程序中各不一樣組件間的交互方式。

圖片描述

在Java EE環境下,攔截器能夠由servlet過濾器充當。該servlet過濾器會攔截所有來自其已註冊上下文的請求,並強制進行驗證。該服務調用要麼攜帶有效的憑證,要麼擁有可以映射至某個用戶的會話令牌。一旦servlet過濾器找到該用戶,則會建立登陸上下文,並將其傳遞給下游組件。每一個下游組件都可以從該登陸上下文內識別出用戶以完成受權。

在微服務環境下,安全性每每成爲最大的挑戰。在微服務架構當中,各服務分佈及部署在分佈式設置當中的多套容器以內。各服務接口再也不存在於本地,而是經過HTTP進行遠程接入。如下示意圖顯示了不一樣微服務之間的交互方式。

圖片描述

這裏的挑戰在於,咱們要如何驗證用戶並在不一樣微服務之間以對稱方式完成登陸上下文傳遞,隨後還要想辦法讓微服務完成對用戶的受權。

保護服務到服務通訊

在今天的文章中,咱們將探討兩套方案,旨在保護服務到服務通訊。其一基於JWT,其二則基於TLS相互驗證。

JSON Web令牌(簡稱JWT)

圖片描述

JWT(即JSON Web令牌)負責定義一套容器,旨在完成各方之間的數據傳輸。其可用於:

  • 在各方之間傳播其中一方的身份。

  • 在各方之間傳播用戶權利。

  • 經過非安全通道在各方之間安全實現數據傳輸。

  • 根據JWT受信指標判斷用戶身份。

已簽名JWT被稱爲JWS(即JSON Web簽名),而加密JWT則被稱爲JWE(即JSON Web加密)。事實上,JWT並不會以自身原始方式存在——其要麼做爲JWS,要麼做爲JWE,它像是一種抽象類——JWS與JWE爲其具體實現方式。

來自某一微服務並將被傳遞至另外一微服務的用戶上下文可伴隨JWS一同傳遞。因爲JWS由上游微服務的某一已知密鑰進行簽名,所以JWS會同時包含有最終用戶身份(在JWT中聲明)以及上游微服務身份(經過簽名實現)。爲了接收JWS,下游微服務首先須要根據JWS自己中的嵌入公鑰對JWS的簽名進行驗證。這還不夠,咱們還須要檢查該密鑰是否受信。不一樣微服務之間可經過多種方式創建受信關係。其一爲由服務爲各服務配置受信證書。很明顯,這種方式在規模化微服務部署環境中並不可行。所以我建議你們創建一套專有證書中心(簡稱CA),同時能夠爲不一樣微服務組設置中介證書中心。如今,相較於互相信任及各自分配不一樣的證書,下游微服務將只須要信任根證書受權或者中介機制便可。這可以顯著下降證書配置所帶來的管理負擔。

JWT驗證的成本

每項微服務都須要承擔JWT驗證成本,其中還包含用於驗證令牌簽名的加密操做。微服務層級中的JWT會進行緩存,而非每次進行數據提取,這就下降了重複令牌驗證形成的性能影響。緩存過時時間必須與JWT的到期時間相匹配。正是因爲利用這種機制,所以若是JWT的過時時間設定得過短,則會給緩存性能形成嚴重影響。

驗證用戶

JWT在其聲明集中包含一項參數,名爲sub,其表明擁有該JWT的主體或者用戶。JWT自己也能夠包含各種用戶屬性,例如first_name、last_name、email等等。若是任何微服務須要在其操做過程當中識別此用戶,則須要查看對應的屬性。Sub屬性的值對於給定發行者而言是唯一的。若是你們擁有一項微服務,其可以從多個發行者處接收令牌,那麼該用戶的唯一性應被認定爲該發行者與sub屬性的結合體。

而aud參數一樣存在於JWT聲明集內,負責指定令牌的目標受衆。其能夠是單個接收者或者是一組接收者。在執行任何驗證檢查以前,該令牌接收者都必須首先查看是否發佈了特定JWT供其使用,若是沒有則當即拒絕。令牌發送方須要在發出令牌以前,肯定該令牌實際接收者的身份,同時aud參數值必須屬於令牌發送方與接收方間預先約定的值。在微服務環境中,咱們能夠利用正規表達式來驗證令牌受衆。舉例來講,令牌中的aud值能夠爲*.facilelogin.com,意味着facilelogin.com域名下的每一個接收方(例如foo.facilelogin.com,bar.facilelogin.com等)都可以擁有本身的aud值。

TLS相互身份驗證

在TLS相互驗證與JWT方法當中,每項微服務都須要擁有本身的證書。這兩種方法的區別在於,JWT驗證機制中JWS可同時攜帶最終用戶身份以及上游服務身份。而TLS相互驗證則只在應用層傳輸最終用戶身份。

證書吊銷

在以上提到的兩種方案當中,證書吊銷都是項棘手的任務。證書吊銷儘管難以實現,但仍然存在多種選項供咱們選擇:

  • CRL (證書吊銷列表 / RFC 2459)

  • OCSP (在線證書狀態協議 / RFC 2560)

  • OCSP Stapling (RFC 6066)

  • OCSP Stapling Required (尚處於草案階段)

CRL的使用頻率並不高。客戶端在發起TLS握手時,必須從對應的證書頒發中心處獲取一份長長的吊銷證書列表,然後檢查服務器證書是否被列入該列表。相較於每一次進行列表獲取,客戶端能夠在本地對CRL進行緩存。在此以後,你們還須要考慮如何避免以陳舊數據爲基礎作出判斷的問題。當TLS相互驗證機制被使用時,服務器也須要針對客戶端進行一樣的證書驗證。最終,人們發現CRL的實際效果其實並不理想,所以新的解決方案也應運而生——這就是OCSP。

在OCSP當中,一切元素的實際效果都要比CRL好上那麼一點。TLS客戶端可以檢查特定證書的狀態,且無需從證書中心處下載完整的吊銷證書列表。換句話來講,當客戶端每次與新的下游微服務進行通訊時,其都必須同對應的OCSP響應方溝通以驗證當前服務器(或者服務)的證書狀態——而服務器則必須面向客戶端證書執行一樣的操做。如此一來,OCSP響應方一樣面臨着巨大的流量壓力。基於一樣的考慮,客戶端仍然能夠對OCSP決策進行緩存,但這無疑繼續帶來一樣的、基於陳舊數據進行決策的可能性。

而OCSP stapling的出現令客戶端再也不須要每次同下遊微服務進行通訊時,都與OCSP響應方「打招呼」。該下游微服務將從對應的OCSP響應方處獲取OCSP響應,以及staple,或者將響應附加到證書自己當中。因爲OCSP響應獲得了對應證書中心的簽名,所以該客戶端可以驗證經過其簽名並接收此響應。這種方法令事情有了起色,事實上現在是由服務而非客戶端與OCSP響應方進行通訊。不過在TLS相互驗證模式下,OCSP stapling相較於原始OCSP沒法帶來任何額外優點。

因爲OCPS必須配合stapling,該服務(即下游服務)須要向客戶端(即上游服務)提供保證,證實OCSP響應被附加到了該服務在TLS握手時接收到的證書中。若是OCSP響應未被附加至該證書中,那麼結果並不是出現軟錯誤,而是客戶端必須當即拒絕該鏈接。

臨時證書

從最終用戶的角度來看,臨時證書的效果與目前的常規證書並沒有區別,只不過暫時證書的過時時間很是之短。TLS客戶端並不須要針對臨時證書進行CRL或者OCSP驗證,而是堅持設定好的過時時間,並對證書自己進行時間戳加蓋。

Netflix與臨時證書

圖片描述

臨時證書帶來的最大挑戰在於其部署與維護工做。自動則正是解決這些難題的靈丹妙藥。Netflix公司建議使用分層方案以構建臨時證書部署機制。你們能夠在TPM(即受信平臺模塊)或者SGX(軟件保護擴展)當中得到系統身份或者長期證書,從而顯著提高安全性。在此以後,再使用這些憑證做爲臨時證書。最後,在微服務中使用臨時證書——這些證書亦可由其它微服務使用。每項微服務都可以利用自身長期證書對臨時證書進行按期刷新。固然,僅僅擁有臨時證書還不夠——託管該服務(或者TLS終止器)的主機應當支持對服務器證書的動態更新。目前存在大量可以運行服務器證書動態重載的TLS終止器,但其中大多數可能會致使短暫的服務停機。

邊界安全

微服務集與外部世界的連通通常經由API網關模式實現。利用API網關模式,須要進行聲明的微服務可以在該網關內得到對應的API。固然,並非全部微服務都須要立足於API網關實現聲明。

圖片描述

最終用戶對微服務的訪問(經過API實現)應當在邊界或者API網關處進行驗證。目前最爲常見的API安全保護模式爲OAuth 2.0。

OAuth 2.0

OAuth 2.0是一套做爲訪問表明的框架。它容許某方對另外一方進行某種操做。OAuth 2.0引入了一系列grant types。其中之一用於解釋協議,客戶端可利用此協議獲取資源擁有方的許可,從而表明擁有方進行資源訪問。另外,還有部分grant types可解釋用於獲取令牌的協議,且整個操做徹底等同於由資源擁有方執行——換言之,該客戶在這種狀況下即至關於資源擁有方。如下示意圖解釋了OAuth 2.0協議的宏觀實現流程。其中描述了OAuth客戶端、資源擁有方、驗證服務器以及資源服務器之間的交互方式。

圖片描述

要想經過API網關訪問某項微服務,請求發起方必須首先得到有效的OAuth令牌。系統可以以自身角色訪問微服務,也能夠做爲其餘用戶實現訪問。對於後一種狀況,假設用戶登陸至某Web應用,那麼此後該Web應用便可以所登陸用戶的身份進行微服務訪問。

圖片描述

下面來看端到端通訊的具體實現方式,如上圖所顯示:

  • 用戶經過Identity Provider登陸至Web應用/移動應用,而Web應用/移動應用則經過OpenID Connect(也能夠是SAML 2.0)信任該Provider。

  • 該Web應用獲取一條OAuth 2.0 access_token與一條id_token。其中id_token將驗證訪問該Web應用的最終用戶。若是使用SAML 2.0,則該Web應用須要與其信任的OAuth驗證服務器的token端點進行通訊,同時將SAML令牌交換爲一條OAuth acess_token,隨後交換OAuth 2.0的SAML 2.0 grant type。

  • 該Web應用會做爲最終用戶調用一個API——並隨同API請求發送access_token。

  • API網關會攔截來自該Web應用的請求,提取access_token,與令牌交換端點(或者STS)進行通訊,並由後者驗證該acess_token,然後向該API網關提供JWT(由其簽名)。此JWT還攜帶有用戶上下文。在STS對acess_token進行驗證時,其還將經過introspection API與對應的OAuth受權服務器進行通訊。

  • API網關向下遊微服務將同時發出請求與JWT。

  • 每項微服務都會驗證其接收到的JWT,然後做爲下游服務調用,其可以建立新的自簽名JWT並將其與該請求一同發送。在其它方案中,亦會用到嵌套JWT——即由新的JWT攜帶上一JWT。

在上述流程當中,來自外部客戶端的API請求將經由該API網關。當某項微服務與其它微服務通訊時,其將再也不須要通過該網關。另外,從特定微服務的角度來看,不管你們是從外部客戶端仍是其它微服務處獲取請求,得到的都是JWT——也就是說,這是一種對稱安全模式。

訪問控制

受權屬於一項業務功能。每項微服務能夠決定使用何種標準以容許各項訪問操做。從簡單的受權角度來說,咱們能夠檢查特定用戶是否向特定資源執行了特定操做。將操做與資源加以結合,也就構成了權限。受權檢查會評估特定用戶是否具有訪問特定資源的最低必要權限集合。該資源可以定義誰能夠進行訪問,可在訪問中具體執行哪些操做。爲特定資源聲明必要權限可經過多種方式實現。

XACML (可擴展訪問控制標記語言)

XACML已經成爲細粒度訪問控制領域的客觀標準。其引入的方式可以表明訪問某種資源所須要的權限集,且具體方法採用基於XML的特定域語言(簡稱DSL)編寫而成。

圖片描述

上圖所示爲XACML組件架構。首先,策略管理員須要經過PAP(即策略管理點)定義XACML策略,而這些策略將被保存在策略存儲內。要檢查特定實體是否擁有訪問某種資源的權限,PEP(即策略執行點)須要攔截該訪問請求、建立一條XACML請求並將其發送至XACML PDP(即策略決策點)。該XACML請求可以攜帶任何有助於在PDP上執行決策流程的屬性。舉例來講,其可以包含拒絕標識符、資源標識符以及特定對象將對目標資源執行的操做。須要進行用戶受權的微服務則須要與該PDP通訊並從JWT中提取相關屬性,從而創建XACML請求。PIP(即策略信息點)會在PDP發現XACML請求中不存在策略評估所要求的特定屬性時介入。在此以後,PDP會與PIP通訊以找到缺失的對應屬性。PIP可以接入相關數據存儲,找到該屬性然後將其返回至PDP。

圖片描述

嵌入式PDP

遠程PDP模式存在幾大弊端,其可能與微服務的基本原則發生衝突:

  • 性能成本:每一次被要求執行訪問控制檢查時,對應微服務都須要經過線纜與PDP進行通訊。當該決策被緩存在客戶端時,此類傳輸成本與策略評估成本將獲得有效下降。不過在使用緩存機制時,咱們亦有可能根據陳舊數據進行安全決策。

  • 策略信息點(簡稱PIP)的全部權:每項微服務都應當擁有本身的PIP,其瞭解要從哪裏引入實現訪問控制所必需的數據。在以上方案中,咱們創建起的一套「總體式」PDP,其中包含所有PIP——對應所有微服務。

圖片描述

如上圖所示,嵌入式PDP將遵循一類事件模式,其中每項微服務都會訂閱其感興趣的主題以從PAP處獲取合適的訪問控制策略,然後更新其內嵌PDP。你們能夠經過微服務組或者全局多租戶模型獲取PAP。當出現新策略或者策略存在更新時,該PAP會向對應的主題發佈事件。

這套方案不會違反微服務中的「服務器不變」原則。「服務器不變」意味着當你們在持續交付流程結尾處,直接利用加載自庫的配置構建服務器或者容器時,整個建立流程應該可以基於一樣的配置進行不斷重複。所以,咱們不但願任何用戶登入服務器並對配置作出變動。在內嵌PDP模式下,儘管服務器會加載對應的策略,但其仍同時處於運行當中。這意味着當咱們啓動新容器時,其仍然立足於一樣的策略集。

在結束本篇文章以前,咱們還有另外一個重要的問題須要回答,即API網關在受權上下文中到底扮演着怎樣的角色。咱們能夠設置全局可訪問的訪問控制策略——其可用於最終用戶,並由網關進行強制執行——但沒法設置服務層級的策略。由於顧名思義,服務層策略必須在服務層上執行。

相關文章
相關標籤/搜索