SaaS 關鍵設計 - Multi-Tenancy - 探討真實世界的租賃關係


多租戶架構 (Mulit-Tenancy Architecture, 以下稱作 MTA)SaaS (Software as a Service, 軟體及服務) 設計的核心議題,也是我過去幾年工作研究的題目之一,大部分的人針對這個題目討論的多是 K8s 的 Namespace 劃分、或者資料庫的拆分方式、使用 Single or Shared / Hybrid … 等策略。

多租戶架構背後需要討論的,除了這些技術架構的議題,更重要的是往前一步:

SaaS 的 多租戶 應該怎麼定義?以及能夠解決那些問題?

基於這些討論與實踐,最後我提出設計 MTA 的關鍵抽象概念,我把它稱為 Isolation Factor (隔離因子)

這篇文章嘗試解釋與探討 多租戶 背景與核心議題,同時用真實世界的租賃關係,剖析設計 SaaS 時必須要知道的概念,嘗試帶出 Isolation Factor 的重要性。

相關文章:


真實世界裡的租賃關係

在真實的世界中,有幾種角色關係:

  • 房東 (Landlord):出租房子的人成為房東
    • 英文用詞:Landlord, Landlady
    • 物件在法律上的資產擁有者,具備 擁有權
    • 對於物件有 管理權 以及 使用權
    • 承租合約成立區間,不具備使用權
  • 房客 (Lodger):指的是房子的承租者 (人) - 中文叫做 租戶房客承租人、或 佃戶
    • 英文用詞:Lodger、Tenant
    • 承租對象的是房東提供的 承租物件
    • 在雙方約定的時間範圍之內,房客 具備 承租物件的 使用權
    • 約定時間之內,非特定情境,房東 不具備 承租物件的使用權
  • 承租物件 (Object) :與租戶對應的房子稱為 承租物件 (Object)、出租處
    • 英文用詞:老美稱為 apartment、英國稱為 flat。
    • 承租物件內部使用稱為使用權,物件以外稱為管理權
    • 物件以外,在真實世界稱為公共空間、公共設施、公共區域 … etc.
  • 合約 (Rental Agreements):指房東 / 租戶 雙方對於 承租物件 的使用權 承諾
    • 合約包含以下資訊:
      1. 房客 (who) 識別資訊,通常是個人身份、職業,目的是用來識別法律上的效益。
      2. 允許使用的 時間範圍 (when)
      3. 對於承租物件的 權利與義務 (what)
      4. 更多參閱 Rental agreement
    • 用詞:tenancy (租賃),通常用在房屋、土地等不動產的
  • 承租 (Lease, v):租戶向房東簽訂使用合約,整個動作稱為 承租
  • 使用權: 泛指承租者 (房客) 在合約期限內,對於承租物件的使用範圍,其中包含承租物件本身以及公共區域的使用權
  • 管理權: 承租物件內部與外部的管制與控制
  • 擁有權 (Ownership): 泛指資產在法律上賦予的擁有權

這些關係稱為 租賃 (Tenancy),概念如下圖所示:

了解基本租賃的幾個角色、關係之後,我想把主軸放在 房東承租物件房客 這三者的關係,然後套到的 SaaS 設計裡。

註:雖然房客 (Lodger) 的英文也可以是 Tenant 這個字,但是實際上中文口語上描述 租戶 的時候,可以意指 人 (房客)、或者是 承租物件 (Object),通常要看前後文判斷,本文會直接使用 Object 直接代表承租房子,避免語意錯置。

其他專有名詞

  • 垂直權限
  • 水平權限
  • 仿登入 (impersonate), 概念類似 sudo / run as xxx
  • RBAC (Role-Based Access Control)
  • ABAC (Role-Based Access Control)

背景探討:各種租賃組合

租賃關係的排列組合

Multi-Tenancy 這個字,中文翻譯成:多租戶,字面上看似容易理解,但在設計與實作時,卻很容易做出有問題的設計。接下用 房東 (Landlord)承租物件 (Object)、以及 房客 (Lodger),三者的數量關係,分別探討各種形式的租賃關係。

