天天看點

dubbo-go 可信 RPC 調用實作

Apache Dubbo/Dubbo-Go 作為阿裡巴巴開源的一款服務治理架構,因其适應 Java/Go 開發者面向接口的程式設計習慣、完全透明的調用方式、優越的性能以及強大的擴充性等優點,在國内使用非常廣泛。除此之外,Dubbo 開源版本原生內建了很多開箱即用的服務治理功能,包括鍊路追蹤,路由、負載均衡、服務注冊發現、監控、認證等。

本文将講解如何在 Dubbo/Dubbo-Go 中實作靈活、安全和高效的身份驗證和授權方案。

定義可信

何為可信?可信的定義很廣泛,依場景不同有不同的定義。在微服務架構中,每個服務都是無狀态的,多個服務之間不可信,為了實作服務間更好地隔離,服務間應進行認證和鑒權。

如支付之類的業務場景,安全性敏感的服務會有限制匿名系統調用的需求,其他業務在接入該類敏感業務之前,需要通過審批方可正常調用,這就需要對這類敏感服務進行權限管控。盡管 Dubbo 開源版本中支援 Token 方式的鑒權實作,但是該實作方式總體來說安全性并不高,并且無法滿足我們需要動态下發以及變更的靈活性需求。

針對于此,我們内部着重從鞏固安全性和拓展靈活性層面重新設計了一套 Dubbo/Dubbo-Go 的服務間調用的鑒權認證功能。本文我們将主要從實作層面講解其大緻實作思路。

可信方案

總體而言,鑒權認證主要讨論以下兩個問題:

1、身份認證:指驗證應用的身份,每個應用在其生命周期内隻有唯一身份,無法變更和僞造。

2、權限鑒定:根據身份資訊鑒定權限是否滿足調用。權限粒度可以進行控制。

我們通過 Access Key ID/Secret Access Key (後文簡稱為 AK/SK) 資訊辨別應用和應用之間的身份關系。例如上遊 應用A 依賴下遊 服務B 和 C,則 A 對 B 和 C 分别有一套 AK/SK,其互相獨立沒有任何關系,就算 A服務 的 AK/SK 資訊洩漏,也無法通過該 AK/SK 資訊調用其他的服務。

在權限鑒定方面也借鑒了公有雲開放 API 常用的 AK/SK 簽名機制。在請求過程中使用 SK 簽名生成 SigningKey,并通過 Dubbo 的 attachment 機制将額外的中繼資料資訊以及 SigningKey 傳輸到服務端,交由服務端計算和驗簽,驗簽通過方能正常處理和響應。

簽名過程主要通過如下三個方式進行加強 SigningKey 的可靠性和安全性。

1、驗證請求者的身份,簽名會通過對應應用的SK作為加密密鑰對請求中繼資料(以及參數)進行加密,保證簽名的唯一性和不可僞造性。

2、支援對參數進行計算簽名,防止非法篡改,若請求參數在傳輸過程中遭到非法篡改,則收到請求後服務端驗簽比對将失敗,身份校驗無法通過,進而防止請求參數被篡改。考慮到簽名以及驗簽過程中加入請求參數的計算可能會影響性能,這個過程是可選的。

3、防止重播攻擊,每一次請求生成的SigningKey都具有指定的有效時間,如請求被截獲,該請求無法在有效時間外進行調用,一定程度避免了重播攻擊。

同時為了去掉明文配置,防止 AK/SK 資訊洩漏,我們通過鑒權系統分發和管理所有 AK/SK 資訊。通過對接内部審批流程,達到流程化和規範化,需要鑒權的應用會通過啟動擷取的方式拉目前應用分發出去或者是已被授權的 AK/SK 資訊。這種方式也帶來了另一種好處,新增、吊銷以及更新權限資訊也無需重新開機應用。

可信流程

結合上面的這些需求和方案,整個接入和鑒權流程圖如下所示:

dubbo-go 可信 RPC 調用實作

整體流程如下:

1、使用該功能的應用需要提前申請對應的證書,并向提供服務的應用送出申請通路工單,由雙方負責人審批通過後,請求鑒權服務中心自動生成鍵值對。

