Add service role in Nova policy
RBAC community wide goal phase-2[1] is to add 'service' role for the service APIs policy rule. This commit defaults the service APIs to 'service' role. This way service APIs will be allowed for service user only. Tempest tests also modified to simulate the service-to-service communication. Tempest tests send the user with service role to nova API. - https://review.opendev.org/c/openstack/tempest/+/892639> Partial implement blueprint policy-service-role-default [1] https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html#phase-2 Change-Id: I1565ea163fa2c8212f71c9ba375654d2aab28330 Signed-off-by: Ghanshyam Maan <gmaan@ghanshyammann.com>
This commit is contained in:
@@ -54,6 +54,19 @@ the `API guide <https://docs.openstack.org/api-guide/compute/index.html>`_.
|
||||
.. include:: os-server-external-events.inc
|
||||
.. include:: server-topology.inc
|
||||
|
||||
=====================
|
||||
Internal Service APIs
|
||||
=====================
|
||||
|
||||
.. warning::
|
||||
The below Nova APIs are meant to communicate to OpenStack services. Those
|
||||
APIs are not supposed to be used by any users because they can make
|
||||
deployment or resources in unwanted state.
|
||||
|
||||
.. include:: os-assisted-volume-snapshots.inc
|
||||
.. include:: os-volume-attachments-swap.inc
|
||||
.. include:: os-server-external-events.inc
|
||||
|
||||
===============
|
||||
Deprecated APIs
|
||||
===============
|
||||
|
||||
60
api-ref/source/os-volume-attachments-swap.inc
Normal file
60
api-ref/source/os-volume-attachments-swap.inc
Normal file
@@ -0,0 +1,60 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
.. _os-volume-attachments-swap:
|
||||
|
||||
===============================================================================
|
||||
Update ("swapping") Server volume attachments (servers, os-volume\_attachments)
|
||||
===============================================================================
|
||||
|
||||
Update ("swapping") the server volume attachments which means swapping
|
||||
the volume attached to the server.
|
||||
|
||||
Update(swapping) a volume attachment
|
||||
====================================
|
||||
|
||||
.. rest_method:: PUT /servers/{server_id}/os-volume_attachments/{volume_id}
|
||||
|
||||
Update a volume attachment.
|
||||
|
||||
.. note:: This action only valid when the server is in ACTIVE, PAUSED and RESIZED state,
|
||||
or a conflict(409) error will be returned.
|
||||
|
||||
.. Important::
|
||||
|
||||
When updating volumeId, this API **MUST** only be used
|
||||
as part of a larger orchestrated volume
|
||||
migration operation initiated in the block storage
|
||||
service via the ``os-retype`` or ``os-migrate_volume``
|
||||
volume actions. Direct usage of this API is not supported
|
||||
and will be blocked by nova with a 409 conflict.
|
||||
Furthermore, updating ``volumeId`` via this API is only
|
||||
implemented by `certain compute drivers`_.
|
||||
|
||||
.. _certain compute drivers: https://docs.openstack.org/nova/latest/user/support-matrix.html#operation_swap_volume
|
||||
|
||||
Updating, or what is commonly referred to as "swapping", volume attachments
|
||||
with volumes that have more than one read/write attachment, is not supported.
|
||||
|
||||
Normal response codes: 202
|
||||
|
||||
Error response codes: badRequest(400), unauthorized(401), forbidden(403), itemNotFound(404), conflict(409)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_id: server_id_path
|
||||
- volume_id: volume_id_swap_src
|
||||
- volumeAttachment: volumeAttachment_put
|
||||
- volumeId: volumeId_swap
|
||||
|
||||
**Example Update a volume attachment: JSON request**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/os-volume_attachments/update-volume-req.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
No body is returned on successful request.
|
||||
@@ -182,31 +182,10 @@ Update a volume attachment
|
||||
|
||||
Update a volume attachment.
|
||||
|
||||
.. note:: This action only valid when the server is in ACTIVE, PAUSED and RESIZED state,
|
||||
or a conflict(409) error will be returned.
|
||||
|
||||
.. Important::
|
||||
|
||||
When updating volumeId, this API **MUST** only be used
|
||||
as part of a larger orchestrated volume
|
||||
migration operation initiated in the block storage
|
||||
service via the ``os-retype`` or ``os-migrate_volume``
|
||||
volume actions. Direct usage of this API is not supported
|
||||
and will be blocked by nova with a 409 conflict.
|
||||
Furthermore, updating ``volumeId`` via this API is only
|
||||
implemented by `certain compute drivers`_.
|
||||
|
||||
.. _certain compute drivers: https://docs.openstack.org/nova/latest/user/support-matrix.html#operation_swap_volume
|
||||
|
||||
Policy default role is 'rule:system_admin_or_owner', its scope is
|
||||
[system, project], which allow project members or system admins to
|
||||
change the fields of an attached volume of a server. Policy defaults
|
||||
enable only users with the administrative role to change ``volumeId``
|
||||
via this operation. Cloud providers can change these permissions
|
||||
through the ``policy.json`` file.
|
||||
|
||||
Updating, or what is commonly referred to as "swapping", volume attachments
|
||||
with volumes that have more than one read/write attachment, is not supported.
|
||||
Policy default role is 'rule:admin_or_owner', its scope is [project], which
|
||||
allow project members or admins to change the fields of an attached volume of
|
||||
a server. Cloud providers can change these permissions through the
|
||||
``policy.yaml`` file.
|
||||
|
||||
Normal response codes: 202
|
||||
|
||||
@@ -218,9 +197,9 @@ Request
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_id: server_id_path
|
||||
- volume_id: volume_id_swap_src
|
||||
- volume_id: volume_id_path
|
||||
- volumeAttachment: volumeAttachment_put
|
||||
- volumeId: volumeId_swap
|
||||
- volumeId: volumeId_update
|
||||
- delete_on_termination: delete_on_termination_put_req
|
||||
- device: attachment_device_put_req
|
||||
- serverId: attachment_server_id_put_req
|
||||
|
||||
@@ -7628,6 +7628,12 @@ volumeId_swap:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
volumeId_update:
|
||||
description: |
|
||||
The UUID of the attached volume.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
volumes:
|
||||
description: |
|
||||
The list of ``volume`` objects.
|
||||
|
||||
@@ -276,6 +276,25 @@ With these new defaults, you can solve the problem of:
|
||||
to provide access to project level user to perform operations within
|
||||
their project only.
|
||||
|
||||
.. rubric:: ``service``
|
||||
|
||||
The ``service`` role is a special role in Keystone, which is used for the
|
||||
internal service-to-service communication. It is assigned to service users
|
||||
i.e. nova or neutron which model the OpenStack services. Nova defaults its
|
||||
service-to-service APIs to require the ``service`` role so that they cannot
|
||||
be used by any non-service users. Allowing access to service-to-service APIs
|
||||
to non-service users can be destructive to resources and leave the deployment
|
||||
in an invalid state. It's advisable to audit the ``policy.yaml`` files and
|
||||
keystone users to make sure those APIs are not allowed to any non-service
|
||||
users and the service role is not granted to human admin accounts.
|
||||
|
||||
.. note::
|
||||
|
||||
Make sure the configured nova service user in other services has the
|
||||
``service`` role otherwise communication from the other services to
|
||||
Nova will fail. For example, user configured as ``username`` option in
|
||||
``neutron.conf`` file under ``[nova]`` section has the ``service`` role.
|
||||
|
||||
Nova supported scope & Roles
|
||||
-----------------------------
|
||||
|
||||
@@ -308,6 +327,10 @@ overridden in the policy.yaml file but scope is not override-able.
|
||||
Such policy rules are default to most of the read only APIs so that legacy
|
||||
admin can continue to access those APIs.
|
||||
|
||||
#. SERVICE_ROLE (Internal): ``service`` role on service users with ``project``
|
||||
scope. Such policy rules are default to the service-to-service APIs (The
|
||||
APIs only meant to be called by the OpenStack services).
|
||||
|
||||
Backward Compatibility
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -41,11 +41,6 @@ class AssistedVolumeSnapshotsController(wsgi.Controller):
|
||||
def create(self, req, body):
|
||||
"""Creates a new snapshot."""
|
||||
context = req.environ['nova.context']
|
||||
# NOTE(gmann) We pass empty target to policy enforcement. This API
|
||||
# is called by cinder which does not have correct project_id.
|
||||
# By passing the empty target, we make sure that we do not check
|
||||
# the requester project_id and allow users with
|
||||
# allowed role to create snapshot.
|
||||
context.can(avs_policies.POLICY_ROOT % 'create', target={})
|
||||
|
||||
snapshot = body['snapshot']
|
||||
@@ -75,11 +70,6 @@ class AssistedVolumeSnapshotsController(wsgi.Controller):
|
||||
def delete(self, req, id):
|
||||
"""Delete a snapshot."""
|
||||
context = req.environ['nova.context']
|
||||
# NOTE(gmann) We pass empty target to policy enforcement. This API
|
||||
# is called by cinder which does not have correct project_id.
|
||||
# By passing the empty target, we make sure that we do not check
|
||||
# the requester project_id and allow users with allowed role to
|
||||
# delete snapshot.
|
||||
context.can(avs_policies.POLICY_ROOT % 'delete', target={})
|
||||
|
||||
delete_metadata = {}
|
||||
|
||||
@@ -80,11 +80,6 @@ class ServerExternalEventsController(wsgi.Controller):
|
||||
def create(self, req, body):
|
||||
"""Creates a new instance event."""
|
||||
context = req.environ['nova.context']
|
||||
# NOTE(gmann) We pass empty target to policy enforcement. This API
|
||||
# is called by neutron which does not have correct project_id where
|
||||
# server belongs to. By passing the empty target, we make sure that
|
||||
# we do not check the requester project_id and allow users with
|
||||
# allowed role to create external event.
|
||||
context.can(see_policies.POLICY_ROOT % 'create', target={})
|
||||
|
||||
response_events = []
|
||||
|
||||
@@ -329,11 +329,6 @@ class VolumeAttachmentController(wsgi.Controller):
|
||||
# different from the 'id' in the url path, or only swap is allowed by
|
||||
# the microversion, we should check the swap volume policy.
|
||||
# otherwise, check the volume update policy.
|
||||
# NOTE(gmann) We pass empty target to policy enforcement. This API
|
||||
# is called by cinder which does not have correct project_id where
|
||||
# server belongs to. By passing the empty target, we make sure that
|
||||
# we do not check the requester project_id and allow users with
|
||||
# allowed role to perform the swap volume.
|
||||
if only_swap or id != volume_id:
|
||||
context.can(va_policies.POLICY_ROOT % 'swap', target={})
|
||||
else:
|
||||
|
||||
@@ -24,14 +24,7 @@ POLICY_ROOT = 'os_compute_api:os-assisted-volume-snapshots:%s'
|
||||
assisted_volume_snapshots_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
name=POLICY_ROOT % 'create',
|
||||
# TODO(gmann): This is internal API policy and called by
|
||||
# cinder. Add 'service' role in this policy so that cinder
|
||||
# can call it with user having 'service' role (not having
|
||||
# correct project_id). That is for phase-2 of RBAC goal and until
|
||||
# then, we keep it open for all admin in any project. We cannot
|
||||
# default it to ADMIN which has the project_id in
|
||||
# check_str and will fail if cinder call it with other project_id.
|
||||
check_str=base.ADMIN,
|
||||
check_str=base.SERVICE_ROLE,
|
||||
description="Create an assisted volume snapshot",
|
||||
operations=[
|
||||
{
|
||||
@@ -42,14 +35,7 @@ assisted_volume_snapshots_policies = [
|
||||
scope_types=['project']),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=POLICY_ROOT % 'delete',
|
||||
# TODO(gmann): This is internal API policy and called by
|
||||
# cinder. Add 'service' role in this policy so that cinder
|
||||
# can call it with user having 'service' role (not having
|
||||
# correct project_id). That is for phase-2 of RBAC goal and until
|
||||
# then, we keep it open for all admin in any project. We cannot
|
||||
# default it to ADMIN which has the project_id in
|
||||
# check_str and will fail if cinder call it with other project_id.
|
||||
check_str=base.ADMIN,
|
||||
check_str=base.SERVICE_ROLE,
|
||||
description="Delete an assisted volume snapshot",
|
||||
operations=[
|
||||
{
|
||||
|
||||
@@ -41,6 +41,12 @@ ADMIN = 'rule:context_is_admin'
|
||||
PROJECT_MEMBER = 'rule:project_manager_api'
|
||||
PROJECT_MEMBER = 'rule:project_member_api'
|
||||
PROJECT_READER = 'rule:project_reader_api'
|
||||
# TODO(gmaan): Remove the admin role from the service rule in 2026.2. We are
|
||||
# continue allowing admin to access the service APIs, otherwise it will break
|
||||
# deployment where nova service users in other services are not assigned
|
||||
# 'service' role. After one SLURP (2026.1), we can make service APIs only
|
||||
# allowed for the 'service' role.
|
||||
SERVICE_ROLE = 'rule:service_or_admin'
|
||||
PROJECT_MANAGER_OR_ADMIN = 'rule:project_manager_or_admin'
|
||||
PROJECT_MEMBER_OR_ADMIN = 'rule:project_member_or_admin'
|
||||
PROJECT_READER_OR_ADMIN = 'rule:project_reader_or_admin'
|
||||
@@ -106,6 +112,11 @@ rules = [
|
||||
"role:reader and project_id:%(project_id)s",
|
||||
"Default rule for Project level read only APIs.",
|
||||
deprecated_rule=DEPRECATED_ADMIN_OR_OWNER_POLICY),
|
||||
policy.RuleDefault(
|
||||
"service_api",
|
||||
"role:service",
|
||||
"Default rule for service-to-service APIs.",
|
||||
deprecated_rule=DEPRECATED_ADMIN_POLICY),
|
||||
policy.RuleDefault(
|
||||
"project_manager_or_admin",
|
||||
"rule:project_manager_api or rule:context_is_admin",
|
||||
@@ -120,7 +131,13 @@ rules = [
|
||||
"project_reader_or_admin",
|
||||
"rule:project_reader_api or rule:context_is_admin",
|
||||
"Default rule for Project reader or admin APIs.",
|
||||
deprecated_rule=DEPRECATED_ADMIN_OR_OWNER_POLICY)
|
||||
deprecated_rule=DEPRECATED_ADMIN_OR_OWNER_POLICY),
|
||||
policy.RuleDefault(
|
||||
"service_or_admin",
|
||||
"rule:service_api or rule:context_is_admin",
|
||||
"Default rule for service or admin APIs.",
|
||||
deprecated_rule=DEPRECATED_ADMIN_POLICY),
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -24,15 +24,7 @@ POLICY_ROOT = 'os_compute_api:os-server-external-events:%s'
|
||||
server_external_events_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
name=POLICY_ROOT % 'create',
|
||||
# TODO(gmann): This is internal API policy and supposed to be called
|
||||
# by neutron, cinder, ironic, and cyborg (may be other openstack
|
||||
# services in future). Add 'service' role in this policy so that
|
||||
# neutron can call it with user having 'service' role (not having
|
||||
# server's project_id). That is for phase-2 of RBAC goal and until
|
||||
# then, we keep it open for all admin in any project. We cannot
|
||||
# default it to ADMIN which has the project_id in
|
||||
# check_str and will fail if neutron call it with other project_id.
|
||||
check_str=base.ADMIN,
|
||||
check_str=base.SERVICE_ROLE,
|
||||
description="Create one or more external events",
|
||||
operations=[
|
||||
{
|
||||
|
||||
@@ -73,14 +73,7 @@ always superset of this policy permission.
|
||||
scope_types=['project']),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=POLICY_ROOT % 'swap',
|
||||
# TODO(gmann): This is internal API policy and supposed to be called
|
||||
# only by cinder. Add 'service' role in this policy so that cinder
|
||||
# can call it with user having 'service' role (not having server's
|
||||
# project_id). That is for phase-2 of RBAC goal and until then,
|
||||
# we keep it open for all admin in any project. We cannot default it to
|
||||
# ADMIN which has the project_id in check_str and will fail
|
||||
# if cinder call it with other project_id.
|
||||
check_str=base.ADMIN,
|
||||
check_str=base.SERVICE_ROLE,
|
||||
description="Update a volume attachment with a different volumeId",
|
||||
operations=[
|
||||
{
|
||||
|
||||
@@ -132,6 +132,12 @@ class BasePolicyTest(test.TestCase):
|
||||
project_id=self.project_id_other,
|
||||
roles=['reader'])
|
||||
|
||||
# service user
|
||||
self.service_context = nova_context.RequestContext(
|
||||
user_id="service_user",
|
||||
project_id="service_user_project_id",
|
||||
roles=['service'])
|
||||
|
||||
self.all_contexts = set([
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.system_member_context, self.system_reader_context,
|
||||
@@ -140,7 +146,8 @@ class BasePolicyTest(test.TestCase):
|
||||
self.project_member_context, self.project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context,
|
||||
self.project_foo_context, self.other_project_reader_context
|
||||
self.project_foo_context, self.other_project_reader_context,
|
||||
self.service_context
|
||||
])
|
||||
|
||||
# All the project contexts for easy access.
|
||||
@@ -238,6 +245,7 @@ class BasePolicyTest(test.TestCase):
|
||||
"rule:project_member_api or rule:context_is_admin",
|
||||
"project_reader_or_admin":
|
||||
"rule:project_reader_api or rule:context_is_admin",
|
||||
"service_api": "role:service",
|
||||
})
|
||||
self.policy.set_rules(self.rules_without_deprecation,
|
||||
overwrite=False)
|
||||
|
||||
@@ -34,11 +34,10 @@ class AssistedVolumeSnapshotPolicyTest(base.BasePolicyTest):
|
||||
self.controller = snapshots.AssistedVolumeSnapshotsController()
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
# By default, legacy rule are enable and scope check is disabled.
|
||||
# system admin, legacy admin, and project admin is able to
|
||||
# take volume snapshot.
|
||||
# admin and service user is able to manage volume snapshot.
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.project_admin_context]
|
||||
self.project_admin_context, self.service_context]
|
||||
|
||||
@mock.patch('nova.compute.api.API.volume_snapshot_create')
|
||||
def test_assisted_create_policy(self, mock_create):
|
||||
@@ -98,7 +97,8 @@ class AssistedSnapshotScopeTypePolicyTest(AssistedVolumeSnapshotPolicyTest):
|
||||
# With scope check enabled, system admin is not able to
|
||||
# take volume snapshot.
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context]
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
self.service_context]
|
||||
|
||||
|
||||
class AssistedSnapshotScopeTypeNoLegacyPolicyTest(
|
||||
|
||||
@@ -84,7 +84,8 @@ class AvailabilityZoneScopeTypePolicyTest(AvailabilityZonePolicyTest):
|
||||
# able to get AZ with host information.
|
||||
self.project_admin_authorized_contexts = [self.legacy_admin_context,
|
||||
self.project_admin_context]
|
||||
self.project_authorized_contexts = self.all_project_contexts
|
||||
self.project_authorized_contexts = (self.all_project_contexts | set([
|
||||
self.service_context]))
|
||||
|
||||
|
||||
class AZScopeTypeNoLegacyPolicyTest(AvailabilityZoneScopeTypePolicyTest):
|
||||
|
||||
@@ -30,17 +30,7 @@ class ExtensionsPolicyTest(base.BasePolicyTest):
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
|
||||
# Check that everyone is able to get extension info.
|
||||
self.everyone_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.project_admin_context, self.project_manager_context,
|
||||
self.project_member_context, self.project_reader_context,
|
||||
self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
]
|
||||
self.everyone_authorized_contexts = self.all_contexts
|
||||
self.everyone_unauthorized_contexts = []
|
||||
|
||||
def test_list_extensions_policy(self):
|
||||
@@ -80,7 +70,8 @@ class ExtensionsScopeTypePolicyTest(ExtensionsPolicyTest):
|
||||
self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.everyone_unauthorized_contexts = [
|
||||
self.system_admin_context, self.system_member_context,
|
||||
|
||||
@@ -126,7 +126,8 @@ class FlavorAccessScopeTypePolicyTest(FlavorAccessPolicyTest):
|
||||
self.admin_authorized_contexts = [
|
||||
self.legacy_admin_context,
|
||||
self.project_admin_context]
|
||||
self.admin_index_authorized_contexts = self.all_project_contexts
|
||||
self.admin_index_authorized_contexts = (self.all_project_contexts |
|
||||
set([self.service_context]))
|
||||
|
||||
|
||||
class FlavorAccessScopeTypeNoLegacyPolicyTest(FlavorAccessScopeTypePolicyTest):
|
||||
|
||||
@@ -51,13 +51,15 @@ class FlavorExtraSpecsPolicyTest(base.BasePolicyTest):
|
||||
# In the base/legacy case, all project and system contexts are
|
||||
# authorized in the "anyone" case.
|
||||
self.all_authorized_contexts = (self.all_project_contexts |
|
||||
self.all_system_contexts)
|
||||
self.all_system_contexts |
|
||||
set([self.service_context]))
|
||||
|
||||
# In the base/legacy case, all project and system contexts are
|
||||
# authorized in the case of things that distinguish between
|
||||
# scopes, since scope checking is disabled.
|
||||
self.all_project_authorized_contexts = (self.all_project_contexts |
|
||||
self.all_system_contexts)
|
||||
self.all_system_contexts |
|
||||
set([self.service_context]))
|
||||
|
||||
# In the base/legacy case, any admin is an admin.
|
||||
self.admin_authorized_contexts = set([self.project_admin_context,
|
||||
@@ -211,8 +213,10 @@ class FlavorExtraSpecsScopeTypePolicyTest(FlavorExtraSpecsPolicyTest):
|
||||
self.flags(enforce_scope=True, group="oslo_policy")
|
||||
|
||||
# Only project users are authorized
|
||||
self.reduce_set('all_project_authorized', self.all_project_contexts)
|
||||
self.reduce_set('all_authorized', self.all_project_contexts)
|
||||
self.reduce_set('all_project_authorized',
|
||||
self.all_project_contexts | set([self.service_context]))
|
||||
self.reduce_set('all_authorized',
|
||||
self.all_project_contexts | set([self.service_context]))
|
||||
|
||||
# Only admins can do admin things
|
||||
self.admin_authorized_contexts = [self.legacy_admin_context,
|
||||
@@ -254,9 +258,10 @@ class FlavorExtraSpecsNoLegacyPolicyTest(FlavorExtraSpecsScopeTypePolicyTest):
|
||||
# contexts stay separate.
|
||||
self.reduce_set(
|
||||
'all_project_authorized',
|
||||
self.all_project_contexts - set([self.project_foo_context]))
|
||||
self.all_project_contexts - set([self.project_foo_context,
|
||||
self.service_context]))
|
||||
everything_but_foo_and_system = (
|
||||
self.all_contexts - set([
|
||||
self.project_foo_context,
|
||||
self.project_foo_context, self.service_context,
|
||||
]) - self.all_system_contexts)
|
||||
self.reduce_set('all_authorized', everything_but_foo_and_system)
|
||||
|
||||
@@ -32,16 +32,7 @@ class FloatingIPPoolsPolicyTest(base.BasePolicyTest):
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
|
||||
# Check that everyone is able to list FIP pools.
|
||||
self.everyone_authorized_contexts = set([
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.project_admin_context, self.project_manager_context,
|
||||
self.project_member_context, self.project_reader_context,
|
||||
self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context,
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context])
|
||||
self.everyone_authorized_contexts = self.all_contexts
|
||||
self.everyone_unauthorized_contexts = set([])
|
||||
|
||||
@mock.patch('nova.network.neutron.API.get_floating_ip_pools')
|
||||
@@ -68,7 +59,8 @@ class FloatingIPPoolsScopeTypePolicyTest(FloatingIPPoolsPolicyTest):
|
||||
super(FloatingIPPoolsScopeTypePolicyTest, self).setUp()
|
||||
self.flags(enforce_scope=True, group="oslo_policy")
|
||||
|
||||
self.reduce_set('everyone_authorized', self.all_project_contexts)
|
||||
self.reduce_set('everyone_authorized', self.all_project_contexts |
|
||||
set([self.service_context]))
|
||||
self.everyone_unauthorized_contexts = (
|
||||
self.all_contexts - self.everyone_authorized_contexts)
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ class FloatingIPPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
@@ -75,7 +76,8 @@ class FloatingIPPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
# With legacy rule and no scope checks, all admin, project members
|
||||
# project reader or other project role(because legacy rule allow server
|
||||
@@ -218,7 +220,8 @@ class FloatingIPScopeTypePolicyTest(FloatingIPPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
@@ -226,7 +229,8 @@ class FloatingIPScopeTypePolicyTest(FloatingIPPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -53,17 +53,7 @@ class KeypairsPolicyTest(base.BasePolicyTest):
|
||||
|
||||
# Check that everyone is able to create, delete and get
|
||||
# their keypairs.
|
||||
self.everyone_authorized_contexts = set([
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.project_admin_context,
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context, self.project_manager_context,
|
||||
self.project_member_context, self.project_reader_context,
|
||||
self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context,
|
||||
self.other_project_reader_context,
|
||||
])
|
||||
self.everyone_authorized_contexts = self.all_contexts
|
||||
|
||||
# Check that admin is able to create, delete and get
|
||||
# other users keypairs.
|
||||
@@ -177,7 +167,8 @@ class KeypairsScopeTypePolicyTest(KeypairsPolicyTest):
|
||||
self.flags(enforce_scope=True, group="oslo_policy")
|
||||
|
||||
# With scope checking, only project-scoped users are allowed
|
||||
self.reduce_set('everyone_authorized', self.all_project_contexts)
|
||||
self.reduce_set('everyone_authorized', self.all_project_contexts |
|
||||
set([self.service_context]))
|
||||
self.admin_authorized_contexts = [
|
||||
self.legacy_admin_context,
|
||||
self.project_admin_context]
|
||||
|
||||
@@ -131,7 +131,8 @@ class LimitsScopeTypePolicyTest(LimitsPolicyTest):
|
||||
self.project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context,
|
||||
self.project_foo_context, self.other_project_reader_context
|
||||
self.project_foo_context, self.other_project_reader_context,
|
||||
self.service_context,
|
||||
]
|
||||
|
||||
|
||||
@@ -157,5 +158,6 @@ class LimitsScopeTypeNoLegacyPolicyTest(LimitsScopeTypePolicyTest):
|
||||
self.project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context,
|
||||
self.project_foo_context, self.other_project_reader_context
|
||||
self.project_foo_context, self.other_project_reader_context,
|
||||
self.service_context,
|
||||
]
|
||||
|
||||
@@ -48,7 +48,8 @@ class NetworksPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
@mock.patch('nova.network.neutron.API.get_all')
|
||||
@@ -116,7 +117,8 @@ class NetworksScopeTypePolicyTest(NetworksPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ class QuotaSetsPolicyTest(base.BasePolicyTest):
|
||||
self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context,
|
||||
self.other_project_reader_context])
|
||||
self.other_project_reader_context,
|
||||
self.service_context])
|
||||
# Everyone is able to get the default quota
|
||||
self.everyone_authorized_contexts = set([
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
@@ -60,7 +61,7 @@ class QuotaSetsPolicyTest(base.BasePolicyTest):
|
||||
self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context,
|
||||
self.other_project_reader_context])
|
||||
self.other_project_reader_context, self.service_context])
|
||||
|
||||
@mock.patch('nova.quota.QUOTAS.get_project_quotas')
|
||||
@mock.patch('nova.quota.QUOTAS.get_settable_quotas')
|
||||
@@ -185,8 +186,10 @@ class QuotaSetsScopeTypePolicyTest(QuotaSetsPolicyTest):
|
||||
self.legacy_admin_context,
|
||||
self.project_admin_context]))
|
||||
self.reduce_set('project_reader_authorized',
|
||||
self.all_project_contexts)
|
||||
self.everyone_authorized_contexts = self.all_project_contexts
|
||||
self.all_project_contexts | set([
|
||||
self.service_context]))
|
||||
self.everyone_authorized_contexts = (self.all_project_contexts | set([
|
||||
self.service_context]))
|
||||
|
||||
|
||||
class QuotaSetsScopeTypeNoLegacyPolicyTest(QuotaSetsScopeTypePolicyTest):
|
||||
|
||||
@@ -152,7 +152,8 @@ class SecurityGroupsPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
@@ -163,7 +164,8 @@ class SecurityGroupsPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
@mock.patch('nova.network.security_group_api.list')
|
||||
@@ -304,7 +306,8 @@ class SecurityGroupsScopeTypePolicyTest(SecurityGroupsPolicyTest):
|
||||
self.project_reader_context,
|
||||
self.project_foo_context, self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
@@ -312,7 +315,8 @@ class SecurityGroupsScopeTypePolicyTest(SecurityGroupsPolicyTest):
|
||||
self.project_reader_context,
|
||||
self.project_foo_context, self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -34,11 +34,11 @@ class ServerExternalEventsPolicyTest(base.BasePolicyTest):
|
||||
self.controller = ev.ServerExternalEventsController()
|
||||
self.req = fakes.HTTPRequest.blank('')
|
||||
|
||||
# With legacy rule and no scope checks, all admin can
|
||||
# create the server external events.
|
||||
# With legacy rule and no scope checks, all admin and service user
|
||||
# can create the server external events.
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.project_admin_context
|
||||
self.project_admin_context, self.service_context
|
||||
]
|
||||
|
||||
@mock.patch('nova.compute.api.API.external_instance_event')
|
||||
@@ -82,7 +82,8 @@ class ServerExternalEventsScopeTypePolicyTest(ServerExternalEventsPolicyTest):
|
||||
|
||||
# With scope checks, system admin is not allowed.
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context]
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
self.service_context]
|
||||
|
||||
|
||||
class ServerExternalEventsScopeTypeNoLegacyPolicyTest(
|
||||
|
||||
@@ -83,7 +83,8 @@ class ServerGroupPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
# With legacy rule, anyone can create SG.
|
||||
@@ -222,19 +223,13 @@ class ServerGroupScopeTypePolicyTest(ServerGroupPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context,
|
||||
self.other_project_manager_context]
|
||||
self.other_project_manager_context,
|
||||
self.service_context]
|
||||
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context]
|
||||
|
||||
self.everyone_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
self.project_manager_context, self.project_member_context,
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_member_context
|
||||
]
|
||||
self.everyone_authorized_contexts = (
|
||||
self.project_create_authorized_contexts)
|
||||
|
||||
|
||||
class ServerGroupScopeTypeNoLegacyPolicyTest(ServerGroupScopeTypePolicyTest):
|
||||
|
||||
@@ -1367,7 +1367,8 @@ class ServersNoLegacyNoScopeTest(ServersPolicyTest):
|
||||
# see everything in their project.
|
||||
self.reduce_set('everyone_authorized',
|
||||
self.all_contexts - set([self.project_foo_context,
|
||||
self.system_foo_context]))
|
||||
self.system_foo_context,
|
||||
self.service_context]))
|
||||
|
||||
# Disabling legacy support means readers and random roles lose
|
||||
# power to create things on their own projects. Note that
|
||||
@@ -1381,7 +1382,8 @@ class ServersNoLegacyNoScopeTest(ServersPolicyTest):
|
||||
self.system_foo_context,
|
||||
self.project_reader_context,
|
||||
self.project_foo_context,
|
||||
self.other_project_reader_context]))
|
||||
self.other_project_reader_context,
|
||||
self.service_context]))
|
||||
|
||||
|
||||
class ServersScopeTypePolicyTest(ServersPolicyTest):
|
||||
@@ -1428,7 +1430,8 @@ class ServersScopeTypePolicyTest(ServersPolicyTest):
|
||||
|
||||
# With scope checking enabled, system users no longer have
|
||||
# project access, even to create their own resources.
|
||||
self.reduce_set('project_member_authorized', self.all_project_contexts)
|
||||
self.reduce_set('project_member_authorized',
|
||||
self.all_project_contexts | set([self.service_context]))
|
||||
|
||||
# With scope checking enabled, system admin is no longer an
|
||||
# admin of project resources.
|
||||
|
||||
@@ -61,7 +61,8 @@ class SnapshotsPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
@@ -72,7 +73,8 @@ class SnapshotsPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
@mock.patch('nova.volume.cinder.API.get_all_snapshots')
|
||||
@@ -191,7 +193,8 @@ class SnapshotsScopeTypePolicyTest(SnapshotsPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
@@ -200,7 +203,8 @@ class SnapshotsScopeTypePolicyTest(SnapshotsPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,8 @@ class TenantNetworksPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
@mock.patch('nova.network.neutron.API.get_all')
|
||||
@@ -113,7 +114,7 @@ class TenantNetworksScopeTypePolicyTest(TenantNetworksPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context, self.service_context
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -119,11 +119,11 @@ class VolumeAttachPolicyTest(base.BasePolicyTest):
|
||||
self.project_member_authorized_contexts)
|
||||
|
||||
# By default, legacy rule are enable and scope check is disabled.
|
||||
# system admin, legacy admin, and project admin is able to update
|
||||
# volume attachment with a different volumeId.
|
||||
# system admin, legacy admin, project admin, and service user is able
|
||||
# to update volume attachment with a different volumeId.
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
self.project_admin_context]
|
||||
self.project_admin_context, self.service_context]
|
||||
|
||||
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid')
|
||||
def test_index_volume_attach_policy(self, mock_get_instance):
|
||||
@@ -256,7 +256,8 @@ class VolumeAttachScopeTypePolicyTest(VolumeAttachPolicyTest):
|
||||
self.project_m_r_or_admin_with_scope_and_legacy)
|
||||
|
||||
self.project_admin_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context]
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
self.service_context]
|
||||
|
||||
|
||||
class VolumeAttachScopeTypeNoLegacyPolicyTest(VolumeAttachScopeTypePolicyTest):
|
||||
|
||||
@@ -51,7 +51,8 @@ class VolumesPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.system_admin_context,
|
||||
@@ -62,7 +63,8 @@ class VolumesPolicyTest(base.BasePolicyTest):
|
||||
self.system_member_context, self.system_reader_context,
|
||||
self.system_foo_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context,
|
||||
self.service_context
|
||||
]
|
||||
|
||||
@mock.patch('nova.volume.cinder.API.get_all')
|
||||
@@ -204,7 +206,7 @@ class VolumesScopeTypePolicyTest(VolumesPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context, self.service_context
|
||||
]
|
||||
self.project_reader_authorized_contexts = [
|
||||
self.legacy_admin_context, self.project_admin_context,
|
||||
@@ -213,7 +215,7 @@ class VolumesScopeTypePolicyTest(VolumesPolicyTest):
|
||||
self.project_reader_context, self.project_foo_context,
|
||||
self.other_project_reader_context,
|
||||
self.other_project_manager_context,
|
||||
self.other_project_member_context
|
||||
self.other_project_member_context, self.service_context
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -308,6 +308,11 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
||||
self.admin_context = context.RequestContext(
|
||||
'fake', 'fake', True, roles=[
|
||||
'admin', 'manager', 'member', 'reader'])
|
||||
self.service_context = context.RequestContext(
|
||||
user_id="service_user",
|
||||
project_id="service_user_project_id",
|
||||
roles=['service'])
|
||||
|
||||
self.target = {}
|
||||
self.fake_policy = jsonutils.loads(fake_policy.policy_data)
|
||||
|
||||
@@ -359,12 +364,8 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
||||
"os_compute_api:os-shelve:shelve_offload",
|
||||
"os_compute_api:os-shelve:unshelve_to_host",
|
||||
"os_compute_api:os-availability-zone:detail",
|
||||
"os_compute_api:os-assisted-volume-snapshots:create",
|
||||
"os_compute_api:os-assisted-volume-snapshots:delete",
|
||||
"os_compute_api:os-console-auth-tokens",
|
||||
"os_compute_api:os-quota-class-sets:update",
|
||||
"os_compute_api:os-server-external-events:create",
|
||||
"os_compute_api:os-volumes-attachments:swap",
|
||||
"os_compute_api:servers:create:zero_disk_flavor",
|
||||
"os_compute_api:os-baremetal-nodes:list",
|
||||
"os_compute_api:os-baremetal-nodes:show",
|
||||
@@ -525,6 +526,13 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
||||
servers_policy.CROSS_CELL_RESIZE,
|
||||
)
|
||||
|
||||
self.service_rules = (
|
||||
"os_compute_api:os-assisted-volume-snapshots:create",
|
||||
"os_compute_api:os-assisted-volume-snapshots:delete",
|
||||
"os_compute_api:os-server-external-events:create",
|
||||
"os_compute_api:os-volumes-attachments:swap",
|
||||
)
|
||||
|
||||
def test_all_rules_in_sample_file(self):
|
||||
special_rules = ["context_is_admin", "admin_or_owner", "default"]
|
||||
for (name, rule) in self.fake_policy.items():
|
||||
@@ -556,6 +564,18 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
||||
self.assertRaises(exception.PolicyNotAuthorized, policy.authorize,
|
||||
self.admin_context, rule, self.target)
|
||||
|
||||
def test_service_only_rules(self):
|
||||
for rule in self.service_rules:
|
||||
self.assertRaises(exception.PolicyNotAuthorized, policy.authorize,
|
||||
self.non_admin_context, rule,
|
||||
{'project_id': 'fake', 'user_id': 'fake'})
|
||||
# TODO(gmaan): For backward compatibility, we are allowing admin
|
||||
# user to access service only rules, but once we remove that
|
||||
# access, we need to assert here that the admin cannot access the
|
||||
# service only rules.
|
||||
policy.authorize(self.admin_context, rule)
|
||||
policy.authorize(self.service_context, rule)
|
||||
|
||||
def test_rule_missing(self):
|
||||
rules = policy.get_rules()
|
||||
# eliqiao os_compute_api:os-quota-class-sets:show requires
|
||||
@@ -567,9 +587,11 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
||||
'project_member_api', 'project_reader_api',
|
||||
'project_manager_or_admin',
|
||||
'project_member_or_admin',
|
||||
'project_reader_or_admin')
|
||||
'project_reader_or_admin', 'service_api',
|
||||
'service_or_admin')
|
||||
result = set(rules.keys()) - set(self.admin_only_rules +
|
||||
self.admin_or_owner_rules +
|
||||
self.allow_all_rules +
|
||||
self.allow_nobody_rules + special_rules)
|
||||
self.allow_nobody_rules + special_rules +
|
||||
self.service_rules)
|
||||
self.assertEqual(set([]), result)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
A few of the Nova APIs are meant only for use by other Openstack services.
|
||||
Those APIs are not supposed to be used by any non-service users (even
|
||||
admins) because they can make deployment or resources in unwanted state.
|
||||
To restrict the usage of those APIs by users, Nova now defaults those APIs
|
||||
to a policy rule of the ``service`` role. This will make sure they are
|
||||
allowed to be used by the OpenStack services only.
|
||||
upgrade:
|
||||
- |
|
||||
Nova changed the default access for the service-to-service APIs which are
|
||||
meant to be used by the OpenStack services only and not by any users.
|
||||
The below service-to-service APIs access default to the ``service`` role:
|
||||
|
||||
* os_compute_api:os-assisted-volume-snapshots:create
|
||||
* os_compute_api:os-assisted-volume-snapshots:delete
|
||||
* os_compute_api:os-server-external-events:create
|
||||
* os_compute_api:os-volumes-attachments:swap
|
||||
|
||||
Make sure the configured nova service user in other services has the
|
||||
``service`` role otherwise communication from the other services to
|
||||
Nova will fail. For example, user configured as ``username`` option in
|
||||
``neutron.conf`` file under ``[nova]`` section has the ``service``
|
||||
role.
|
||||
|
||||
If you are allowing these APIs to be accessed by admin or non-admin users
|
||||
then it is highly recommended to remove that permission and make sure
|
||||
those APIs are not accessible by any non-service users.
|
||||
|
||||
For backward compatibility, Nova continue allow ``admin`` role token to
|
||||
access service APIs but in future release, ``admin`` access will be
|
||||
removed.
|
||||
deprecations:
|
||||
- |
|
||||
The below service-to-service APIs policy rule default value
|
||||
``role:admin or role:service`` is deprecated and will be changed to
|
||||
``role:service`` in future release:
|
||||
|
||||
* os_compute_api:os-assisted-volume-snapshots:create
|
||||
* os_compute_api:os-assisted-volume-snapshots:delete
|
||||
* os_compute_api:os-server-external-events:create
|
||||
* os_compute_api:os-volumes-attachments:swap
|
||||
Reference in New Issue
Block a user