三個變動因子,每個變動因子都有 一個多個 兩種選項,其排列組合列舉如下表:

探討過程,我會嘗試用真實世界的案例帶入,如果沒有舉例的,可能是我自己經歷不夠、想像力不足,或者是 … 排列組合根本就不合理。

首先先從 多租戶 這個詞的相對詞:單一租戶 Single Tenant 切入。

Case A: Single Tenant

Single Tenant 指的是 一個房東 可以提供 一個物件一個房客 承租 ,完成 一個租賃合約,這三者的關係如下圖:

這三者是一對一對一的關係:

房東:承租物件:房客 = 1:1:1

生活中常見的例子,像是一個大樓的 (一個) 房東,將一整棟大樓租賃給一家企業。

  • 一個房東
  • 一棟大樓
  • 一家企業

Case B: Multiple Tenant

房東只有一個物件可以承租給房客?雖然有,但是不是普通鄉民會接觸的。

生活中更多的例子會是一個房東同時擁有多個物件可以出租,也就是 一個房東 可以提供 多個物件多個房客 承租 ,完成 多個租賃合約,這三者的關係如下圖:

這三者的關係是:

房東:承租物件:房客 = 1:N:N

注意,這裡描述 承租物件房客 兩者是一對一關係,也就是每一個物件,只承租給一個客戶。不是一個物件,承租給多個客戶,這種結構在最後會描述。

在真實世界的租賃中,承租物件已經具備明確的 邊界 (Border),像是房屋都具備具象化的牆壁、隔間、房門等邊界,所以房內屬於私人區域、以外則公共區域,公私領域的邊界是清楚,且明確的。

而所謂的 多租戶 這個詞背後隱含的是:

相對於房東而言,也就是我們都是站在房東角度在論述。

這句話很重要,請留意思考的切入角度 (角色),本文全文的論述其實都是房東角度。

Case C

上述 Case A: Single TenantCase B: Multiple Tenant 是真實世界常見的例子,屬於正常、合理的例子。

接下來我們來探討第三個例子,其結構如下圖:

這三者關係是:

房東:承租物件:房客 = 1:N:1

這個意思是,一個房東,擁有 N 個物件,但是都租給同一個房客,會有這樣的案例?現實生活中,也許有吧?不曉得 … 貧窮限制我的想像啊。。。。

Case D

排列組合還有,繼續推演下一個狀況:

這三者關係是:

房東:承租物件:房客 = 1:1:N

這個狀況的意思是:

一個房東的其中一個物件,同時租給多個房客,背後有多個契約。

真實案例像是青年旅館,一個大通鋪,一堆人住一個晚上。在 IT 系統裡,有點像是一家公司申請一個 AWS Account,在裡面部署一套系統,這套系統,同時租賃給多個客戶使用。


探討

上一段整理了四個排列組合,真實世界的運作往往會比這些單一排列組合更複雜,更多的是複合式的組合。

我們就用這四個為基礎單位,探討真實世界的組合。

探討一:Case X1 = Case B + D

上述 Case B / D 有著很類似的概念,不過看到這裡的讀者可能腦袋也打結了 XD

重新整理這兩者的關係如下:

Case B:

房東:承租物件:房客 = 1:N:N

Case D

房東:承租物件:房客 = 1:1:N

把這兩個 Case 合併成 Case X1 如下圖:

用 AWS 的角度舉例說明,圖中的角色分別如下:

  • Landlard: AWS
  • Object: AWS Account
  • Lodgers: AWS IAM 裡的 User

這個例子,如果用過 AWS 的人應該不難理解,不過要留意的是,每個 AWS Account 裡的資源彼此是看不到彼此的,像是:

  • User#A @ Object#A 是無法直接跟 User#A @ Object#B 對話的
  • Object#B 是無法得知 Object#A 裡有哪些 Users
  • User#A @ Object#A 不等於 User#A @ Object#B

上面的描述,背後隱含的關鍵意義就是 Object 之間是 隔離 的,而且是強制性的隔離。

換 GCP 的例子:

  • Landlard: GCP
  • Object: GCP Project
  • Lodgers: GCP Project IAM User

