SovereignCloudStack / issues

This repository is used for issues that are cross-repository or not bound to a specific repository.
https://github.com/orgs/SovereignCloudStack/projects/6
2 stars 1 forks source link

Domain Admin rights for SCS IaaS Customers #184

Open fkr opened 2 years ago

fkr commented 2 years ago

SCS Clouds should provide a way to grant Domain Manager rights to SCS Customers. To avoid conflict with the unscoped admin role in OpenStack we want to refer to this as "Domain Manager" (domain-manager)

Action Items

reqa commented 1 year ago

I found https://bugs.launchpad.net/keystone/+bug/1783659 , I guess that's what this issue is about. It references https://specs.openstack.org/openstack/keystone-specs/specs/keystone/ongoing/policy-goals-and-roadmap.html

Test confirms that an admin (domain and/or project) can see all other domains:

# Test domain scope visibility on CLI as in
#     https://bugs.launchpad.net/keystone/+bug/1783659
## Setup:
### Domain admin:
openstack --os-cloud admin domain create TestDomain
openstack --os-cloud admin user create --domain TestDomain --password password TestDomainAdmin1
openstack --os-cloud admin role add --domain TestDomain --user TestDomainAdmin1 admin
### Project admin:
openstack --os-cloud admin user create --domain TestDomain --password password TestDomainAdmin2
openstack --os-cloud admin project create --domain TestDomain TestDomainProject
openstack --os-cloud admin role add --project-domain TestDomain --project TestDomainProject --user TestDomainAdmin2 admin

## Test with domain admin:
openstack --os-auth-url https://api.testbed.osism.xyz:5000/v3 \
                    --os-username TestDomainAdmin1 --os-user-domain-name TestDomain \
                    --os-auth-type password --os-password password \
                    --os-domain-name TestDomain \
                    token issue
### "Domain Admin" sees all domains with this "domain scoped" token
### (see https://docs.openstack.org/keystone/latest/admin/tokens-overview.html):
openstack --os-endpoint https://api.testbed.osism.xyz:5000/v3 --os-token <$OS_TOKEN>  domain list

## Test with project admin:
openstack --os-auth-url https://api.testbed.osism.xyz:5000/v3 \
                    --os-username TestDomainAdmin2 --os-user-domain-name TestDomain \
                    --os-auth-type password --os-password password \
                    --os-project-name TestDomainProject --os-project-domain-name TestDomain \
                    token issue
### "Project Admin" sees all domains with this "project scoped" token
### (see https://docs.openstack.org/keystone/latest/admin/tokens-overview.html):
openstack --os-endpoint https://api.testbed.osism.xyz:5000/v3 --os-token <$OS_TOKEN> domain list

The interesting point is, that this seems to be independent of the question of domain or not domain. The point is the admin role. Even if you just use projects. But yes, in that sense domains don't seem to offer additional separation currently.

markus-hentsch commented 1 year ago

Keystone policy-based domain admin concept

As documented before, OpenStack does not properly scope the "admin" role, making domain separation questionable for self-service approaches using that role.

As an alternative, using policy adjustments in Keystone, a new role could be established that acts as a counterpart to the "admin" role but scoped within domains. Below I have documented a prototype of such approach that I tried out with that goal in mind. This approach implements the following key changes:

Notes regarding "Definition of Done":

Preparation

openstack domain create domain-a
openstack domain create domain-b

openstack user create --domain domain-a --password b0gusp4ss domain-a-admin
openstack user create --domain domain-b --password b0gusp4ss domain-b-admin

openstack project create --domain domain-a domain-a-project-1
openstack project create --domain domain-b domain-b-project-1

openstack role create domain-admin-role
openstack role add --user domain-a-admin --domain domain-a domain-admin-role
openstack role add --user domain-b-admin --domain domain-b domain-admin-role

openstack role assignment list --names --role domain-admin-role
+-------------------+-------------------------+-------+---------+----------+--------+-----------+
| Role              | User                    | Group | Project | Domain   | System | Inherited |
+-------------------+-------------------------+-------+---------+----------+--------+-----------+
| domain-admin-role | domain-a-admin@domain-a |       |         | domain-a |        | False     |
| domain-admin-role | domain-b-admin@domain-b |       |         | domain-b |        | False     |
+-------------------+-------------------------+-------+---------+----------+--------+-----------+

RC file examples

An RC file example for a domain admin would look like this:

export OS_REGION_NAME=RegionOne
export OS_INTERFACE=public
export OS_AUTH_URL=https://identity.mycloud.com/v3
export OS_DOMAIN_NAME=domain-a
export OS_USERNAME=domain-a-admin
export OS_VOLUME_API_VERSION=3
export OS_AUTH_TYPE=password
export OS_USER_DOMAIN_NAME=domain-a
export OS_DOMAIN_NAME=domain-a
export OS_PASSWORD=b0gusp4ss
export OS_IDENTITY_API_VERSION=3