2、開啟鑒權認證的服務在應用啟動之後,會運作一個背景線程,長輪詢遠鑒權服務中心,查詢是否有新增權限變動資訊,如果有則進行全量/增量的拉取。

3、上遊應用在請求需要鑒權的服務時,會通過 SK 作為簽名算法的 key,對本次請求的中繼資料資訊甚至是參數資訊進行計算得到簽名,通過 Dubbo 協定 Attachment 字段傳送到對端,除此之外還有請求時間戳、AK 資訊等資訊。

4、下遊應用在處理鑒權服務時會對請求驗簽,驗簽通過則繼續處理請求,否則直接傳回異常。

其中需要說明的是第三步,使用鑒權服務的應用和鑒權服務中心的互動需通過 HTTPS 的雙向認證,并在 TLS 信道上進行資料互動,保證 AK/SK 資訊傳輸的安全性。

該方案目前已經有 Java/Go 實作,均已合并到 dubbo/dubbo-go。除了預設的 Hmac 簽名算法實作之外,我們将簽名和認證方法進行抽象,以 dubbo-go中的實作為例:

// Authenticator

type Authenticator interface {

// Sign
// give a sign to request
Sign(protocol.Invocation, *common.URL) error
// Authenticate
// verify the signature of the request is valid or not
Authenticate(protocol.Invocation, *common.URL) error           

}

使用者可通過 SPI 機制定制簽名和認證方式,以及适配公司内部基礎設施的密鑰服務下發 AK/SK。

示例

以 Helloworld 示例 中的代碼接入目前社群版本中的預設鑒權認證功能實作為例:

Helloworld 示例:

https://github.com/apache/dubbo-samples/tree/master/golang/helloworld/dubbo

在無需改變代碼的情況下,隻需要在配置上增加額外的相關鑒權配置即可,dubbo-go 服務端配置示例如下:

services:
  "UserProvider":
    # 可以指定多個registry,使用逗号隔開;不指定預設向所有注冊中心注冊
    registry: "hangzhouzk"
    protocol : "dubbo"
    # 相當于dubbo.xml中的interface
    interface : "com.ikurento.user.UserProvider"
    loadbalance: "random"
    # 本服務開啟auth
    auth: "true"  
    # 啟用auth filter,對請求進行驗簽
    filter: "auth"
    # 預設實作通過配置檔案配置AK、SK
    params:
      .accessKeyId: "SYD8-23DF"
      .secretAccessKey: "BSDY-FDF1"
    warmup: "100"
    cluster: "failover"
    methods:
      - name: "GetUser"
        retries: 1
        loadbalance: "random"
           

dubbo-go 用戶端配置示例如下:

references:
  "UserProvider":
    # 可以指定多個registry,使用逗号隔開;不指定預設向所有注冊中心注冊
    registry: "hangzhouzk"
    protocol: "dubbo"
    interface: "com.ikurento.user.UserProvider"
    cluster: "failover"
    # 本服務開啟sign filter,需要簽名
    filter: "sign"
    # 預設實作通過配置檔案配置AK、SK
    params:
      .accessKeyId: "SYD8-23DF"
      .secretAccessKey: "BSDY-FDF1"
    methods:
      - name: "GetUser"
        retries: 3
           

可以看到,dubbo-go 接入鑒權認證的功能也十分簡單。需要補充說明的是,配置檔案檔案中 ak/sk 都加了特殊字首 ".",是為了說明該字段是敏感資訊,不能在發起網絡請求時傳輸出去,相關代碼可參閱 dubbo-go-pr-509。

dubbo-go-pr-509:

https://github.com/apache/dubbo-go/pull/509

總結

Apache Dubbo 作為一款老而彌新的服務治理架構,無論是其自身還是其生态都還在飛速進化中。本文描述的最新實作的可信服務調用,是為了避免敏感接口被匿名使用者調用而在 SDK 層面提供的額外保障,在 RPC 層面保障安全性。

dubbo-go 作為 Dubbo 生态中發展最快的成員,目前基本上保持與 Dubbo 齊頭并進的态勢。dubbo-go 社群釘釘群号為 23331795, 歡迎你的加入。

作者資訊:鄭澤超,Apache Dubbo/Dubbo-Go committer,GithubID: CodingSinger,目前就職于上海愛奇藝科技有限公司,Java/Golang 開發工程師。