在前面章節中,微服務部份我們討論了從單體架構到微服務架構的轉換,並以一個範例介紹了如何進行業務邏輯和數據的拆分。但如同結尾提到,其實微服務設計上,會面臨不同的問題。這部分我會再針對此部分做一個go through介紹。但今天我想針對微服務架構中的資料庫權限管理進行介紹,並基於具體實例來說明如何實作。
本文亦致敬我的職涯同事 Clarke,與他共事期間,特別是在微服務的資料庫設計與權限拆分上學習了許多寶貴的知識。希望透過這篇文章,分享他所教導的經驗和設計思路。
閱讀完後大致會對Schema與User細微度的設計會稍微有感跟理解一個初步脈絡
在微服務的設計中,我們通常會根據不同服務對資料庫(DB)的需求,為各服務設置資料庫 Schema 的使用權限,並依此設計相應的 API Service。在過去,我的經驗大多在工廠的設備控制與生產服務串接,由於工廠端系統較為簡單,DB 實例(DB Instance)建置完成後,通常不需要為多個 API Service 特別規劃 Schema 的使用權限管理。常見做法是直接使用一個 Root 使用者來進行所有操作。然而,這在微服務架構中並不是一個好的設計。這樣會導致每個服務擁有過多的權限,增加潛在的安全風險。
在為服務實際應用中,應該根據不同服務的資料需求,設置其專屬的權限範圍,並將這些權限分配至不同的資料庫 Schema。接著,針對每個 Schema 設計對應的 API Service 來存取資料。
資料庫 Schema 是一種組織方式,允許將表格、視圖、索引等物件分類與管理。在這樣的架構下,每個微服務通過其專屬的 API Service 存取資料庫,而其操作的範圍僅限於指定的 Schema。這樣可以有效防止服務擁有過多的資料庫權限,從而降低安全風險。
在台北受訓那時期,新人專題要設計一個雲端系統,須具備登入和圖片上傳功能。如果不採用微服務架構,單一的 API Service 連接到一個資料庫實例的 Schema 即可完成。但按照微服務的設計原則,應將這兩個功能拆分為兩個獨立的 API Service,一個處理圖片上傳,另一個處理登入功能。
在這樣的設計中,我們將資料庫 Schema 進行拆分:
接著,針對這兩個 Schema 設計不同的角色和權限,確保每個服務只擁有執行其職責所需的權限,這樣可以有效地提升系統的安全性和可管理性。
schema 是一種將數據庫物件(如表格、視圖、索引、數據類型、函數等)組織在一起的命名空間。每個數據庫都可以有一個或多個 schema,每個 schema 都有一個名稱,該名稱在其數據庫中必須是唯一的。
以下將通過 SQL 範例來說明如何為微服務設計資料庫權限管理。具體步驟包括:
首先,為兩個功能分別創建角色 HW_PROCESS
和 HW_SECURITY
,並設置資料庫 Schema 來隔離各自的權限。每個角色都有自己的登入憑證,並且只被授權訪問自己的 Schema。
-- 創建角色
CREATE ROLE HW_PROCESS;
CREATE ROLE HW_SECURITY;
-- 授權
GRANT HW_PROCESS TO POSTGRES;
GRANT HW_SECURITY TO POSTGRES;
-- 創建 Schema 並授權
CREATE SCHEMA AUTHORIZATION HW_PROCESS;
CREATE SCHEMA AUTHORIZATION HW_SECURITY;
-- 設置角色的登入權限和密碼
ALTER ROLE HW_PROCESS WITH LOGIN PASSWORD 'hwprocess';
ALTER ROLE HW_SECURITY WITH LOGIN PASSWORD 'hwsecurity';
此段指令完成以下幾個步驟
HW_PROCESS
和 HW_SECURITY
。HW_PROCESS
和 HW_SECURITY
角色授予給 POSTGRES
超級使用者。HW_PROCESS
和 HW_SECURITY
角色。簡單來說HW_PROCESS
和 HW_SECURITY
分別是這兩個 Schema 的擁有者。HW_PROCESS
和 HW_SECURITY
角色設置了登入權限和各自的密碼接著根據不同的服務需求,創建對應的 API 使用者 HWSAP
和 HWPAP
,並設置密碼以便使用這些使用者進行服務連接。
-- 創建 API 使用者
CREATE ROLE HWSAP LOGIN PASSWORD 'HWSAP123'; -- 用於 SECURITY Schema
CREATE ROLE HWPAP LOGIN PASSWORD 'HWSAP123'; -- 用於 PROCESS Schema
接著,為每個 Schema 設置不同的角色(Role Group),並分別授予不同的操作權限。角色依據操作職責進行細分:
-- HW_PROCESS 角色組設置
CREATE ROLE RL_HW_PROCESS_SEL; -- 查詢
CREATE ROLE RL_HW_PROCESS_MOD; -- 修改
CREATE ROLE RL_HW_PROCESS_EXE; -- 執行
-- 賦予相應權限
GRANT SELECT ON ALL TABLES IN SCHEMA HW_PROCESS TO RL_HW_PROCESS_SEL;
GRANT INSERT, UPDATE, DELETE ON ALL TABLES TO RL_HW_PROCESS_MOD;
GRANT EXECUTE ON ALL PROCEDURES TO RL_HW_PROCESS_EXE;
-- HW_SECURITY 角色組設置
CREATE ROLE RL_HW_SECURITY_SEL; -- 查詢
CREATE ROLE RL_HW_SECURITY_MOD; -- 修改
CREATE ROLE RL_HW_SECURITY_EXE; -- 執行
-- HW_PROCESS 角色設置
GRANT SELECT ON ALL TABLES IN SCHEMA HW_SECURITY TO RL_HW_SECURITY_SEL;
GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA HW_SECURITY TO RL_HW_SECURITY_MOD;
GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA HW_SECURITY TO RL_HW_SECURITY_EXE;
在 HW_PROCESS
Schema 創建三個角色:
RL_HW_PROCESS_SEL
:主要負責查詢HW_PROCESS
資料。RL_HW_PROCESS_MOD
:主要負責修改HW_PROCESS
資料(如插入、更新、刪除)。RL_HW_PROCESS_EXE
:主要負責執行HW_PROCESS
存儲程序(Stored Procedures)。賦予相應的權限
RL_HW_PROCESS_SEL
被授予對 HW_PROCESS
Schema 中所有資料表的 SELECT 權限,代表角色只能查詢資料,不能修改。RL_HW_PROCESS_MOD
被授予 INSERT、UPDATE 和 DELETE 權限,讓該角色可以插入、更新和刪除資料表中的資料。RL_HW_PROCESS_EXE
被授予對 HW_PROCESS
Schema 中所有存儲程序的 EXECUTE 權限,允許該角色執行資料庫中的存儲程序。在 HW_SECURITY
Schema 創建三個角色 :
RL_HW_SECURITY_SEL
:負責查詢 HW_SECURITY
Schema 中的資料。RL_HW_SECURITY_MOD
:負責修改 HW_SECURITY
Schema 中的資料。RL_HW_SECURITY_EXE
:負責執行 HW_SECURITY
Schema 中的程序。賦予相應的權限
RL_HW_SECURITY_SEL
被授予對 HW_SECURITY
Schema 中所有資料表的 SELECT 權限,讓該角色可以查詢資料。RL_HW_SECURITY_MOD
被授予對 HW_SECURITY
Schema 中所有資料表的 INSERT、UPDATE 和 DELETE 權限,這允許修改資料。RL_HW_SECURITY_EXE
被授予對 HW_SECURITY
Schema 中所有程序的 EXECUTE 權限,可以執行存儲程序。最後,將角色組賦予對應的 API 使用者,讓每個使用者僅能執行其服務所需的操作。
-- 為 HWSAP 分配 HW_SECURITY 角色
GRANT RL_HW_SECURITY_SEL, RL_HW_SECURITY_MOD, RL_HW_SECURITY_EXE TO HWSAP;
-- 為 HWPAP 分配 HW_PROCESS 角色
GRANT RL_HW_PROCESS_SEL, RL_HW_PROCESS_MOD, RL_HW_PROCESS_EXE TO HWPAP;
整體SQL與法如下
-- SCHEMA & TABLE SETTING
CREATE ROLE HW_PROCESS;
CREATE ROLE HW_SECURITY;
GRANT HW_PROCESS TO POSTGRES;
GRANT HW_SECURITY TO POSTGRES;
CREATE SCHEMA AUTHORIZATION HW_PROCESS;
CREATE SCHEMA AUTHORIZATION HW_SECURITY;
ALTER ROLE HW_PROCESS WITH LOGIN PASSWORD 'hwprocess';
ALTER ROLE HW_SECURITY WITH LOGIN PASSWORD 'hwsecurity';
-- CREATE AP USER
-- AP USER
CREATE ROLE HWSAP LOGIN PASSWORD 'HWSAP123';
CREATE ROLE HWPAP LOGIN PASSWORD 'HWSAP123';
-- CREATE ROLE GROUP
-- HW_PROCESS
CREATE ROLE RL_HW_PROCESS_SEL;
CREATE ROLE RL_HW_PROCESS_MOD;
CREATE ROLE RL_HW_PROCESS_EXE;
GRANT SELECT ON ALL TABLES IN SCHEMA HW_PROCESS TO RL_HW_PROCESS_EXE;
GRANT INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA HW_PROCESS TO RL_HW_PROCESS_MOD
GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA HW_PROCESS TO RL_HW_PROCESS_EXE;
-- HW_SECURITY
CREATE ROLE RL_HW_SECURITY_SEL;
CREATE ROLE RL_HW_SECURITY_MOD;
CREATE ROLE RL_HW_SECURITY_EXE;
GRANT SELECT ON ALL TABLES IN SCHEMA HW_SECURITY TO RL_HW_SECURITY_SEL;
GRANT INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA HW_SECURITY TO RL_HW_SECURITY_MOD;
GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA HW_SECURITY TO RL_HW_SECURITY_EXE;
-- GRANT ROLE GROUP TO USER
GRANT RL_HW_SECURITY_SEL, RL_HW_SECURITY_MOD, RL_HW_SECURITY_EXE TO HWSAP;
GRANT RL_HW_PROCESS_SEL, RL_HW_PROCESS_MOD, RL_HW_PROCESS_EXE TO HWPAP;
根據上述設計,角色和權限的關係可以簡單整理如下:
主要角色
HW_PROCESS
:負責處理圖片上傳的 Schema 及其操作。HW_SECURITY
:負責處理登入的 Schema 及其操作。API 使用者
HWSAP
:負責與 HW_SECURITY
相關的服務,擁有 SELECT、MODIFY 和 EXECUTE 權限。HWPAP
:負責與 HW_PROCESS
相關的服務,擁有 SELECT、MODIFY 和 EXECUTE 權限。角色組(Role Group)
RL_HW_PROCESS_SEL
/ RL_HW_SECURITY_SEL
:查詢權限。RL_HW_PROCESS_MOD
/ RL_HW_SECURITY_MOD
:資料修改權限。RL_HW_PROCESS_EXE
/ RL_HW_SECURITY_EXE
:執行儲存程序的權限。這樣的設計能夠實現細粒度的資料庫權限控制,保證每個服務只擁有其職責範圍內的權限,確保系統的安全性與可管理性。但其實以目前的專案情境,角色Group組員微度可能應用不上,但我覺得是一個很好的觀念做此紀錄。
稍微簡單比較一下簡單權限設定與細部權限控管的兩種方案,從便利性、安全性、實作速度、權限控制及維護成本等多個面向進行對照。
比較項目 | 簡單權限設定 | 細部權限控管 |
---|---|---|
便利性 | 高:一次設定,所有服務共用 | 低:需針對每個服務獨立設定 |
實作速度 | 快:適合小型應用或測試階段 | 較慢:需考量每個服務的需求與權限 |
安全性 | 低:每個服務擁有過多權限,風險高 | 高:遵循最小權限原則,降低安全風險 |
權限控制 | 無法細緻控制,所有服務共用 | 精細控制,每個服務只擁有其需要的權限 |
問題追蹤 | 難以追蹤,無法區分個服務執行了操作 | 容易追溯,所有操作可追蹤至具體服務 |
維護成本 | 低:初期設定簡單 | 高:需針對各服務進行權限管理 |
適用場景 | 小型、簡單或短期應用 | 大型、長期維護且具擴展性應用 |
資料庫連線設置部分,Quarkus支援JDBC連線,通常透過quarkus.datasource
屬性來配置資料來源。Quarkus具備兩種主要資料庫連線方式:使用阻塞(JDBC)或非阻塞(反應式)的方式來與資料庫交互。以下是JDBC連線設定配置
單一資料來源配置示意如下
# 全域資料來源配置
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=service_user
quarkus.datasource.password=service_password
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydb
quarkus.datasource.jdbc.max-size=15
quarkus.datasource.jdbc.min-size=2
如果以上述範例拆服務配置如下
# 對於登入服務 (Security)
quarkus.datasource.security.db-kind=postgresql
quarkus.datasource.security.username=HWSAP
quarkus.datasource.security.password=HWSAP123
quarkus.datasource.security.jdbc.url=jdbc:postgresql://localhost:5432/securitydb
quarkus.datasource.security.jdbc.max-size=8
quarkus.datasource.security.jdbc.min-size=2
# 對於圖片上傳服務 (Process)
quarkus.datasource.process.db-kind=postgresql
quarkus.datasource.process.username=HWPAP
quarkus.datasource.process.password=HWPAP123
quarkus.datasource.process.jdbc.url=jdbc:postgresql://localhost:5432/processdb
quarkus.datasource.process.jdbc.max-size=8
quarkus.datasource.process.jdbc.min-size=2
根據上述過一遍權限與角色分隔設置上,整理出以下關鍵點
細粒度權限控制:在許多情況下,你可能不希望你的應用程式服務有權限去做所有事情。例如,一個應用程式可能只需要讀取資料,而不需要寫入或刪除。透過為這些服務創建特定的角色,你可以確定他們只有他們實際需要的權限。
最小權限原則:一種常見的安全最佳實踐,只賦予完成任務所需的最小權限。如果你的應用程式服務只需要讀取資料,那麼給它們賦予寫入或修改的權限可能會引入不必要的風險。
角色分隔:透過為不同的應用程式服務創建不同的角色,可以更容易地追蹤和管理哪個服務正在做什麼。這也使得審計和問題排查變得更容易。
避免使用 schema 擁有者進行操作:在許多數據庫系統中,schema 擁有者(在這種情況下為**HW_PROCESS
** 和 HW_SECURITY
)擁有對其 schema 中的所有對象的所有權限。如果應用程式以 schema 擁有者的身份運行,那麼任何可能的漏洞或配置錯誤都可能導致整個 schema 的數據被修改或刪除。
為你的應用程式服務創建專門的角色可以提供更精確的控制,並降低可能的安全風險。