這個也不難理解,同樣可以舉例出 Object 之間隔離的概念,也完全與 AWS 一致。

GCP 與 AWS 的隔離概念稱為 垂直權限 (Vertical Authority)

繼續下一個例子是 K8s:

  • Landlard: K8s Cluster
  • Object: by Namespace
  • Lodgers: Application or Developer

K8s 開始出現一個狀況,所謂的 Namespace 只是邏輯概念切割,也就是資源之間的並不是 強隔離

探討二:二房東 Case X2

上述 Case E 用 AWS / GCP / K8s 當例子,但更多時候企業在發展自己的業務狀況會是這樣:

Object#A 拆分,自己變成二房東,租一個物件,但是這個物件拆分成 N 個,每個再租給其他的使用者。

而如何把 Object#A 拆分的好與壞,就在於隔離的實作。

前面提到在真實世界的租賃中,承租物件已經具備明確的 邊界 (Border),但是承租 AWS 的企業,又把這個 SaaS 承租給他們的客戶,而對於 SaaS 客戶而言,邊界應該、必須要存在,而這個邊界則需要由 SaaS 公司在架構設計時,必須自己建立一道讓客戶以為的邊界,這個邊界,在本文中稱為 隔離 (Isolation)

隔離的核心議題: Isolation Factor (隔離因子)

本質上來講,隔離是透過一種 邊界 (Boundary) 方式,區分租戶彼此之間的空間範圍。

房子來講,區分彼此的空間範圍就是樑柱、牆壁、門、地板、天花板 … 等;以企業內部來講,就是各種辦公室的實體隔間、以及特定角色授權;以應用程式來說,就是使用者 A 能否看到使用 B 的資料而言。依照這樣的隔離概念,底下這些都是犯規:

  • 企業大樓裡,未經授權的員工,進入機房
  • 企業員工在 AWS 上開台機器,沒有認證授權,方便自己進出公司網域
  • SRE 說:我的 Gmail 看到別人的信,就要把 Gmail shutdown! –> 相關報導
  • 薩爾達傳說 - 王國之淚: 看我通天術 (這嚴重犯規 XDD)

實體隔離與邏輯隔離

在商業應用程式裡,隔離則因為 領域 (Domains) 不同,會用不同的方式,商業應用角度多半會以 邏輯隔離 為主。

邏輯隔離的例子,舉例常見的概念:

  • Google 服務 (Gmail / Gmap / Docs …) 都是以 Gmail Account 為隔離單位
  • GCP 以 Project 為隔離單位
  • AWS 則以 Account 為單位
  • Chrome 這個瀏覽器則以 Profile 為隔離概念
  • 多租戶架構的電商平台,隔離則是以 為單位,像是 91APP 是開店平台
  • 教育平台,則是以學校為單位,像是 Teachable 這個平台
    • 開學校之後,每個學校都可以有自己的學生、自己的老師 .. 等角色定義
  • 作業系統的隔離:Linux 的系統權限 user-group-anyone 本質上就是種隔離
  • 資料庫的隔離:Database / Table / Row 都是隔離概念,更甚者則是交易過程的鎖。

上述的隔離,在權限系統稱為 垂直權限,也就是透過 帳號 (通常) 隔離彼此。除了垂直權限,相對則是 水平權限,概念如下圖:

但是當業務發展到一定程度之後,或者依照法規的需求,則很常會以期望實體隔離,也就是在實體的系統架構,就是 專用 (Dedicated) 資源,不與其他人共用。
不管是實體還是邏輯隔離,都需要一個關鍵因子來定義怎麼隔離?而這個隔離的關鍵因子我把它稱為 隔離因子 (Isolation Factor)

前面描述的手段與方法都是為了達到隔離:

  • 權限:多租戶架構常用的方法是 垂直權限
    • 相對於垂直權限,稱為 水平權限,實踐方式有 RBAC、ABAC
  • 實體隔離 (physical isolation)
  • 邏輯隔離 (logical isolation): 虛擬化 virtualization, VPC

AWS 服務的隔離因子

