方案背景
Nacos自開源依賴,權限控制一直需求比較強烈,這也反應了用戶需求將Nacos部署到生產環境的需求。最新發布的Nacos 1.2.0版本已經支持了服務發現和配置管理的權限控制,保障用戶安全上生產。本文主要介紹Nacos權限控制的設計方案和使用指南。
什么是權限控制?
在分布式服務調用時,需要對未知的或者不受信任的請求來源的請求進行識別和拒絕。權限控制一般分為兩個階段:身份識別(Authentication)和權限識別(Authorization)。身份認證主要確定訪問者的身份,權限識別則判斷這個訪問者是否有對應資源的權限。
在Nacos的場景中,配置管理的權限控制指的是設置某個配置能否被某個用戶讀寫,這個比較好理解,沒有權限的用戶舊無法讀取或者寫入對應的配置。服務發現的權限控制指的是用戶是否有權限進行某個服務的注冊或者訂閱,這里需要注意的是服務發現的權限控制只能夠控制用戶是否可以從Nacos獲取到服務的地址或者在Nacos上修改服務的地址。但是如果已經獲取到了服務的地址,Nacos無法在服務真正調用時進行權限控制,這個時候的權限控制需要由服務框架來完成。
常見實現方式
認證(Authentication)
- 用戶名+密碼
- Cookie(只適用於瀏覽器)
- Session
- Token(JWT,Oauth,LDAP,SAML,OpenID)
- AK/SK
鑒權(Authorization)
- ACL: 規定資源可以被哪些主體進行哪些操作;
- DAC: 規定資源可以被哪些主體進行哪些操作 同時,主體可以將資源的權限,授予其他主體;
- MAC:a. 規定資源可以被哪些類別的主體進行哪些操作 b. 規定主體可以對哪些等級的資源進行哪些操作 當一個操作,同時滿足a與b時,允許操作;
- RBAC: a. 規定角色可以對哪些資源進行哪些操作 b. 規定主體擁有哪些角色當一個操作,同時滿足a與b時,允許操作;
- ABAC: 規定哪些屬性的主體可以對哪些屬性的資源在哪些屬性的情況下進行哪些操作。
方案詳情
Nacos的權限控制,目標是能夠滿足用戶基本的鑒權需求,同時能夠保持擴展性,可以支持去對接用戶自帶的用戶管理系統或者鑒權系統,包括后面和K8S生態以及Service Mesh生態能夠無縫的融合。基於這樣的考慮,目前Nacos權限控制的設計是自帶一個基本的實現,然后可以支持用戶擴展。具體的設計如下。
模塊設計
整體的模塊設計是盡量將鑒權的邏輯抽象出來,不在服務發現模塊或者配置管理模塊添加相關的邏輯。通過配置文件可以選擇當前使用的鑒權系統。Nacos自帶的認證系統使用JWT Token,自帶的鑒權系統使用的是RBAC。
認證算法
對於用戶來說,不管是在控制台還是在客戶端,都是上傳用戶名和密碼來獲取一個token,然后后續的每一次到Nacos的請求都會帶上這個token來表明身份。這個token會有一個失效時間,對於控制台來說,只需要直接提示用戶重新登錄即可,對於客戶端則需要有一個定期到Nacos刷新token的邏輯。
鑒權算法
Nacos自帶的鑒權系統使用的是RBAC模型,可以在網上查詢相關的資料。
數據模型
鑒權的數據模型也是基於標准的RBAC來設計的,分為用戶、角色和權限三部分。用戶就是由用戶名和密碼組成的用戶信息,角色則是一個邏輯上的用戶組,Nacos啟動時會自帶一個全局管理員的角色,只有這個全局管理員的角色可以進行添加用戶、添加角色、添加授權等操作,保證安全性。而權限則是由資源+動作來組成。
接口設計
以下接口涉及到登錄和鑒權的所有邏輯,這些接口除了登錄接口,其他接口都只能由全局管理員來調用。
用戶管理
- 創建用戶:POST
/nacos/v1/auth/users?username=xx&password=yy
- 刪除用戶:DELETE /nacos/v1/auth/users?username=xx&password=yy
- 更新用戶:PUT /nacos/v1/auth/users?username=xx&oldPassword=yy&newPassword=zz
- 登錄:POST
/nacos/v1/auth/users/login?username=xxx&password=yyy
角色管理
- 創建角色/綁定用戶到角色:POST /nacos/v1/auth/roles?role=xx&username=yy
- 刪除某個用戶的角色:DELETE /nacos/v1/auth/roles?role=xx&username=yy
- 獲取用戶的所有角色:GET /nacos/v1/auth/roles?username=xxx
權限管理
- 給角色添加權限:POST /nacos/v1/auth/permissions?role=xxx&resource=yyy&action=zzz
- 從角色刪除權限:DELETE /nacos/v1/auth/permissions?role=xxx&resource=yyy&action=zzz
- 獲取某個角色的權限:GET /nacos/v1/auth/permissions?role=xxx
Nacos權限控制實戰
安裝Nacos 1.2.0
- 部署包准備。可以直接下載安裝包:https://github.com/alibaba/nacos/releases/tag/1.2.0,也可以將Nacos master分支clone下來進行源碼編譯:
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
- 安裝包解壓,然后使用distribution/nacos-mysql.sql進行數據庫初始化,主要是新增了users, roles, permissions三張表,standalone模式使用distribution/schema.sql進行初始化。
- Server端打開權限控制開關。修改con/application.properties內容:
nacos.core.auth.enabled=true
這個開關采用了熱加載模式,無需重啟Server即可生效。因此當權限控制功能使用有異常時,可以直接回滾到不鑒權的模式。
使用權限控制
1、使用管理員賬號登錄Nacos控制台(如果頁面提示錯誤,可以情況瀏覽器緩存刷新頁面):
可以看到,左側邊欄增加了一個父菜單和三個子菜單,分別用於權限控制里的用戶創建、角色創建以及權限管 理。這個菜單欄只會在管理員登錄的時候顯示,也就意味着只有管理員才能進行權限的管理和分配。
2、管理用戶。點擊“用戶列表”,進入用戶管理頁面,可以進行用戶的創建、修改和刪除:
3、管理角色。因為Nacos的自帶的權限是基於角色來進行分配的,因此需要給創建好的用戶綁定一些角色:
4、管理權限。角色創建好以后,就可以給這個角色賦予特定的權限了:
在“添加資源”對話框里,可以選擇綁定的角色,命名空間資源以及對應的動作類型,例如在上圖中,我們給角色role1綁定命名空間test的讀寫權限。然后又因為剛剛我們是將user1綁定到了role1上,那么user1這個用戶就可以對test這個命名空間的資源進行讀寫操作了。
5、使用user1登錄控制台。點擊控制台右上角,退出admin賬號,然后用剛才創建的user1進行登錄:
如上圖所示,首先是左側的權限管理菜單消失了,因為當前用戶不是管理員。其次是會彈出一個鑒權失敗的提示框。不用擔心,這個提示框意思是user1沒有public命名空間的讀權限,所以會彈出,但是不影響我們將命名空間切換到test:
如上圖所示,我們可以看到test命名空間的配置數據了,下面我們再來介紹客戶端的使用。
6、首先依賴最新的nacos 1.2.0客戶端,然后在初始化時添加如下代碼:
Properties properties = new Properties();
properties.put(PropertyKeyConst.NAMESPACE, "99a791cf-41c4-4535-9e93-b0141652bad0");
properties.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
// 配置用戶名:
properties.put(PropertyKeyConst.USERNAME, "user1");
// 配置密碼:
properties.put(PropertyKeyConst.PASSWORD, "pwd1");
ConfigService iconfig = NacosFactory.createConfigService(properties);
7、使用客戶端進行正常的讀寫配置操作。