Policy Definitions

    # classify domain admins with a special role
    "is_domain_admin": "role:domain-admin-role"

    # allow domain admins to retrieve their own domain
    "identity:get_domain": "(rule:is_domain_admin and token.domain.id:%(target.domain.id)s) or rule:admin_required"

    # specify a rule that whitelists roles which domain admins are permitted to assign and revoke
    "is_domain_role": "%(target.role.name)s:member"

    # list_domains is needed for GET /v3/domains?name=... requests
    # this is mandatory for things like "create user --domain $DOMAIN_NAME $USER_NAME" to correctly discover domains by name
    "identity:list_domains": "rule:is_domain_admin or rule:admin_required"

    # list_roles is needed for GET /v3/roles?name=... requests
    # this is mandatory for things like "role add ... $ROLE_NAME" to correctly discover roles by name
    "identity:list_roles": "rule:is_domain_admin or rule:admin_required"

    # allow domain admins to manage user within their domain
    "identity:list_users": "(rule:is_domain_admin and token.domain.id:%(target.domain_id)s) or rule:admin_required"
    "identity:get_user": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s) or rule:admin_required"
    "identity:create_user": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s) or rule:admin_required"
    "identity:update_user": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s) or rule:admin_required"
    "identity:delete_user": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s) or rule:admin_required"

    # allow domain admins to manage projects within their domain
    "identity:list_projects": "(rule:is_domain_admin and token.domain.id:%(target.domain_id)s) or rule:admin_required"
    "identity:get_project": "(rule:is_domain_admin and token.domain.id:%(target.project.domain_id)s) or rule:admin_required"
    "identity:create_project": "(rule:is_domain_admin and token.domain.id:%(target.project.domain_id)s) or rule:admin_required"
    "identity:update_project": "(rule:is_domain_admin and token.domain.id:%(target.project.domain_id)s) or rule:admin_required"
    "identity:delete_project": "(rule:is_domain_admin and token.domain.id:%(target.project.domain_id)s) or rule:admin_required"

    # allow domain admins to manage role assignments within their domain
    # (restricted to specific roles by the 'is_domain_role' rule)
    "identity:check_grant": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s and token.domain.id:%(target.project.domain_id)s and rule:is_domain_role) or rule:admin_required"
    "identity:list_grants": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s and token.domain.id:%(target.project.domain_id)s and rule:is_domain_role) or rule:admin_required"
    "identity:create_grant": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s and token.domain.id:%(target.project.domain_id)s and rule:is_domain_role) or rule:admin_required"
    "identity:revoke_grant": "(rule:is_domain_admin and token.domain.id:%(target.user.domain_id)s and token.domain.id:%(target.project.domain_id)s and rule:is_domain_role) or rule:admin_required"

    # allow 'role assignment list' scoped to the domain
    "identity:list_role_assignments": "(rule:is_domain_admin and token.domain.id:%(target.domain_id)s) or rule:admin_required"

Limitations

The approach described here currently has the following limitations:

  1. due to the "identity:list_domains" rule, domain admins are able to see all domains via "openstack domain list" and can inspect other domains with "openstack domain show"
    • this is due to the lack of proper domain-scoping for the domain list API, see [1]
  2. due to the "identity:list_roles" rule, domain admins are able to see all roles via "openstack role list" and can inspect other roles with "openstack role show"
  3. the described approach has not been extensively pentested yet

The result of points 1 and 2 is that the metadata of all domains and roles will be exposed to all domain admins!


[1] about the lack of domain-scoping for the domains API

When a command specifying an object per name is used, e.g. the domain in "openstack user create --domain my-domain ..." then openstackclient will attempt to resolve the domain name into the domain ID by internally retrieving the domain list via "GET /v3/domains?name=my-domain" before attempting to create the user object. That means, that even if the domain admin only needs their own domain, they need access to the domain list API to resolve the name to ID of their very own domain.
The same goes for the roles API: resolving a role name to ID is done via the roles list API in the client.

For "openstack project list" there is proper domain-scoping implemented:

This is currently not implemented for "openstack domain list":

This policy works for projects:

"identity:list_projects": "(rule:is_domain_admin and token.domain.id:%(target.domain_id)s) or rule:admin_required"

This policy does not work for domains:

"identity:list_domains": "(rule:is_domain_admin and token.domain.id:%(target.domain.id)s) or rule:admin_required"

and leads to the following error upon "openstack domain list":

You are not authorized to perform the requested action: identity:list_domains. (HTTP 403) (Request-ID: req-224b577d-c428-4720-a03e-cb195471afba)

This is why the policy has to be configured to allow domain admins to list all domains in order to enable them to manage user, projects and role assignments within their domain properly.

Follow up Action Item:

reqa commented 1 year ago

Thank you very much @markus-hentsch for this valuable contribution and the research and expertise that have gone into it. We have discussed this in last weeks SCS SIG IAM and would like to implement this approach for SCS. We would like to call the role domain-manager instead for two reasons: 1. to avoid confusion with the unscoped admin role and to be inline with the upstream plan https://specs.openstack.org/openstack/keystone-specs/specs/keystone/2023.1/default-service-role.html .

reqa commented 1 year ago

@matfechner where does this have to go? First to https://github.com/osism/testbed ? Or somewhere in https://github.com/osism/cfg-generics ?

fkr commented 1 year ago

This is going to be tested by AOV and arcodix in their greenfield deployments.

markus-hentsch commented 8 months ago

FTR, we discussed domain management with Arvid, Artem and Juan during the IAM SIG call on 2024-03-06 in the scope of the ongoing work on the Keycloak and identity federation. There is one very important point that we realized:

The Domain Manager Role for Keystone as per the current SCS standard draft is pretty much mutually exclusive to identity federation. Reason is that managing identity resources (users, projects, groups, role assignments) is not Keystone's responsibility anymore when using an external Identity Provider such as Keycloak. As a result, manipulating such resources and their relationships within Keystone is neither possible (at least not in a persistent fashion) nor desired.

In a federated setup the current Domain Manager Role is only useful for and applicable to the small subset of local Keystone user accounts not managed by any external Identity Provider or for setups that don't use identity federation at all.