Implement secure RBAC for usage
This commit updates the policies for the usage resource in placement to support read-only roles. This is part of a broader community effort to support read-only roles and implement secure, consistent default policies. This commit also allows project readers to see project-specific usages, resolve a long-standing policy TODO. Co-Authored-By: Stephen Finucane <stephenfin@redhat.com> Change-Id: I80afaae965d3c5f862320ac11a7d05db2f6b6553
This commit is contained in:
parent
1f9529f8a0
commit
7a7365c7e0
|
@ -88,18 +88,17 @@ def get_total_usages(req):
|
|||
sum/total of usages.
|
||||
Return 404 Not Found if the wanted microversion does not match.
|
||||
"""
|
||||
project_id = req.GET.get('project_id')
|
||||
user_id = req.GET.get('user_id')
|
||||
|
||||
context = req.environ['placement.context']
|
||||
# TODO(mriedem): When we support non-admins to use GET /usages we
|
||||
# should pass the project_id (and user_id?) from the query parameters
|
||||
# into context.can() for the target.
|
||||
context.can(policies.TOTAL_USAGES)
|
||||
context.can(
|
||||
policies.TOTAL_USAGES,
|
||||
target={'project_id': project_id})
|
||||
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
|
||||
|
||||
util.validate_query_params(req, schema.GET_USAGES_SCHEMA_1_9)
|
||||
|
||||
project_id = req.GET.get('project_id')
|
||||
user_id = req.GET.get('user_id')
|
||||
|
||||
usages = usage_obj.get_all_by_project_user(context, project_id,
|
||||
user_id=user_id)
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ RULE_ADMIN_API = 'rule:admin_api'
|
|||
# let's continue using generic check strings.
|
||||
SYSTEM_ADMIN = 'role:admin and system_scope:all'
|
||||
SYSTEM_READER = 'role:reader and system_scope:all'
|
||||
PROJECT_READER = 'role:reader and project_id:%(project_id)s'
|
||||
PROJECT_READER_OR_SYSTEM_READER = f'({SYSTEM_READER}) or ({PROJECT_READER})'
|
||||
|
||||
rules = [
|
||||
# "placement" is the default rule (action) used for all routes that do
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
|
||||
from oslo_log import versionutils
|
||||
from oslo_policy import policy
|
||||
|
||||
from placement.policies import base
|
||||
|
@ -19,34 +20,49 @@ from placement.policies import base
|
|||
PROVIDER_USAGES = 'placement:resource_providers:usages'
|
||||
TOTAL_USAGES = 'placement:usages'
|
||||
|
||||
DEPRECATED_REASON = """
|
||||
The usage API now supports a read-only role by default.
|
||||
"""
|
||||
|
||||
deprecated_list_rp_usages = policy.DeprecatedRule(
|
||||
name=PROVIDER_USAGES,
|
||||
check_str=base.RULE_ADMIN_API
|
||||
)
|
||||
deprecated_list_total_usages = policy.DeprecatedRule(
|
||||
name=TOTAL_USAGES,
|
||||
check_str=base.RULE_ADMIN_API
|
||||
)
|
||||
|
||||
|
||||
rules = [
|
||||
policy.DocumentedRuleDefault(
|
||||
PROVIDER_USAGES,
|
||||
base.RULE_ADMIN_API,
|
||||
"List resource provider usages.",
|
||||
[
|
||||
name=PROVIDER_USAGES,
|
||||
check_str=base.SYSTEM_READER,
|
||||
description="List resource provider usages.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/resource_providers/{uuid}/usages'
|
||||
}
|
||||
],
|
||||
scope_types=['system']),
|
||||
scope_types=['system'],
|
||||
deprecated_rule=deprecated_list_rp_usages,
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since=versionutils.deprecated.WALLABY),
|
||||
policy.DocumentedRuleDefault(
|
||||
# TODO(mriedem): At some point we might set scope_types=['project']
|
||||
# so that non-admin project-scoped token users can query usages for
|
||||
# their project. The context.can() target will need to change as well
|
||||
# in the actual policy enforcement check in the handler code.
|
||||
TOTAL_USAGES,
|
||||
base.RULE_ADMIN_API,
|
||||
"List total resource usages for a given project.",
|
||||
[
|
||||
name=TOTAL_USAGES,
|
||||
check_str=base.PROJECT_READER_OR_SYSTEM_READER,
|
||||
description="List total resource usages for a given project.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/usages'
|
||||
}
|
||||
],
|
||||
scope_types=['system'])
|
||||
scope_types=['system', 'project'],
|
||||
deprecated_rule=deprecated_list_total_usages,
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since=versionutils.deprecated.WALLABY)
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
fixtures:
|
||||
- LegacyRBACPolicyFixture
|
||||
|
||||
vars:
|
||||
- &project_id 9520f97991e94f30a8dd205ef3ce735a
|
||||
- &project_admin_headers
|
||||
x-auth-token: user
|
||||
x-roles: admin,member,reader
|
||||
x-project-id: *project_id
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
- &project_member_headers
|
||||
x-auth-token: user
|
||||
x-roles: member,reader
|
||||
x-project-id: *project_id
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
|
||||
tests:
|
||||
|
||||
- name: project admin can create resource provider
|
||||
POST: /resource_providers
|
||||
request_headers: *project_admin_headers
|
||||
data:
|
||||
name: $ENVIRON['RP_NAME']
|
||||
uuid: $ENVIRON['RP_UUID']
|
||||
status: 200
|
||||
|
||||
- name: project member cannot list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *project_member_headers
|
||||
status: 403
|
||||
|
||||
- name: project admin can list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *project_admin_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
- name: project member cannot get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *project_member_headers
|
||||
status: 403
|
||||
|
||||
- name: project admin can get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *project_admin_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
|
@ -0,0 +1,154 @@
|
|||
---
|
||||
fixtures:
|
||||
- SecureRBACPolicyFixture
|
||||
|
||||
vars:
|
||||
- &project_id $ENVIRON['PROJECT_ID']
|
||||
- &project_id_alt $ENVIRON['PROJECT_ID_ALT']
|
||||
- &system_admin_headers
|
||||
x-auth-token: user
|
||||
x-roles: admin,member,reader
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
openstack-system-scope: all
|
||||
- &system_reader_headers
|
||||
x-auth-token: user
|
||||
x-roles: reader
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
openstack-system-scope: all
|
||||
- &project_admin_headers
|
||||
x-auth-token: user
|
||||
x-roles: admin,member,reader
|
||||
x-project-id: *project_id
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
- &project_member_headers
|
||||
x-auth-token: user
|
||||
x-roles: member,reader
|
||||
x-project-id: *project_id
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
- &project_reader_headers
|
||||
x-auth-token: user
|
||||
x-roles: reader
|
||||
x-project-id: *project_id
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
- &alt_project_admin_headers
|
||||
x-auth-token: user
|
||||
x-roles: admin,member,reader
|
||||
x-project-id: *project_id_alt
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
- &alt_project_member_headers
|
||||
x-auth-token: user
|
||||
x-roles: member,reader
|
||||
x-project-id: *project_id_alt
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
- &alt_project_reader_headers
|
||||
x-auth-token: user
|
||||
x-roles: reader
|
||||
x-project-id: *project_id_alt
|
||||
accept: application/json
|
||||
content-type: application/json
|
||||
openstack-api-version: placement latest
|
||||
|
||||
tests:
|
||||
|
||||
- name: system admin can create resource provider
|
||||
POST: /resource_providers
|
||||
request_headers: *system_admin_headers
|
||||
data:
|
||||
name: $ENVIRON['RP_NAME']
|
||||
uuid: $ENVIRON['RP_UUID']
|
||||
status: 200
|
||||
|
||||
- name: project admin cannot list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *project_admin_headers
|
||||
status: 403
|
||||
|
||||
- name: project member cannot list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *project_member_headers
|
||||
status: 403
|
||||
|
||||
- name: project reader cannot list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *project_reader_headers
|
||||
status: 403
|
||||
|
||||
- name: system reader can list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *system_reader_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
- name: system admin can list provider usage
|
||||
GET: /resource_providers/$ENVIRON['RP_UUID']/usages
|
||||
request_headers: *system_admin_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
- name: project admin can get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *project_admin_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
- name: project member can get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *project_member_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
- name: project reader can get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *project_reader_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
# Make sure users from other projects can't snoop around for usage on projects
|
||||
# they have no business knowing about.
|
||||
- name: project admin cannot get total usage for unauthorized project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *alt_project_admin_headers
|
||||
status: 403
|
||||
|
||||
- name: project member cannot get total usage for unauthorized project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *alt_project_member_headers
|
||||
status: 403
|
||||
|
||||
- name: project reader cannot get total usage for unauthorized project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *alt_project_reader_headers
|
||||
status: 403
|
||||
|
||||
- name: system reader can get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *system_reader_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
||||
|
||||
- name: system admin can get total usage for project
|
||||
GET: /usages?project_id=$ENVIRON['PROJECT_ID']
|
||||
request_headers: *system_admin_headers
|
||||
status: 200
|
||||
response_json_paths:
|
||||
usages: {}
|
Loading…
Reference in New Issue