OpenStack 的 Keystone V3 中引入了 Domain 的概念。引入這個概念后,關于 admin 這個role 的定義就變得復雜了起來。
本文測試環境是社區 Mitaka 版本。
1. Domain,project,user,role,token 的概念和關系
1.1 概況
簡單來說,
它們之間的關系用一個不完整的圖來表示:
說明:
1.2 Token scope 和 Scoped token
官方文檔在這里,我這里寫的只是我的理解。
Token 是針對不同 scope 認證狀態,這里的 scope 是指 project 和 domain,因此一共有三種 scoped token:
下文有獲取不同類型 token 的方法的描述。
2. 各種 admin
admin 是一種特別的 role。下面分兩種情況討論。
2.1 使用默認 policy.json 時候的 admin 的權限
2.1.1 Identity 資源的 admin 權限
對 Identiy 項目中的大多數資源的操作都需要 admin 權限,比如:
"identity:get_user": "rule:admin_required", "identity:list_users": "rule:admin_required", "identity:create_user": "rule:admin_required", "identity:update_user": "rule:admin_required", "identity:delete_user": "rule:admin_required",
也就是說,以 user 為例,如果一個用戶沒有 admin 角色,那么他將不能對 user 做任何操作。而 policy.json 文件中對 admin 的約束非常簡單:
"admin_required": "role:admin or is_admin:1",
也就是說,滿足兩個條件中的一個,它就是 administrator:
從 policy.json 文件可以看出來,只要賦予一個用戶 admin 角色,那么他就是 administrator 了,可以操作 OpenStack cloud 內的所有資源。
2.1.2 OpenStack 基礎設施資源的權限控制
以 Cinder 為例,它也使用 policy.json 文件進行 role 的 policy 控制,它區分了 admin,project owner 和普通 user 的權限:
"context_is_admin": "role:admin", "admin_or_owner": "is_admin:True or project_id:%(project_id)s", "default": "rule:admin_or_owner", "admin_api": "is_admin:True", "volume:create": "", "volume:delete": "rule:admin_or_owner", "volume:get": "rule:admin_or_owner", "volume:get_all": "rule:admin_or_owner", "volume:get_volume_metadata": "rule:admin_or_owner",
可見:
2.2 使用 policy.v3cloudsample.json 時候的 admin 的權限
從上面 2.1.1 可以看出,使用默認 policy.json 文件時的 admin 權限控制非常粗,不能支持 Keystone V3 API 中引入的域的概念。因此,社區提供了支持多域的 policy.v3cloudsample.json 文件。
2.2.1 Identity 中的 admin
"admin_required": "role:admin", "cloud_admin": "role:admin and (token.is_admin_project:True or domain_id:2b871f5dba704f74923ac01b4fcd7205)", "service_role": "role:service", "service_or_admin": "rule:admin_required or rule:service_role", "owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s", "admin_or_owner": "(rule:admin_required and domain_id:%(target.token.user.domain.id)s) or rule:owner", "admin_and_matching_domain_id": "rule:admin_required and domain_id:%(domain_id)s", "service_admin_or_owner": "rule:service_or_admin or rule:owner",
它定義了幾種 admin:
cloud admin (cloud_admin):必須擁有 admin role;其 token 在 admin project 內 或者在指定的 domain 內。Cloud admin 的主要職責是
domain admin:必須擁有 admin role;token 的 domain id 必須和被操作資源(包括user,project 等) 的 domain id 相同。其主要職責包括
只有 Cloud admin 擁有的一些權限:
只有 Domain admin 擁有的一些權限(當然這些權限 cloud admin 都擁有):
2.2.2 示例規則說明
"admin_required": "role:admin","identity:create_project": "rule:admin_required and domain_id:%(project.domain_id)s","identity:get_project": "rule:admin_required and domain_id:%(target.project.domain_id)s","identity:list_projects": "rule:admin_required and domain_id:%(domain_id)s",
先來看create_project,首先要求 admin角色,需要注意的是and的后半句 domain_id:%(project.domain_id)s,這條規則的意思就是 create_project 時,使用的token的 domain_id 必須等于project所在的domain的domain_id。
也就是如下場景:
1.為userA在domainA的范圍內賦予admin的權限
2.userA指定domainA作為scope,申請一個domainA scope的tokenA
3.userA使用tokenA,去創建project,創建project時domain_id參數必須為domainA的id
4.創建project成功
這里有幾個關鍵點需要注意:
這樣一條規則的意義在于,可以限制只有在domainA內有權限的用戶才能在domainA創建project。
get_project 比較好理解,就是查詢的project的 domain_id 必須和token的 domain_id 相同,也就是只能查詢 token 所在范圍內的project。
list_project 是查詢出所有的project,但是會根據token的domain_id過濾,然后剩下所有和token的domain_id相同的project。
keystone 增加了 domain 這樣一個概念之后,其實也就把 keystone 本身的資源 user、project、group 按照 domain 給做了一個劃分,可以做到在 domain 范圍內的對于user、project和group的管理。
3. 多域(multi-domain)的相關操作
3.1 啟用多域 policy.json
1. Keystone 使用普通的 policy.json 文件,使用 admin 用戶,創建 admin_domain domain,cloud_admin user 并授予其 admin role
openstack domain create admin_domain openstack user create --domain admin_domain --password 1111 --description "Cloud admin" cloud_admin openstack role add --domain admin_domain --user cloud_admin admin
2. 使用 policy.v3cloudsample.json
使用policy.v3cloudsample.json 覆蓋 /etc/keystone/policy.json,并做如下修改(藍色部分為上一步說創建的 admin_domain 的 id):
3. 重啟 keystone service
3.2 操作
1. 獲取 cloud_admin 用戶 scoped domain 'admin_domain' token
CLOUD_ADMIN_TOKEN=$(/curl http://localhost:5000/v3/auth/tokens / -s / -i / -H "Content-Type: application/json" / -d '{ "auth": { "identity": { "methods": [ "password" ], "password": { "user": { "domain": { "name": "admin_domain" }, "name": "cloud_admin", "password": "password" } } }, "scope": { "domain": { "name": "admin_domain" } } }}' | grep ^X-Subject-Token: | awk '{print $2}' )
注意 Keystone token 分為兩大類:domain-scoped token 和 project-scoped token,各自需要使用不同的 scope 目標:
--os-domain-name <auth-domain-name> | --os-domain-id <auth-domain-id> Domain-level authorization scope (name or ID) --os-project-name <auth-project-name> | --os-project-id <auth-project-id> Project-level authentication scope (name or ID)
其中 domain-scoped token 用于操作 domain 范圍內的資源,包括 projects 和 users;project-scoped token 用于操作 project 范圍的資源??梢院唵蔚卣J為,前者適合于 cloud admin 和 domain admin;后者合適于 project admin 和 標準 user。
2. 創建域 dom1
ID_DOM1=$(/curl http://localhost:5000/v3/domains / -s / -H "X-Auth-Token: $CLOUD_ADMIN_TOKEN" / -H "Content-Type: application/json" / -d '{ "domain": { "enabled": true, "name": "dom1" }}' | jq .domain.id | tr -d '"')
3. 在 dom1 中創建第一個用戶 adm1
ID_ADM1=$(/curl http://localhost:5000/v3/users / -s / -H "X-Auth-Token: $CLOUD_ADMIN_TOKEN" / -H "Content-Type: application/json" / -d "{ /"user/": { /"description/": /"Administrator of domain dom1/", /"domain_id/": /"$ID_DOM1/", /"enabled/": true, /"name/": /"adm1/", /"password/": /"password/" }}" | jq .user.id | tr -d '"')
4. 賦予用戶 adm1 'admin' role
curl -X PUT http://localhost:5000/v3/domains/${ID_DOM1}/users/${ID_ADM1}/roles/${ADMIN_ROLE_ID} / -s / -i / -H "X-Auth-Token: $CLOUD_ADMIN_TOKEN" / -H "Content-Type: application/json"
5. 獲取 adm1 在 dom1 中的 token,同樣是domain-scoped 的
ADM1_TOKEN=$(/curl http://localhost:5000/v3/auth/tokens / -s / -i / -H "Content-Type: application/json" / -d '{ "auth": { "identity": { "methods": [ "password" ], "password": { "user": { "domain": { "name": "dom1" }, "name": "adm1", "password": "password" } } }, "scope": { "domain": { "name": "dom1" } } }}' | grep ^X-Subject-Token: | awk '{print $2}' )
6. 在 dom1 中創建 prj1
ID_PRJ1=$(/curl http://localhost:5000/v3/projects / -s / -H "X-Auth-Token: $ADM1_TOKEN" / -H "Content-Type: application/json" / -d "{ /"project/": { /"enabled/": true, /"domain_id/": /"$ID_DOM1/", /"name/": /"prj1/" }/}" | jq .project.id | tr -d '"' )echo "ID of prj1: $ID_PRJ1"
7. 在 dom1 中創建標準用戶 usr1
ID_USR1=$(/curl http://localhost:5000/v3/users / -s / -H "X-Auth-Token: $ADM1_TOKEN" / -H "Content-Type: application/json" / -d "{ /"user/": { /"default_project_id/": /"$ID_PRJ1/", /"description/": /"Just a user of dom1/", /"domain_id/": /"$ID_DOM1/", /"enabled/": true, /"name/": /"usr1/", /"password/": /"password/" }}" | jq .user.id | tr -d '"' )echo "ID of user usr1: $ID_USR1"
8. 賦予 usr1 Member 權限
MEMBER_ROLE_ID=$(/curl http://localhost:5000/v3/roles?name=Member / -s / -H "X-Auth-Token: $ADM1_TOKEN" /| jq .roles[0].id | tr -d '"' )curl -X PUT http://localhost:5000/v3/projects/${ID_PRJ1}/users/${ID_USR1}/roles/${MEMBER_ROLE_ID} / -s / -i / -H "X-Auth-Token: $ADM1_TOKEN" / -H "Content-Type: application/json"
3.3 使用 OpenStack CLI 操作
經過測試,獲得如下結果:
1. 使用 cloud_admin 用戶在 openstack CLI 操作都正常
2. 使用 domain admin 用戶 adm1 用戶在 OpenStack CLI 中不正常
從 OpenStac CLI 文檔上看,可以通過下面的方法獲取不同 scoped token:
--os-domain-name <auth-domain-name> | --os-domain-id <auth-domain-id>Domain-level authorization scope (name or ID)--os-project-name <auth-project-name> | --os-project-id <auth-project-id>Project-level authentication scope (name or ID)
但是實際測試中,使用 --os-domain-name 無法獲取期望的 domain-scoped token:
root@controller:/home/sammy# openstack --os-domain-name dom1 --os-username adm1 --os-password password --os-user-domain-name dom1 user listYou are not authorized to perform the requested action: identity:list_users (HTTP 403) (Request-ID: req-ea4b10-0a35-4d88-907f-bab181544f40)
調試發現,此時的token 自帶有 project_id,而不帶有 domain_id。還需要進一步確認是否是個 bug。
一個 workaround 是,對于這種 domain admin 用戶,需要首選獲取 domain scoped token,然后通過 curl 操作,比如要獲取 domain 內的project 列表:
root@controller:/home/sammy# curl -sX GET -H "X-Auth-Token:$ADM1_TOKEN" http://mysqlserver:5000/v3/projects?domain_id=db7de29b35dd450284dc99bc0a6474ca{"links": {"self": "http://mysqlserver:5000/v3/projects?domain_id=db7de29b35dd450284dc99bc0a6474ca", "previous": null, "next": null}, "projects": [{"is_domain": false, "description": "", "links": {"self": "http://mysqlserver:5000/v3/projects/7ff06beb0045405f8bebcda166f47f04"}, "enabled": true, "id": "7ff06beb0045405f8bebcda166f47f04", "parent_id": "db7de29b35dd450284dc99bc0a6474ca", "domain_id": "db7de29b35dd450284dc99bc0a6474ca", "name": "prj1"}
3. 從結果看, Mitaka 版本的 OpenStack CLI 對多域的支持情況如下:
3.4 Horizon 對多域的支持
3.4.1 準備工作
1. 修改 /etc/openstack-dashboard/local_settings.py 文件:
OPENSTACK_API_VERSIONS = { "data-processing": 1.1, "identity": 3, "volume": 2, "compute": 2,}# Set this to True if running on multi-domain model. When this is enabled, it# will require user to enter the Domain name in addition to username for login.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
2. 將 keystone 使用的支持多域的 policy.json 文件拷貝到目錄/etc/openstack-dashboard/keystone_policy.json,然后修改文件local_settings.py:
POLICY_FILES = { 'identity': 'keystone_policy.json'}
3. 重啟 horizon 服務,此時可以使用 domain 和 username,password 登錄
4. 簡單測試了一下,發現還是有不少問題。
比如 cloud admin dashboard 中只能出來它所在的domain,而不能出來所有的 domains:
以domain admin 登錄,直接報錯:
以普通用戶登錄,還能顯示 Admin/System 面板。
備注:Keystone V3 中的概念較多,涉及的面較廣,本文只是說明了一部分,甚至不是很準確。接下來會根據需要持續更新。
新聞熱點
疑難解答
圖片精選