Merge "Introduce scope_types in servers Policies"

This commit is contained in:
Zuul
2020-04-16 17:10:35 +00:00
committed by Gerrit Code Review
3 changed files with 309 additions and 131 deletions
+146 -120
View File
@@ -25,50 +25,55 @@ CROSS_CELL_RESIZE = 'compute:servers:resize:cross_cell'
rules = [
policy.DocumentedRuleDefault(
SERVERS % 'index',
RULE_AOO,
"List all servers",
[
name=SERVERS % 'index',
check_str=RULE_AOO,
description="List all servers",
operations=[
{
'method': 'GET',
'path': '/servers'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'detail',
RULE_AOO,
"List all servers with detailed information",
[
name=SERVERS % 'detail',
check_str=RULE_AOO,
description="List all servers with detailed information",
operations=[
{
'method': 'GET',
'path': '/servers/detail'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'index:get_all_tenants',
base.RULE_ADMIN_API,
"List all servers for all projects",
[
name=SERVERS % 'index:get_all_tenants',
check_str=base.RULE_ADMIN_API,
description="List all servers for all projects",
operations=[
{
'method': 'GET',
'path': '/servers'
}
]),
],
scope_types=['system']),
policy.DocumentedRuleDefault(
SERVERS % 'detail:get_all_tenants',
base.RULE_ADMIN_API,
"List all servers with detailed information for all projects",
[
name=SERVERS % 'detail:get_all_tenants',
check_str=base.RULE_ADMIN_API,
description="List all servers with detailed information for "
" all projects",
operations=[
{
'method': 'GET',
'path': '/servers/detail'
}
]),
],
scope_types=['system']),
policy.DocumentedRuleDefault(
SERVERS % 'allow_all_filters',
base.RULE_ADMIN_API,
"Allow all filters when listing servers",
[
name=SERVERS % 'allow_all_filters',
check_str=base.RULE_ADMIN_API,
description="Allow all filters when listing servers",
operations=[
{
'method': 'GET',
'path': '/servers'
@@ -77,17 +82,19 @@ rules = [
'method': 'GET',
'path': '/servers/detail'
}
]),
],
scope_types=['system']),
policy.DocumentedRuleDefault(
SERVERS % 'show',
RULE_AOO,
"Show a server",
[
name=SERVERS % 'show',
check_str=RULE_AOO,
description="Show a server",
operations=[
{
'method': 'GET',
'path': '/servers/{server_id}'
}
]),
],
scope_types=['system', 'project']),
# the details in host_status are pretty sensitive, only admins
# should do that by default.
policy.DocumentedRuleDefault(
@@ -148,31 +155,33 @@ allow everyone.
}
]),
policy.DocumentedRuleDefault(
SERVERS % 'create',
RULE_AOO,
"Create a server",
[
name=SERVERS % 'create',
check_str=RULE_AOO,
description="Create a server",
operations=[
{
'method': 'POST',
'path': '/servers'
}
]),
],
scope_types=['project']),
policy.DocumentedRuleDefault(
SERVERS % 'create:forced_host',
base.RULE_ADMIN_API,
"""
name=SERVERS % 'create:forced_host',
check_str=base.RULE_ADMIN_API,
description="""
Create a server on the specified host and/or node.
In this case, the server is forced to launch on the specified
host and/or node by bypassing the scheduler filters unlike the
``compute:servers:create:requested_destination`` rule.
""",
[
operations=[
{
'method': 'POST',
'path': '/servers'
}
]),
],
scope_types=['project']),
policy.DocumentedRuleDefault(
REQUESTED_DESTINATION,
base.RULE_ADMIN_API,
@@ -191,35 +200,39 @@ validated by the scheduler filters unlike the
}
]),
policy.DocumentedRuleDefault(
SERVERS % 'create:attach_volume',
RULE_AOO,
"Create a server with the requested volume attached to it",
[
name=SERVERS % 'create:attach_volume',
check_str=RULE_AOO,
description="Create a server with the requested volume attached to it",
operations=[
{
'method': 'POST',
'path': '/servers'
}
]),
],
scope_types=['project']),
policy.DocumentedRuleDefault(
SERVERS % 'create:attach_network',
RULE_AOO,
"Create a server with the requested network attached to it",
[
name=SERVERS % 'create:attach_network',
check_str=RULE_AOO,
description="Create a server with the requested network attached "
" to it",
operations=[
{
'method': 'POST',
'path': '/servers'
}
]),
],
scope_types=['project']),
policy.DocumentedRuleDefault(
SERVERS % 'create:trusted_certs',
RULE_AOO,
"Create a server with trusted image certificate IDs",
[
name=SERVERS % 'create:trusted_certs',
check_str=RULE_AOO,
description="Create a server with trusted image certificate IDs",
operations=[
{
'method': 'POST',
'path': '/servers'
}
]),
],
scope_types=['project']),
policy.DocumentedRuleDefault(
ZERO_DISK_FLAVOR,
base.RULE_ADMIN_API,
@@ -261,65 +274,71 @@ https://bugs.launchpad.net/nova/+bug/1739646 for details.
}
]),
policy.DocumentedRuleDefault(
SERVERS % 'delete',
RULE_AOO,
"Delete a server",
[
name=SERVERS % 'delete',
check_str=RULE_AOO,
description="Delete a server",
operations=[
{
'method': 'DELETE',
'path': '/servers/{server_id}'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'update',
RULE_AOO,
"Update a server",
[
name=SERVERS % 'update',
check_str=RULE_AOO,
description="Update a server",
operations=[
{
'method': 'PUT',
'path': '/servers/{server_id}'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'confirm_resize',
RULE_AOO,
"Confirm a server resize",
[
name=SERVERS % 'confirm_resize',
check_str=RULE_AOO,
description="Confirm a server resize",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (confirmResize)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'revert_resize',
RULE_AOO,
"Revert a server resize",
[
name=SERVERS % 'revert_resize',
check_str=RULE_AOO,
description="Revert a server resize",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (revertResize)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'reboot',
RULE_AOO,
"Reboot a server",
[
name=SERVERS % 'reboot',
check_str=RULE_AOO,
description="Reboot a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (reboot)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'resize',
RULE_AOO,
"Resize a server",
[
name=SERVERS % 'resize',
check_str=RULE_AOO,
description="Resize a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (resize)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
CROSS_CELL_RESIZE,
base.RULE_NOBODY,
@@ -334,75 +353,82 @@ https://bugs.launchpad.net/nova/+bug/1739646 for details.
}
]),
policy.DocumentedRuleDefault(
SERVERS % 'rebuild',
RULE_AOO,
"Rebuild a server",
[
name=SERVERS % 'rebuild',
check_str=RULE_AOO,
description="Rebuild a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (rebuild)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'rebuild:trusted_certs',
RULE_AOO,
"Rebuild a server with trusted image certificate IDs",
[
name=SERVERS % 'rebuild:trusted_certs',
check_str=RULE_AOO,
description="Rebuild a server with trusted image certificate IDs",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (rebuild)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'create_image',
RULE_AOO,
"Create an image from a server",
[
name=SERVERS % 'create_image',
check_str=RULE_AOO,
description="Create an image from a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (createImage)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'create_image:allow_volume_backed',
RULE_AOO,
"Create an image from a volume backed server",
[
name=SERVERS % 'create_image:allow_volume_backed',
check_str=RULE_AOO,
description="Create an image from a volume backed server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (createImage)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'start',
RULE_AOO,
"Start a server",
[
name=SERVERS % 'start',
check_str=RULE_AOO,
description="Start a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (os-start)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'stop',
RULE_AOO,
"Stop a server",
[
name=SERVERS % 'stop',
check_str=RULE_AOO,
description="Stop a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (os-stop)'
}
]),
],
scope_types=['system', 'project']),
policy.DocumentedRuleDefault(
SERVERS % 'trigger_crash_dump',
RULE_AOO,
"Trigger crash dump in a server",
[
name=SERVERS % 'trigger_crash_dump',
check_str=RULE_AOO,
description="Trigger crash dump in a server",
operations=[
{
'method': 'POST',
'path': '/servers/{server_id}/action (trigger_crash_dump)'
}
]),
],
scope_types=['system', 'project']),
]
+4 -3
View File
@@ -149,9 +149,10 @@ class BasePolicyTest(test.TestCase):
def ensure_raises(req, *args, **kwargs):
exc = self.assertRaises(
exception.PolicyNotAuthorized, func, req, *arg, **kwarg)
self.assertEqual(
"Policy doesn't allow %s to be performed." %
rule_name, exc.format_message())
if rule_name is not None:
self.assertEqual(
"Policy doesn't allow %s to be performed." %
rule_name, exc.format_message())
# Verify all the context having allowed scope and roles pass
# the policy check.
for context in authorized_contexts:
+159 -8
View File
@@ -121,6 +121,17 @@ class ServersPolicyTest(base.BasePolicyTest):
self.project_reader_context, self.project_foo_context,
self.other_project_member_context
]
# Check that project member is able to create serve
self.project_member_authorized_contexts = [
self.legacy_admin_context, self.system_admin_context,
self.project_admin_context, self.project_member_context,
self.system_member_context,
self.other_project_member_context,
self.project_reader_context, self.project_foo_context,
self.system_reader_context, self.system_foo_context]
# Check that non-project member is not able to create server
self.project_member_unauthorized_contexts = [
]
def test_index_server_policy(self):
@@ -241,8 +252,8 @@ class ServersPolicyTest(base.BasePolicyTest):
def test_create_server_policy(self, mock_create):
mock_create.return_value = ([self.instance], '')
rule_name = policies.SERVERS % 'create'
self.common_policy_check(self.everyone_authorized_contexts,
self.everyone_unauthorized_contexts,
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule_name,
self.controller.create,
self.req, body=self.body)
@@ -281,8 +292,8 @@ class ServersPolicyTest(base.BasePolicyTest):
'block_device_mapping': [{'device_name': 'foo'}],
},
}
self.common_policy_check(self.everyone_authorized_contexts,
self.everyone_unauthorized_contexts,
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule_name,
self.controller.create,
self.req, body=body)
@@ -306,8 +317,8 @@ class ServersPolicyTest(base.BasePolicyTest):
}],
},
}
self.common_policy_check(self.everyone_authorized_contexts,
self.everyone_unauthorized_contexts,
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule_name,
self.controller.create,
self.req, body=body)
@@ -334,8 +345,8 @@ class ServersPolicyTest(base.BasePolicyTest):
},
}
self.common_policy_check(self.everyone_authorized_contexts,
self.everyone_unauthorized_contexts,
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule_name,
self.controller.create,
req, body=body)
@@ -698,3 +709,143 @@ class ServersScopeTypePolicyTest(ServersPolicyTest):
def setUp(self):
super(ServersScopeTypePolicyTest, self).setUp()
self.flags(enforce_scope=True, group="oslo_policy")
# Check that system admin is able to list the servers
# for all projects.
self.admin_authorized_contexts = [
self.system_admin_context]
# Check that non-system/admin is not able to list the servers
# for all projects.
self.admin_unauthorized_contexts = [
self.legacy_admin_context, self.project_admin_context,
self.system_member_context, self.system_reader_context,
self.system_foo_context, self.project_member_context,
self.project_reader_context, self.project_foo_context,
self.other_project_member_context
]
# Check if project member can create the server.
self.project_member_authorized_contexts = [
self.legacy_admin_context,
self.project_admin_context, self.project_member_context,
self.other_project_member_context, self.project_reader_context,
self.project_foo_context
]
# Check if non-project member cannot create the server.
self.project_member_unauthorized_contexts = [
self.system_admin_context, self.system_member_context,
self.system_reader_context, self.system_foo_context,
]
# Check if project admin can create the server with host.
self.project_admin_authorized_contexts = [
self.legacy_admin_context, self.project_admin_context
]
# Check if non-project admin cannot create the server with host.
self.project_admin_unauthorized_contexts = [
self.project_member_context, self.other_project_member_context,
self.project_reader_context, self.project_foo_context,
self.system_admin_context, self.system_member_context,
self.system_reader_context, self.system_foo_context,
]
@mock.patch('nova.compute.api.API.create')
@mock.patch('nova.compute.api.API.parse_availability_zone')
def test_create_forced_host_server_policy(self, mock_az, mock_create):
# These policy are project scoped only and 'create' policy is checked
# before 'create:forced_host' so we need to allow 'create' policy
# for everyone. Also skip the error message assertion because for
# system scoped unauth context 'create' policy fail and for project
# scoped unauth context 'create:forced_host' fail.
rule = policies.SERVERS % 'create'
self.policy.set_rules({rule: "@"}, overwrite=False)
mock_create.return_value = ([self.instance], '')
mock_az.return_value = ('test', 'host', None)
# rule_name = policies.SERVERS % 'create:forced_host'
self.common_policy_check(self.project_admin_authorized_contexts,
self.project_admin_unauthorized_contexts,
None,
self.controller.create,
self.req, body=self.body)
@mock.patch('nova.compute.api.API.create')
def test_create_attach_volume_server_policy(self, mock_create):
# These policy are project scoped only and 'create' policy is checked
# before 'create:attach_volume' so even we allow it for everyone
# system scoped context cannot validate theese as they fail
# on 'create' policy itself.
# So sending the 'create' rule for policy error assertion.
rule = policies.SERVERS % 'create'
self.policy.set_rules({rule: "@"}, overwrite=False)
mock_create.return_value = ([self.instance], '')
# rule_name = policies.SERVERS % 'create:attach_volume'
body = {
'server': {
'name': 'server_test',
'imageRef': uuids.fake_id,
'flavorRef': uuids.fake_id,
'block_device_mapping': [{'device_name': 'foo'}],
},
}
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule,
self.controller.create,
self.req, body=body)
@mock.patch('nova.compute.api.API.create')
def test_create_attach_network_server_policy(self, mock_create):
# These policy are project scoped only and 'create' policy is checked
# before 'create:attach_network' so even we allow it for everyone
# system scoped context cannot validate theese as they fail
# on 'create' policy itself.
# So sending the 'create' rule for policy error assertion.
rule = policies.SERVERS % 'create'
self.policy.set_rules({rule: "@"}, overwrite=False)
mock_create.return_value = ([self.instance], '')
# rule_name = policies.SERVERS % 'create:attach_network'
body = {
'server': {
'name': 'server_test',
'imageRef': uuids.fake_id,
'flavorRef': uuids.fake_id,
'networks': [{
'uuid': uuids.fake_id
}],
},
}
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule,
self.controller.create,
self.req, body=body)
@mock.patch('nova.compute.api.API.create')
def test_create_trusted_certs_server_policy(self, mock_create):
# These policy are project scoped only and 'create' policy is checked
# before 'create:trusted_certs' so even we allow it for everyone
# system scoped context cannot validate theese as they fail
# on 'create' policy itself.
# So sending the 'create' rule for policy error assertion.
rule = policies.SERVERS % 'create'
self.policy.set_rules({rule: "@"}, overwrite=False)
req = fakes.HTTPRequest.blank('', version='2.63')
mock_create.return_value = ([self.instance], '')
# rule_name = policies.SERVERS % 'create:trusted_certs'
body = {
'server': {
'name': 'server_test',
'imageRef': uuids.fake_id,
'flavorRef': uuids.fake_id,
'trusted_image_certificates': [uuids.fake_id],
'networks': [{
'uuid': uuids.fake_id
}],
},
}
self.common_policy_check(self.project_member_authorized_contexts,
self.project_member_unauthorized_contexts,
rule,
self.controller.create,
req, body=body)