第 五 章 Dashboard 與 RADOS gateway 的整合的整合
5.2 Swift 的認證與授權
我們在 4.2.1小節有提到,controller 在安裝 Keystone 的時候可以指定 object-store 這 個服務的 endpoint 在哪 IP 哪個 port 上,讓 Dashboard 可以正確地與 Swift API 溝通,提 供 end-user 物件儲存的前端介面;另一方面,我們也在前一節安裝好了 RADOS gateway 來提供 Swift API,使用 Ceph 來支援物件儲存的服務,而不是使用 OpenStack Swift 這 個程式。
可是問題來了,Dashboard 會使用 Keystone 的授權來向任何 catalog 提供的 endpoint API 要 求 服 務,舉 例 來 說,若 我 們 使 用 了 bob 帳 號 登 入 了 Dashboard,會 得 到 一 組 Keystone 分配的 auth-key(類似 session-key),那我們就可以使用這組 auth-key 來向任何 有跟 Keystone 建立授權連線的服務來進行操作。
但 是 目 前 版 本 的 RADOS gateway 雖 然 提 供 了 相 容 的 Swift API,但 是 並 不 會 向 Keystone 要求授權,取而代之的是 Radosgw 自己維護了一套帳號密碼授權的對應 (藉由 radosgw-admin),如圖 5.1。
圖 5.1: RADOS gateway 認證示意圖
因此我們幫 radosgw-admin 撰寫了一個 python 介面的 API - rgwauthAPI[附錄 C.1],
讓其他使用者可以使用 python 方便的對 Radosgw 新增或刪除 Swift/S3 協定的使用者,
以及其他權限上的操作。並且針對 Dashboard 提供的物件儲存介面的前端與後端,補 充了一些令他相容於 Radosgw 的程式碼 [附錄 C.2],讓 Dashboard 可以完全使用 Ceph RADOS gateway 來提供物件儲存的服務,相關內容都可以在 github 下載使用1。
1
https://github.com/ChuanyuTsai/rgwauthAPI/
5.2.1 rgwauthAPI
圖 5.2: rgwauthAPI sequence diagram
rgwauthAPI 依賴 python-swift,python-cloudfiles,以及 radosgw 三個套件,必須先安 裝且設定好 cephuser 這個變數來指名呼叫 radosgw-admin 時的使用者。
圖 5.2說明了這個 module 的運作流程。使用上提供了 authenticate - user auto create 模 式以及 not auto create 模式。若是使用 auto create 模式則不存在的使用者要求認證時,
rgwauthAPI 會自動幫該使用者在 radosgw-admin 上建立一個一般使用者權限的帳號,反 之則會回傳使用者不存在的例外情形。
NCTU CStack 系統預設每個專案 (tenant) 都擁有物件儲存的服務,因此任何可供使 用者登入 (啟用中) 的專案皆會在向 rgwauthAPI 認證時,預設使用 user auto create 模式 來做認證,減輕了系統管理者需要手動建立帳號的負擔。
在確認了使用者存在 Ceph RADOS Gateway 上後,rgwauthAPI 會試著跟 Ceph 連線,
並取回新的 token,回傳給 dashboad,讓 dashboard 可以繼續接下來的操作。
radosgw-admin 在設計上規定一個使用者可包含多個 subuser,subuser 可各自設定權 限並且在建立時可選擇是透過 S3 API 認證或是 Swift API 認證,所有 subuser 皆分享同 一個空間 (可存取相同的物件以及容器)。因此 rgwauthAPI 也提供了刪除 subuser,以及
https://github.com/ChuanyuTsai/horizon/
在刪除使用者時會自動刪除屬於該使用者的物件以及容器,避免這些無法再存取的物 件和容器永久的占用 ceph 儲存系統的空間,有效的減少 object leak 的問題 [5]。
5.2.2 Dashboard Patches
有了 rgwauthAPI 後就可以修改 Dashboard 來使用它了。在 patch Dashboard 的部分為 了維護方便,並且需要相容於之後的官方更新,我們使用 GIT 並從官方的程式碼 fork 出自己的 repository,在上面做修改後,可以輕鬆的產生 patch 並安裝到上線的機器中。
這些 patches 包含了 rgwauthAPI 的支援,提供顯示 S3 服務入口,修正物件名稱有斜 線時不能正常顯示的問題,修正專案的使用空間及配額限制,並修正建立虛擬機時規格 列表的顯示內容等。
rgwauthAPI 的支援
OpenStack Keystone Operations Radosgw-admin A Tenant Enable/Suspend A User
Multiple Users Add/Remove Multiple Subusers Share Same Containers Create/Delete Share Same Buckets
Table 5.1: 認證關係的對應
表格 5.1說明了在 NCTU CStack 系統上,Keystone 和 Radosgw-admin 的權限對應 關係。我們將 Radosgw-admin 上的 User 對應到 Keystone 的專案,這樣 subuser 對應到 Keystone 的使用者,這樣可以使得相同專案的所有使用者存取共同的容器以及物件,彼 此可以分享跟專案相關的檔案資料,也比較符合我們的需求。
這裡主要是修改了/horizon/api/swift.py 這個檔案,並在設定檔增加了兩個參數來讓 系統管理者決定要以甚麼方式支援 RADOS gateway:
SWIFT_USE_RADOSGW_AUTH:決定是否要改用 rgwauthAPI 來認證;
SYNC_KEYSTONE_RADOSGW_AUTH:決定是否要使用 user auto create 的認證模式。
若設定成 False,則只有管理者手動加入的專案才能使用物件儲存的服務。
1. /horizon/api/swift.py
嘗試與 rgwauthAPI 認證的程式碼。
def swift_api(request):
endpoint = url_for(request, 'object-store') + auth_token = request.session['token']
+
+ use_radosgw_auth = getattr(settings, 'SWIFT_USE_RADOSGW_AUTH', False) + sync_radosgw_auth = getattr(settings, 'SYNC_KEYSTONE_RADOSGW_AUTH', False) + if (use_radosgw_auth == True):
+ uid,subuser = request.session['tenant_id'],request.session['user_id']
+ try:
+ rgw = RGW(uid, subuser, endpoint)
+ storage_url, auth_token = rgw.authenticate('swift', sync_radosgw_auth) + except Exception as e:
+ # rgwauthAPI now puts error msg in args[0]
+ raise exceptions.RadosgwExceptions(str(e.args[0])) + auth = SwiftAuthentication(storage_url, auth_token)
return cloudfiles.get_connection(auth=auth)
2. /horizon/exceptions.py
定義一個新的例外情形來處理 rgwauthAPI 認證失敗的情形。
+class RadosgwExceptions(HorizonException):
+ def __init__(self, msg):
+ self.msg = msg +
+ def __repr__(self):
+ return self.msg +
+ def __unicode__(self):
+ return _(self.msg)
3. /horizon/api/swift.py
由於 radosgw 在接收上傳的物件時需要清楚的知道物件的檔案大小,但是目前的 Dashboard 只提供檔案名稱,因此需要額外幫它加上去。
def swift_upload_object(request, container_name, object_name, object_file):
container = swift_api(request).get_container(container_name) - obj = container.create_object(object_name)
+ # radosgw needs to know the size exactly
+ obj = cloudfiles.storage_object.Object(container, object_name,
+ object_record = {
+ 'name': object_name,
+ 'content_type': object_file.content_type,
+ 'bytes': object_file._size,
+ 'last_modified': None,
+ 'hash': None
+ })
obj.send(object_file) return obj
4. /horizon/dashboards/syspanel/projects/tables.py
由於我們希望 Radosgw-admin 的帳號可以與 Keystone 的同步,所以當有專案或使 用者被刪除時,也要透過 rgwauthAPI 來將相對應的使用者與 subuser 刪除。
需要注意的是專案的刪除必須遞迴的將所有屬於這個專案的使用者移出這個專案 後才能將該專案刪除,不然會導致有的使用者明明還有其他專案的權限,卻在登 入 Dashboard 時遭遇" 不屬於任何專案" 的錯誤而無法登入,這邊一併做修正。
class DeleteTenantsAction(tables.DeleteAction):
def delete(self, request, obj_id):
+ use_radosgw_auth = getattr(settings, 'SWIFT_USE_RADOSGW_AUTH', False) + sync_radosgw_auth = getattr(settings, 'SYNC_KEYSTONE_RADOSGW_AUTH', False) + if use_radosgw_auth and sync_radosgw_auth:
+ endpoint = url_for(request, 'object-store')
+ try:
+ LOG.debug('Radosgw remove user %s from endpoint: %s'
+ % (obj_id, endpoint))
+ RGW(obj_id, 'admin', authUrl=endpoint).rmUser() + except Exception as e:
+ exceptions.handle(request, _("Unable to delete rgw user.")) + for user in api.keystone.user_list(request, obj_id):
+ api.keystone.remove_tenant_user(request, obj_id, user.id) ...
def action(self, request, user_id):
tenant_id = self.table.kwargs['tenant_id']
+ use_radosgw_auth = getattr(settings, 'SWIFT_USE_RADOSGW_AUTH', False) + sync_radosgw_auth = getattr(settings, 'SYNC_KEYSTONE_RADOSGW_AUTH', False) + if use_radosgw_auth and sync_radosgw_auth:
+ endpoint = url_for(request, 'object-store') + uid, subuser = tenant_id, user_id
+ try:
+ LOG.debug('Radosgw remove subuser %s:%s from endpoint: %s'
+ % (uid, subuser, endpoint))
+ RGW(uid, subuser, endpoint).rmSubuser()
+ except:
+ redirect = reverse("horizon:syspanel:projects:users",
+ args=(tenant_id,))
+ exceptions.handle(request, _('Remove user failed.'),
+ redirect=redirect)
額外的 S3 連接方式
由於 Radosgw-admin 本身即支援 OpenStack Swift API 以及 Amazon S3 API 這兩種常 見的物件儲存服務的協定,有鑑於大量軟體對於 S3 API 的支援與開發程度,我們另外 設計了一種方式讓專案內的使用者可以用其他相容 S3 API 的軟體來使用我們提供的物
件儲存服務,這也是原本的 OpenStack Essex Swift 程式沒有的功能2。
具體做法是在建立 Radosgw 的使用者時一起建立一組 S3 協定的 subuser,並且在 Dashboard 的物件儲存頁面提供一個"ShowKey" 頁面顯示那組 subuser 的 Access Key 和 Secret Key 以及 5.1.1小節提到的存取點 http://s3.nctu.edu.tw/,使用者有了這些資訊後就 可以使用自己喜歡軟體透過 S3 協定來操作專案上面的容器或是物件,甚至在專案裡啟 動的虛擬機上也可以安裝 s3fs3來將專案上的容器掛載到虛擬機上的任意資料夾,有些 使用情形下這是個非常方便的功能。
由於 Dashboard 是使用 python 的 Django 來開發的一套 MVC framework,因此我們 僅需在 view 與 controller 的地方加入相對應的程式碼即可完成這些功能。
1. /horizon/dashboards/nova/containers/tables.py
如果支援 Radosgw 的參數被設置起來,就在物件儲存的首頁增加 Show Keys 的按 鈕來讓使用者取得 S3 服務的連接方式。
+class ShowKeys(tables.LinkAction):
+ name = "show_keys"
+ verbose_name = _("Show Keys")
+ url = "horizon:nova:containers:show_keys"
+ classes = ("ajax-modal", "btn-create") +
+ if getattr(settings, 'SWIFT_SHOW_RADOSGW_KEYS', False):
+ table_actions = (ShowKeys, CreateContainer, DeleteContainer)
+ else:
+ table_actions = (CreateContainer, DeleteContainer)
2. /horizon/dashboards/nova/containers/urls.py
Django MVC 中的 controller 設定檔,呼叫 ShowKey 的 action。
+ url(r'^show/$', ShowKeysView.as_view(), name='show_keys'),
3. /horizon/dashboards/nova/templates/nova/containers/_showkeys.html
Django MVC 中的 view,設定 ShowKey 的左邊是一個表格,右邊為說明文字。
+<div class="left">
+ <fieldset>
+ {% include "horizon/common/_form_fields.html" %}
+ </fieldset>
+</div>
+<div class="right">
+ <h3>{% trans "Description" %}:</h3>
2