AWS 有很多服務,舉凡 EC2 / S3 / DynamoDB / CloudFront … etc. 這些服務在 AWS 裏面都需要計算隔離方式,但是每個服務本身的屬性不一樣,在設計的時候怎麼知道每個服務的隔離因子是什麼?底下列舉設計 AWS 服務要考慮的隔離因子:

  • EC2: Instance
  • S3: Bucket
  • DynamoDB: Table
  • CloudFront: Distribution
  • VPC 本身就是個隔離單位

上述列舉的是這些服務的隔離因子例子,因為每個服務特性有所差異,要對應到 AWS Account 時,就要具體用一個單位對應隔離的想法,不然就會無法對應。

隔離沒做好會怎樣?

這是隔離背後要解決的關鍵痛點,最經典的案例是下圖:


Source: Google儲存SRE團隊負責人第一手經驗大公開, by ITHome, 20160421

另一個經典案例則是 VPC 的問題,底下截圖則是中國知名技術專家 陳皓 的部落格:


Source: 关于阿里云经典网络的问题, by Coolshell, 20200419

這都是別人的問題,而我面對過的問題則是之前在電商工作時,曾經出現的問題,我把它稱為 A-c-B event,中文稱為 A 店跨 B 店。也就是 B 店的使用者,看到 A 店的資料,不管是商品資料、還是訂單資料。

這三個例子,資安角度都是 垂直權限 的問題,背後實際問題就是隔離的設計與實踐。

updated 2023/09/29: 最近發生的 Google Bard臭蟲讓用戶對話出現在公開Google搜尋結果中 也屬於隔離沒做好造成的。

跨租戶問題常見的做法

雖然說跨租戶是不允許的,但是生活中還是有很多場景,需要跨租戶存取,例如我們信用卡掛失的時候,客服人員可以幫你調整信用卡的狀態。客服人員代替你調整信用卡的過程,就是個跨租戶操作,不管怎樣他要操作設定的時候,都要獲得你的允許,然後才能幫你調整狀態。這樣的過程,其實就是個身份暫時轉換,代理 (delegate) 執行的過程。

類似的做法,在作業系統已經都有很成熟的做法:

  • Linux: sudo as XXX
  • Windows: Run as XXXX

在系統實作時,專有名詞為 impersonate (v),也就是 User#A@Tanent#A as User#B@Tenant#B,這是個需要授權程序的。

在 AWS 的設計,幾種常見的例子:

  • 當 Account#A 要存取 Account#B 得時候,可以透過 STS 取得臨時授權
  • 當網路要相互連線時,需要透過雙方授權才能連結,像是 VPC Peering

小結

下圖是一張網路梗圖:


Source: https://www.facebook.com/groups/it.humor.and.memes/posts/24452121121053675/

圖中在 Windows 裡裝了 VMWare,然後裡面裝了 Windows,裡面再裝 VMWare … 如此好幾層 … 這張圖表述了多租戶的核心概念,不過大家知道 VM 本身是模擬硬體,換言之實作的是實體隔離。相對於 VM 則是 Container,透過 Kernal 的特性 (cgroup, namespace … etc),時做出隔離的概念。

而應用程式如果要做出隔離概念,則必定要面對如何定義租戶的概念,租戶本質就是為了達到隔離,用來隔離的 隔離因子 (Isolation Factor),則是本文想帶出的概念。

多租戶架構因而衍生的相關議題:

  1. 水平權限系統,像是 RBAC / ABAC,也就是 AWS IAM
  2. 租戶與 功能 的訂閱市集 (Marketplace),背後本質是個 Pub/Sub 概念
  3. 帳務系統:延續租戶與功能訂閱而產生的議題,也就是使用狀況 (Usage) 與帳務資訊 (Billing)
  4. 功能系統的通訊架構,相關參閱 摘要 Eclipse 設計的啟發:當代 SaaS 分散式架構的關鍵設計

延伸閱讀

站內文章

參考資料



Comments

2023/09/11 22:30:00





  • 全站索引
  • 關於這裏
  • 關於作者
  • 學習法則
  • 思考本質
  • 一些領悟
  • 分類哲學
  • ▲ TOP ▲