OpenStack Mitaka 版本中的 domain 和 admin


OpenStack 的 Keystone V3 中引入了 Domain 的概念。引入這個概念后,關於 admin 這個role 的定義就變得復雜了起來。 

本文測試環境是社區 Mitaka 版本。

1. Domain,project,user,role,token 的概念和關系

1.1 概況

簡單來說,

  • Domain - 表示 project 和 user 的集合,在公有雲或者私有雲中常常表示一個客戶
  • Group - 一個domain 中的部分用戶的集合
  • Project - IT基礎設施資源的集合,比如虛機,卷,鏡像等
  • Role - 角色,表示一個 user 對一個 project resource 的權限 
  • Token - 一個 user 對於某個目標(project 或者 domain)的一個有限時間段內的身份令牌

它們之間的關系用一個不完整的圖來表示:

說明:

  • Domain 可以認為是 project,user,group 的 namespace。 一個 domain 內,這些元素的名稱不可以重復,但是在兩個不同的domain內,它們的名稱可以重復。因此,在確定這些元素時,需要同時使用它們的名稱和它們的 domain 的 id 或者 name。
  • Group 是一個 domain 部分 user 的集合,其目的是為了方便分配 role。給一個 group 分配 role,結果會給 group 內的所有 users 分配這個 role。
  • Role 是全局(global)的,因此在一個 keystone 管轄范圍內其名稱必須唯一。role 的名稱沒有意義,其意義在於 policy.json 文件根據 role 的名稱所指定的允許進行的操作。
  • 簡單地,role 可以只有 admin 和 member 兩個,前者表示管理員,后者表示普通用戶。但是,結合 domain 和 project 的限定,admin 可以分為 cloud admin,domain admin 和 project admin。
  • policy.json 文件中定義了 role 對某種類型的資源所能進行的操作,比如允許 cloud admin 創建 domain,允許所有用戶創建卷等
  • project 是資源的集合,其中有一類特殊的project 是 admin project。通過指定 admin_project_domain_name 和 admin_project_name 來確定一個 admin project,然后該project 中的 admin 用戶即是 cloud admin。
  • Token 具有 scope 的概念,分為 unscoped token,domain-scoped token 和 project-scoped token。下文有說明。

1.2 Token scope 和 Scoped token

官方文檔在這里,我這里寫的只是我的理解。

Token 是針對不同 scope 認證狀態,這里的 scope 是指 project 和 domain,因此一共有三種 scoped token:

  • project-scoped token:針對一個 project 的 token,它包含 service catalog, a set of roles, 和那個 project 的詳細信息
  • domain-scoped token:針對一個 domain  的 token,它具有有限的使用場景,只用於 domain 層面的操作。與 project-scoped 相比,它只具有優先的 sevice catalog
  • unscoped token:當既不指定 project 也不指定 domain 為 scope ,同時 user 也沒有 default project 時獲得的 token,這是一種特殊的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:

  • 他擁有 'admin' 這個 role,而這里的 ‘admin’ 是寫死的,因為默認就是使用這個名字,當然你可以修改它,比如創建一個 cloud_admin role,然后修改這里為 role:cloud_admin,其效果是一樣的。
  • is_admin:1:這個只是在項目啟動后才使用,其判斷條件是操作使用的token 和 keystone.conf 中的 admin_token 相同。

從 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",

可見:

  • 創建 volume:不限特定權限,只要是 user 角色就行
  • 刪除 volume,獲取所有volumes:需要 admin 或者 project owner 權限,owner 是指用戶 token 的 project id 和被刪除 volume 的 project id 相同(也就是說對於一個 project 中的兩個普通用戶 user1 和 user2,user2 可以刪除 user1 創建的 volume,但是不可以刪除)

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 的主要職責是
    • 創建 domains
    • 為每個 domain 創建 domain admin
  • domain admin:必須擁有 admin role;token 的 domain id 必須和被操作資源(包括user,project 等) 的 domain id 相同。其主要職責包括
    • 在該 domain 內創建 projects
    • 在該 domain 內創建 users
    • 分配 project 的權限給 user,包括 admin 和 user,前者就是 project admin,后者是 project user

只有 Cloud admin 擁有的一些權限:

  • region 的增刪改
  • service 的增刪改
  • endpoint 的增刪改
  • domain 的列表,增刪改
  • role 增刪改

只有 Domain admin 擁有的一些權限(當然這些權限 cloud admin 都擁有):

  • 獲取特定 domain 的信息
  • 列表 projects,以及增刪改
  • 列表 users 和 groups
  • user 增刪改

2.2.2 示例規則說明

1 "admin_required": "role:admin",
2 
3 "identity:create_project": "rule:admin_required and domain_id:%(project.domain_id)s",
4 
5 "identity:get_project": "rule:admin_required and domain_id:%(target.project.domain_id)s",
6 
7 "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成功

這里有幾個關鍵點需要注意:

  • 首先userA在domainA內必須要有admin權限,這樣才能滿足rule:admin_required
  • 其次,token需要是一個domain scope的token,這樣token中才會有domain_id 
  • 再次,創建project的時候,domain_id參數必須等於domainA的id,這樣才能滿足domain_id:%(project.domain_id)s

這樣一條規則的意義在於,可以限制只有在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):

"cloud_admin": "role:admin and (token.is_admin_project:True or domain_id:2b871f5dba704f74923ac01b4fcd7205)"

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 范圍的資源。可以簡單地認為,前者適合於 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:同 REST API 中 的 scope/domain/name,獲取 domain-scoped token
  • --os-project-name:同 REST API 中的 scope/project/name,獲取 project-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 list
You 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 對多域的支持情況如下:

  • 支持 cloud admin,這是通過 admin domain 的方式來實現的
  • 支持 project owner,通過 project-scoped token
  • 支持普通 user,通過 project-scoped token
  • 不支持 domain admin,因為無法獲取 domain-scoped token

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 中的概念較多,涉及的面較廣,本文只是說明了一部分,甚至不是很准確。接下來會根據需要持續更新。

 

參考鏈接:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM