Implement secure RBAC

This commit updates default policies to account for system scope
and default roles. This is part of a broader change to provide a
consistent and secure authorization experience across OpenStack
projects.

- Introduces basic/reusable check strings in base.py
- Implements secure RBAC for build info API
- Implements secure RBAC for the action API
- Implements secure RBAC for cloud formations
- Implements secure RBAC for events
- Implements secure RBAC for the resource API
- Implements secure RBAC for the service API
- Implements secure RBAC for software configs
- Implements secure RBAC for software deployments
- Implements secure RBAC for stacks
- Adds unit tests for legacy and new secure-rbac policies.

Change-Id: Iff1e39481ea3b1f00bd89dba4a00aed30334ecec
This commit is contained in:
Lance Bragstad 2020-12-01 20:03:33 +00:00 committed by ramishra
parent 8daa7e9389
commit 93594c30ec
24 changed files with 1214 additions and 213 deletions

View File

@ -29,12 +29,17 @@ def registered_policy_enforce(handler):
"""
@functools.wraps(handler)
def handle_stack_method(controller, req, tenant_id, **kwargs):
if req.context.tenant_id != tenant_id and not req.context.is_admin:
_target = {"project_id": tenant_id}
if req.context.tenant_id != tenant_id and not (
req.context.is_admin or
req.context.system_scope == all):
raise exc.HTTPForbidden()
allowed = req.context.policy.enforce(
context=req.context,
action=handler.__name__,
scope=controller.REQUEST_SCOPE,
target=_target,
is_registered_policy=True)
if not allowed:
raise exc.HTTPForbidden()

View File

@ -10,29 +10,51 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
POLICY_ROOT = 'actions:%s'
DEPRECATED_REASON = """
The actions API now supports system scope and default roles.
"""
def _action_rule(action_name, description):
return policy.DocumentedRuleDefault(
name=POLICY_ROOT % action_name,
check_str='rule:%s' % (POLICY_ROOT % 'action'),
description=description,
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}]
)
deprecated_action = policy.DeprecatedRule(
name=POLICY_ROOT % 'action',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_snapshot = policy.DeprecatedRule(
name=POLICY_ROOT % 'snapshot',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_suspend = policy.DeprecatedRule(
name=POLICY_ROOT % 'suspend',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_resume = policy.DeprecatedRule(
name=POLICY_ROOT % 'resume',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_check = policy.DeprecatedRule(
name=POLICY_ROOT % 'check',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_cancel_update = policy.DeprecatedRule(
name=POLICY_ROOT % 'cancel_update',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_cancel_without_rollback = policy.DeprecatedRule(
name=POLICY_ROOT % 'cancel_without_rollback',
check_str=base.RULE_DENY_STACK_USER
)
actions_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'action',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
description='Performs non-lifecycle operations on the stack '
'(Snapshot, Resume, Cancel update, or check stack resources). '
'This is the default for all actions but can be overridden by more '
@ -41,14 +63,88 @@ actions_policies = [
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_action,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
_action_rule('snapshot', 'Create stack snapshot.'),
_action_rule('suspend', 'Suspend a stack.'),
_action_rule('resume', 'Resume a suspended stack.'),
_action_rule('check', 'Check stack resources.'),
_action_rule('cancel_update', 'Cancel stack operation and roll back.'),
_action_rule('cancel_without_rollback',
'Cancel stack operation without rolling back.'),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'snapshot',
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Create stack snapshot',
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_snapshot,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'suspend',
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Suspend a stack.',
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_suspend,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'resume',
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Resume a suspended stack.',
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_resume,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'check',
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Check stack resources.',
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_check,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'cancel_update',
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Cancel stack operation and roll back.',
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_cancel_update,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'cancel_without_rollback',
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Cancel stack operation without rolling back.',
operations=[{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions',
'method': 'POST',
}],
deprecated_rule=deprecated_cancel_without_rollback,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -18,11 +18,45 @@ RULE_DENY_STACK_USER = 'rule:deny_stack_user'
RULE_DENY_EVERYBODY = 'rule:deny_everybody'
RULE_ALLOW_EVERYBODY = 'rule:allow_everybody'
# Check strings that embody common personas
SYSTEM_ADMIN = 'role:admin and system_scope:all'
SYSTEM_READER = 'role:reader and system_scope:all'
PROJECT_MEMBER = 'role:member and project_id:%(project_id)s'
PROJECT_READER = 'role:reader and project_id:%(project_id)s'
# Heat personas
PROJECT_ADMIN = 'role:admin and project_id:%(project_id)s'
PROJECT_STACK_USER = 'role:heat_stack_user and project_id:%(project_id)s'
# Composite check strings that are useful for policies that protect APIs that
# operate at different scopes.
SYSTEM_ADMIN_OR_PROJECT_MEMBER = (
'(' + SYSTEM_ADMIN + ')'
' or (' + PROJECT_MEMBER + ')'
)
SYSTEM_OR_PROJECT_READER = (
'(' + SYSTEM_READER + ')'
' or (' + PROJECT_READER + ')'
)
SYSTEM_ADMIN_OR_PROJECT_MEMBER_OR_STACK_USER = (
'(' + SYSTEM_ADMIN + ')'
' or (' + PROJECT_MEMBER + ')'
' or (' + PROJECT_STACK_USER + ')'
)
SYSTEM_OR_PROJECT_READER_OR_STACK_USER = (
'(' + SYSTEM_READER + ')'
' or (' + PROJECT_READER + ')'
' or (' + PROJECT_STACK_USER + ')'
)
rules = [
policy.RuleDefault(
name="context_is_admin",
check_str="role:admin and is_admin_project:True",
check_str=(
"(role:admin and is_admin_project:True) OR "
"(" + SYSTEM_ADMIN + ")"
),
description="Decides what is required for the 'is_admin:True' check "
"to succeed."),
policy.RuleDefault(

View File

@ -10,23 +10,38 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
DEPRECATED_REASON = """
The build API now supports system scope and default roles.
"""
POLICY_ROOT = 'build_info:%s'
deprecated_build_info = policy.DeprecatedRule(
name=POLICY_ROOT % 'build_info',
check_str=base.RULE_DENY_STACK_USER
)
build_info_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'build_info',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show build information.',
operations=[
{
'path': '/v1/{tenant_id}/build_info',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_build_info,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
@ -17,48 +18,170 @@ from heat.policies import base
# These policies are for AWS CloudFormation-like APIs, so we won't list out
# the URI paths in rules.
DEPRECATED_REASON = """
The cloud formation API now supports system scope and default roles.
"""
POLICY_ROOT = 'cloudformation:%s'
deprecated_list_stacks = policy.DeprecatedRule(
name=POLICY_ROOT % 'ListStacks',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_create_stack = policy.DeprecatedRule(
name=POLICY_ROOT % 'CreateStack',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_describe_stacks = policy.DeprecatedRule(
name=POLICY_ROOT % 'DescribeStacks',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_delete_stack = policy.DeprecatedRule(
name=POLICY_ROOT % 'DeleteStack',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_update_stack = policy.DeprecatedRule(
name=POLICY_ROOT % 'UpdateStack',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_cancel_update_stack = policy.DeprecatedRule(
name=POLICY_ROOT % 'CancelUpdateStack',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_describe_stack_events = policy.DeprecatedRule(
name=POLICY_ROOT % 'DescribeStackEvents',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_validate_template = policy.DeprecatedRule(
name=POLICY_ROOT % 'ValidateTemplate',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_get_template = policy.DeprecatedRule(
name=POLICY_ROOT % 'GetTemplate',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_estimate_template_cost = policy.DeprecatedRule(
name=POLICY_ROOT % 'EstimateTemplateCost',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_describe_stack_resource = policy.DeprecatedRule(
name=POLICY_ROOT % 'DescribeStackResource',
check_str=base.RULE_ALLOW_EVERYBODY
)
deprecated_describe_stack_resources = policy.DeprecatedRule(
name=POLICY_ROOT % 'DescribeStackResources',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_list_stack_resources = policy.DeprecatedRule(
name=POLICY_ROOT % 'ListStackResources',
check_str=base.RULE_DENY_STACK_USER
)
cloudformation_policies = [
policy.RuleDefault(
name=POLICY_ROOT % 'ListStacks',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_list_stacks,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'CreateStack',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_create_stack,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'DescribeStacks',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_describe_stacks,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'DeleteStack',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_delete_stack,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'UpdateStack',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_update_stack,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'CancelUpdateStack',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_cancel_update_stack,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'DescribeStackEvents',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_describe_stack_events,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'ValidateTemplate',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_validate_template,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'GetTemplate',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_get_template,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'EstimateTemplateCost',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_estimate_template_cost,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'DescribeStackResource',
check_str=base.RULE_ALLOW_EVERYBODY),
check_str=base.SYSTEM_OR_PROJECT_READER_OR_STACK_USER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_describe_stack_resource,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'DescribeStackResources',
check_str=base.RULE_DENY_STACK_USER),
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_describe_stack_resources,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.RuleDefault(
name=POLICY_ROOT % 'ListStackResources',
check_str=base.RULE_DENY_STACK_USER)
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
deprecated_rule=deprecated_list_stack_resources,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -10,16 +10,32 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
POLICY_ROOT = 'events:%s'
DEPRECATED_REASON = """
The events API now supports system scope and default roles.
"""
deprecated_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show = policy.DeprecatedRule(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER
)
events_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List events.',
operations=[
{
@ -27,11 +43,15 @@ events_policies = [
'events',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show event.',
operations=[
{
@ -39,7 +59,10 @@ events_policies = [
'resources/{resource_name}/events/{event_id}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -10,16 +10,43 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
POLICY_ROOT = 'resource:%s'
DEPRECATED_REASON = """
The resources API now supports system scope and default roles.
"""
deprecated_list_resources = policy.DeprecatedRule(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_mark_unhealthy = policy.DeprecatedRule(
name=POLICY_ROOT % 'mark_unhealthy',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show_resource = policy.DeprecatedRule(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
)
deprecated_metadata = policy.DeprecatedRule(
name=POLICY_ROOT % 'metadata',
check_str=base.RULE_ALLOW_EVERYBODY,
)
deprecated_signal = policy.DeprecatedRule(
name=POLICY_ROOT % 'signal',
check_str=base.RULE_ALLOW_EVERYBODY,
)
resource_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List resources.',
operations=[
{
@ -27,11 +54,15 @@ resource_policies = [
'resources',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_list_resources,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'metadata',
check_str=base.RULE_ALLOW_EVERYBODY,
check_str=base.SYSTEM_OR_PROJECT_READER_OR_STACK_USER,
scope_types=['system', 'project'],
description='Show resource metadata.',
operations=[
{
@ -39,11 +70,15 @@ resource_policies = [
'resources/{resource_name}/metadata',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_metadata,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'signal',
check_str=base.RULE_ALLOW_EVERYBODY,
check_str=base.SYSTEM_OR_PROJECT_READER_OR_STACK_USER,
scope_types=['system', 'project'],
description='Signal resource.',
operations=[
{
@ -51,11 +86,15 @@ resource_policies = [
'resources/{resource_name}/signal',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_signal,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'mark_unhealthy',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Mark resource as unhealthy.',
operations=[
{
@ -63,11 +102,15 @@ resource_policies = [
'resources/{resource_name_or_physical_id}',
'method': 'PATCH'
}
]
],
deprecated_rule=deprecated_mark_unhealthy,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show resource.',
operations=[
{
@ -75,7 +118,10 @@ resource_policies = [
'resources/{resource_name}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show_resource,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -10,16 +10,30 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
DEPRECATED_REASON = """
The service API now supports system scope and default roles.
"""
POLICY_ROOT = 'service:%s'
deprecated_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'index',
check_str=base.RULE_CONTEXT_IS_ADMIN
)
service_policies = [
policy.RuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_CONTEXT_IS_ADMIN)
check_str=base.SYSTEM_READER,
deprecated_rule=deprecated_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -10,67 +10,113 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
DEPRECATED_REASON = """
The software configuration API now support system scope and default roles.
"""
POLICY_ROOT = 'software_configs:%s'
deprecated_global_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'global_index',
check_str=base.RULE_DENY_EVERYBODY
)
deprecated_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_create = policy.DeprecatedRule(
name=POLICY_ROOT % 'create',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show = policy.DeprecatedRule(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_delete = policy.DeprecatedRule(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_DENY_STACK_USER
)
software_configs_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'global_index',
check_str=base.RULE_DENY_EVERYBODY,
check_str=base.SYSTEM_READER,
scope_types=['system', 'project'],
description='List configs globally.',
operations=[
{
'path': '/v1/{tenant_id}/software_configs',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_global_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List configs.',
operations=[
{
'path': '/v1/{tenant_id}/software_configs',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'create',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Create config.',
operations=[
{
'path': '/v1/{tenant_id}/software_configs',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_create,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show config details.',
operations=[
{
'path': '/v1/{tenant_id}/software_configs/{config_id}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Delete config.',
operations=[
{
'path': '/v1/{tenant_id}/software_configs/{config_id}',
'method': 'DELETE'
}
]
],
deprecated_rule=deprecated_delete,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -10,71 +10,119 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
DEPRECATED_REASON = """
The software deployment API now supports system scope and default roles.
"""
POLICY_ROOT = 'software_deployments:%s'
deprecated_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_create = policy.DeprecatedRule(
name=POLICY_ROOT % 'create',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show = policy.DeprecatedRule(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_update = policy.DeprecatedRule(
name=POLICY_ROOT % 'update',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_delete = policy.DeprecatedRule(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_DENY_STACK_USER
)
software_deployments_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List deployments.',
operations=[
{
'path': '/v1/{tenant_id}/software_deployments',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'create',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Create deployment.',
operations=[
{
'path': '/v1/{tenant_id}/software_deployments',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_create,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show deployment details.',
operations=[
{
'path': '/v1/{tenant_id}/software_deployments/{deployment_id}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'update',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Update deployment.',
operations=[
{
'path': '/v1/{tenant_id}/software_deployments/{deployment_id}',
'method': 'PUT'
}
]
],
deprecated_rule=deprecated_update,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Delete deployment.',
operations=[
{
'path': '/v1/{tenant_id}/software_deployments/{deployment_id}',
'method': 'DELETE'
}
]
],
deprecated_rule=deprecated_delete,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'metadata',
check_str=base.RULE_ALLOW_EVERYBODY,
check_str=base.SYSTEM_OR_PROJECT_READER_OR_STACK_USER,
scope_types=['system', 'project'],
description='Show server configuration metadata.',
operations=[
{

View File

@ -10,16 +10,144 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import versionutils
from oslo_policy import policy
from heat.policies import base
DEPRECATED_REASON = """
The stack API now supports system scope and default roles.
"""
POLICY_ROOT = 'stacks:%s'
deprecated_abandon = policy.DeprecatedRule(
name=POLICY_ROOT % 'abandon',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_create = policy.DeprecatedRule(
name=POLICY_ROOT % 'create',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_delete = policy.DeprecatedRule(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_detail = policy.DeprecatedRule(
name=POLICY_ROOT % 'detail',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_export = policy.DeprecatedRule(
name=POLICY_ROOT % 'export',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_generate_template = policy.DeprecatedRule(
name=POLICY_ROOT % 'generate_template',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_global_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'global_index',
check_str=base.RULE_DENY_EVERYBODY
)
deprecated_index = policy.DeprecatedRule(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_list_resource_types = policy.DeprecatedRule(
name=POLICY_ROOT % 'list_resource_types',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_list_template_versions = policy.DeprecatedRule(
name=POLICY_ROOT % 'list_template_versions',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_list_template_functions = policy.DeprecatedRule(
name=POLICY_ROOT % 'list_template_functions',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_preview = policy.DeprecatedRule(
name=POLICY_ROOT % 'preview',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_resource_schema = policy.DeprecatedRule(
name=POLICY_ROOT % 'resource_schema',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show = policy.DeprecatedRule(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_template = policy.DeprecatedRule(
name=POLICY_ROOT % 'template',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_environment = policy.DeprecatedRule(
name=POLICY_ROOT % 'environment',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_files = policy.DeprecatedRule(
name=POLICY_ROOT % 'files',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_update = policy.DeprecatedRule(
name=POLICY_ROOT % 'update',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_update_patch = policy.DeprecatedRule(
name=POLICY_ROOT % 'update_patch',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_preview_update = policy.DeprecatedRule(
name=POLICY_ROOT % 'preview_update',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_preview_update_patch = policy.DeprecatedRule(
name=POLICY_ROOT % 'preview_update_patch',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_validate_template = policy.DeprecatedRule(
name=POLICY_ROOT % 'validate_template',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_snapshot = policy.DeprecatedRule(
name=POLICY_ROOT % 'snapshot',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show_snapshot = policy.DeprecatedRule(
name=POLICY_ROOT % 'show_snapshot',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_delete_snapshot = policy.DeprecatedRule(
name=POLICY_ROOT % 'delete_snapshot',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_list_snapshots = policy.DeprecatedRule(
name=POLICY_ROOT % 'list_snapshots',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_restore_snapshot = policy.DeprecatedRule(
name=POLICY_ROOT % 'restore_snapshot',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_list_outputs = policy.DeprecatedRule(
name=POLICY_ROOT % 'list_outputs',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_show_output = policy.DeprecatedRule(
name=POLICY_ROOT % 'show_output',
check_str=base.RULE_DENY_STACK_USER
)
deprecated_lookup = policy.DeprecatedRule(
name=POLICY_ROOT % 'lookup',
check_str=base.RULE_ALLOW_EVERYBODY
)
stacks_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'abandon',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Abandon stack.',
operations=[
{
@ -27,44 +155,60 @@ stacks_policies = [
'abandon',
'method': 'DELETE'
}
]
],
deprecated_rule=deprecated_abandon,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'create',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Create stack.',
operations=[
{
'path': '/v1/{tenant_id}/stacks',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_create,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Delete stack.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}',
'method': 'DELETE'
}
]
],
deprecated_rule=deprecated_delete,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'detail',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List stacks in detail.',
operations=[
{
'path': '/v1/{tenant_id}/stacks',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_detail,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'export',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Export stack.',
operations=[
{
@ -72,11 +216,15 @@ stacks_policies = [
'export',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_export,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'generate_template',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Generate stack template.',
operations=[
{
@ -84,55 +232,75 @@ stacks_policies = [
'template',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_generate_template,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'global_index',
check_str=base.RULE_DENY_EVERYBODY,
check_str=base.SYSTEM_READER,
scope_types=['system', 'project'],
description='List stacks globally.',
operations=[
{
'path': '/v1/{tenant_id}/stacks',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_global_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List stacks.',
operations=[
{
'path': '/v1/{tenant_id}/stacks',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_index,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'list_resource_types',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List resource types.',
operations=[
{
'path': '/v1/{tenant_id}/resource_types',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_list_resource_types,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'list_template_versions',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List template versions.',
operations=[
{
'path': '/v1/{tenant_id}/template_versions',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_list_template_versions,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'list_template_functions',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List template functions.',
operations=[
{
@ -140,55 +308,75 @@ stacks_policies = [
'{template_version}/functions',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_list_template_functions,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'lookup',
check_str=base.RULE_ALLOW_EVERYBODY,
check_str=base.SYSTEM_OR_PROJECT_READER_OR_STACK_USER,
scope_types=['system', 'project'],
description='Find stack.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_identity}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_lookup,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'preview',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Preview stack.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/preview',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_preview,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'resource_schema',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show resource type schema.',
operations=[
{
'path': '/v1/{tenant_id}/resource_types/{type_name}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_resource_schema,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show stack.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_identity}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'template',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Get stack template.',
operations=[
{
@ -196,11 +384,15 @@ stacks_policies = [
'template',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_template,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'environment',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Get stack environment.',
operations=[
{
@ -208,11 +400,15 @@ stacks_policies = [
'environment',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_environment,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'files',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Get stack files.',
operations=[
{
@ -220,33 +416,45 @@ stacks_policies = [
'files',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_files,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'update',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Update stack.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}',
'method': 'PUT'
}
]
],
deprecated_rule=deprecated_update,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'update_patch',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Update stack (PATCH).',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}',
'method': 'PATCH'
}
]
],
deprecated_rule=deprecated_update_patch,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'preview_update',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Preview update stack.',
operations=[
{
@ -254,11 +462,15 @@ stacks_policies = [
'preview',
'method': 'PUT'
}
]
],
deprecated_rule=deprecated_preview_update,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'preview_update_patch',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Preview update stack (PATCH).',
operations=[
{
@ -266,22 +478,30 @@ stacks_policies = [
'preview',
'method': 'PATCH'
}
]
],
deprecated_rule=deprecated_preview_update_patch,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'validate_template',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Validate template.',
operations=[
{
'path': '/v1/{tenant_id}/validate',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_validate_template,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'snapshot',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Snapshot Stack.',
operations=[
{
@ -289,11 +509,15 @@ stacks_policies = [
'snapshots',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_snapshot,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show_snapshot',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show snapshot.',
operations=[
{
@ -301,11 +525,15 @@ stacks_policies = [
'snapshots/{snapshot_id}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show_snapshot,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete_snapshot',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Delete snapshot.',
operations=[
{
@ -313,11 +541,15 @@ stacks_policies = [
'snapshots/{snapshot_id}',
'method': 'DELETE'
}
]
],
deprecated_rule=deprecated_delete_snapshot,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'list_snapshots',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List snapshots.',
operations=[
{
@ -325,11 +557,15 @@ stacks_policies = [
'snapshots',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_list_snapshots,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'restore_snapshot',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description='Restore snapshot.',
operations=[
{
@ -337,11 +573,15 @@ stacks_policies = [
'snapshots/{snapshot_id}/restore',
'method': 'POST'
}
]
],
deprecated_rule=deprecated_restore_snapshot,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'list_outputs',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='List outputs.',
operations=[
{
@ -349,11 +589,15 @@ stacks_policies = [
'outputs',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_list_outputs,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show_output',
check_str=base.RULE_DENY_STACK_USER,
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description='Show outputs.',
operations=[
{
@ -361,7 +605,10 @@ stacks_policies = [
'outputs/{output_key}',
'method': 'GET'
}
]
],
deprecated_rule=deprecated_show_output,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
]

View File

@ -471,7 +471,9 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase):
mock_enforce.assert_called_with(action='global_index',
scope=self.controller.REQUEST_SCOPE,
is_registered_policy=True,
context=self.context)
context=self.context,
target={"project_id": self.tenant}
)
def test_global_index_uses_admin_context(self, mock_enforce):
rpc_client = self.controller.rpc_client
@ -1675,7 +1677,9 @@ class StackControllerTest(tools.ControllerTest, common.HeatTestCase):
version='1.20'
)
def test_show_invalidtenant(self, mock_enforce):
# the test_show_invalidtenant for stacks is now dealt with srbac
# more generic approach
def test_deprecated_show_invalidtenant(self, mock_enforce):
identity = identifier.HeatIdentifier('wibble', 'wordpress', '6')
req = self._get('/stacks/%(stack_name)s/%(stack_id)s' % identity)

View File

@ -119,6 +119,7 @@ class ControllerTest(object):
action=self.action,
context=self.context,
scope=self.controller.REQUEST_SCOPE,
target={'project_id': self.tenant},
is_registered_policy=mock.ANY
)
self.assertEqual(self.expected_request_count,

View File

@ -1,3 +0,0 @@
{
"context_is_admin": "role:admin"
}

View File

@ -1,15 +0,0 @@
{
"deny_stack_user": "not role:heat_stack_user",
"cloudformation:ListStacks": "rule:deny_stack_user",
"cloudformation:CreateStack": "rule:deny_stack_user",
"cloudformation:DescribeStacks": "rule:deny_stack_user",
"cloudformation:DeleteStack": "rule:deny_stack_user",
"cloudformation:UpdateStack": "rule:deny_stack_user",
"cloudformation:DescribeStackEvents": "rule:deny_stack_user",
"cloudformation:ValidateTemplate": "rule:deny_stack_user",
"cloudformation:GetTemplate": "rule:deny_stack_user",
"cloudformation:EstimateTemplateCost": "rule:deny_stack_user",
"cloudformation:DescribeStackResource": "",
"cloudformation:DescribeStackResources": "rule:deny_stack_user",
"cloudformation:ListStackResources": "rule:deny_stack_user",
}

View File

@ -1,14 +0,0 @@
{
"cloudformation:ListStacks": "!",
"cloudformation:CreateStack": "!",
"cloudformation:DescribeStacks": "!",
"cloudformation:DeleteStack": "!",
"cloudformation:UpdateStack": "!",
"cloudformation:DescribeStackEvents": "!",
"cloudformation:ValidateTemplate": "!",
"cloudformation:GetTemplate": "!",
"cloudformation:EstimateTemplateCost": "!",
"cloudformation:DescribeStackResource": "!",
"cloudformation:DescribeStackResources": "!",
"cloudformation:ListStackResources": "!"
}

View File

@ -1,7 +1,3 @@
{
"context_is_admin": "role:admin",
"resource_types:OS::Cinder::Quota": "!",
"resource_types:OS::Keystone::*": "rule:context_is_admin"
}

View File

@ -0,0 +1,241 @@
actions_most_restricted:
scope: "actions"
actions:
- "snapshot"
- "suspend"
- "resume"
- "cancel_update"
- "cancel_without_rollback"
allowed:
- "system_admin"
- "project_member"
denied:
- "stack_user"
actions_restricted:
scope: "actions"
actions:
- "check"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
cloud_formation_most_restricted:
scope: "cloudformation"
actions:
- "ListStacks"
- "CreateStack"
- "DescribeStacks"
- "DeleteStack"
- "UpdateStack"
- "DescribeStackEvents"
- "ValidateTemplate"
- "GetTemplate"
- "EstimateTemplateCost"
- "DescribeStackResources"
allowed:
- "system_admin"
- "project_member"
denied:
- "stack_user"
cloud_formation_restricted:
scope: "cloudformation"
actions:
- "DescribeStackResource"
allowed:
- "system_admin"
- "project_member"
build_info_acl:
scope: "build_info"
actions:
- "build_info"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
events_acl:
scope: "events"
actions:
- "index"
- "show"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
resource_least_restricted:
scope: "resource"
actions:
- "metadata"
- "signal"
allowed:
- "system_reader"
- "system_reader"
- "stack_user"
resource_restricted:
scope: "resource"
actions:
- "index"
- "show"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
resource_most_restricted:
scope: "resource"
actions:
- "mark_unhealthy"
allowed:
- "system_admin"
- "project_member"
denied:
- "stack_user"
service_acl:
scope: "service"
actions:
- "index"
allowed:
- "system_reader"
software_configs_least_restricted:
scope: "software_configs"
actions:
- "global_index"
allowed:
- "system_reader"
software_configs_most_restricted:
scope: "software_configs"
actions:
- "create"
- "delete"
allowed:
- "system_admin"
- "project_member"
denied:
- "stack_user"
software_configs_restricted:
scope: "software_configs"
actions:
- "index"
- "create"
- "show"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
software_deployments_most_restricted:
scope: "software_deployments"
actions:
- "create"
- "update"
- "delete"
allowed:
- "system_admin"
- "project_member"
denied:
- "stack_user"
software_deployments_restricted:
scope: "software_deployments"
actions:
- "index"
- "show"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
software_deployments_least_restricted:
scope: "software_deployments"
actions:
- "metadata"
allowed:
- "stack_user"
stacks_most_restricted:
scope: "stacks"
actions:
- "abandon"
- "create"
- "delete"
- "export"
- "generate_template"
- "update"
- "update_patch"
- "preview_update"
- "preview_update_patch"
- "validate_template"
- "snapshot"
- "delete_snapshot"
- "restore_snapshot"
allowed:
- "system_admin"
- "project_member"
denied:
- "stack_user"
stacks_restricted:
scope: "stacks"
actions:
- "detail"
- "index"
- "list_resource_types"
- "list_template_versions"
- "list_template_functions"
- "preview"
- "resource_schema"
- "show"
- "template"
- "environment"
- "files"
- "show_snapshot"
- "list_snapshots"
- "list_outputs"
- "show_output"
allowed:
- "system_reader"
- "project_reader"
denied:
- "stack_user"
stacks_restricted_index:
scope: "stacks"
actions:
- "global_index"
allowed:
- "system_admin"
stacks_open:
scope: "stacks"
actions:
- "lookup"
allowed:
- "system_reader"
- "project_reader"
- "stack_user"
create_stacks:
scope: "stacks"
actions:
- "create"
allowed:
- "system_admin"
- "project_admin"
- "project_member"

View File

@ -0,0 +1,22 @@
cloud_formation_restricted:
scope: "cloudformation"
actions:
- "DescribeStackResource"
allowed:
- "stack_user"
- "anyone"
stacks_open:
scope: "stacks"
actions:
- "lookup"
allowed:
- "anyone"
create_stacks:
scope: "stacks"
actions:
- "create"
allowed:
- "system_reader"
- "project_reader"

View File

@ -16,6 +16,8 @@
import os.path
import ddt
from oslo_config import fixture as config_fixture
from oslo_policy import policy as base_policy
@ -27,17 +29,8 @@ from heat.tests import utils
policy_path = os.path.dirname(os.path.realpath(__file__)) + "/policy/"
@ddt.ddt
class TestPolicyEnforcer(common.HeatTestCase):
cfn_actions = ("ListStacks", "CreateStack", "DescribeStacks",
"DeleteStack", "UpdateStack", "DescribeStackEvents",
"ValidateTemplate", "GetTemplate",
"EstimateTemplateCost", "DescribeStackResource",
"DescribeStackResources")
cw_actions = ("DeleteAlarms", "DescribeAlarmHistory", "DescribeAlarms",
"DescribeAlarmsForMetric", "DisableAlarmActions",
"EnableAlarmActions", "GetMetricStatistics", "ListMetrics",
"PutMetricAlarm", "PutMetricData", "SetAlarmState")
def setUp(self):
super(TestPolicyEnforcer, self).setUp(mock_resource_policy=False)
@ -47,44 +40,80 @@ class TestPolicyEnforcer(common.HeatTestCase):
def get_policy_file(self, filename):
return policy_path + filename
def test_policy_cfn_default(self):
enforcer = policy.Enforcer(scope='cloudformation')
def _get_context(self, persona):
if persona == "system_admin":
ctx = utils.dummy_system_admin_context()
elif persona == "system_reader":
ctx = utils.dummy_system_reader_context()
elif persona == "project_admin":
ctx = utils.dummy_context(roles=['admin', 'member', 'reader'])
elif persona == "project_member":
ctx = utils.dummy_context(roles=['member', 'reader'])
elif persona == "project_reader":
ctx = utils.dummy_context(roles=['reader'])
elif persona == "stack_user":
ctx = utils.dummy_context(roles=['heat_stack_user'])
elif persona == "anyone":
ctx = utils.dummy_context(roles=['foobar'])
else:
self.fail("Persona [{}] not found".format(persona))
return ctx
ctx = utils.dummy_context(roles=[])
for action in self.cfn_actions:
# Everything should be allowed
enforcer.enforce(ctx, action, is_registered_policy=True)
def _test_legacy_rbac_policies(self, **kwargs):
scope = kwargs.get("scope")
actions = kwargs.get("actions")
allowed_personas = kwargs.get("allowed", [])
denied_personas = kwargs.get("denied", [])
self._test_policy_allowed(scope, actions, allowed_personas)
self._test_policy_notallowed(scope, actions, denied_personas)
def test_policy_cfn_notallowed(self):
enforcer = policy.Enforcer(
scope='cloudformation',
policy_file=self.get_policy_file('notallowed.json'))
@ddt.file_data('policy/test_acl_personas.yaml')
@ddt.unpack
def test_legacy_rbac_policies(self, **kwargs):
self._test_legacy_rbac_policies(**kwargs)
ctx = utils.dummy_context(roles=[])
for action in self.cfn_actions:
# Everything should raise the default exception.Forbidden
self.assertRaises(exception.Forbidden, enforcer.enforce, ctx,
action, {}, is_registered_policy=True)
@ddt.file_data('policy/test_deprecated_access.yaml')
@ddt.unpack
def test_deprecated_policies(self, **kwargs):
self._test_legacy_rbac_policies(**kwargs)
def test_policy_cfn_deny_stack_user(self):
enforcer = policy.Enforcer(scope='cloudformation')
@ddt.file_data('policy/test_acl_personas.yaml')
@ddt.unpack
def test_secure_rbac_policies(self, **kwargs):
self.fixture.config(group='oslo_policy', enforce_scope=True)
self.fixture.config(group='oslo_policy', enforce_new_defaults=True)
scope = kwargs.get("scope")
actions = kwargs.get("actions")
allowed_personas = kwargs.get("allowed", [])
denied_personas = kwargs.get("denied", [])
self._test_policy_allowed(scope, actions, allowed_personas)
self._test_policy_notallowed(scope, actions, denied_personas)
ctx = utils.dummy_context(roles=['heat_stack_user'])
for action in self.cfn_actions:
# Everything apart from DescribeStackResource should be Forbidden
if action == "DescribeStackResource":
enforcer.enforce(ctx, action, is_registered_policy=True)
else:
self.assertRaises(exception.Forbidden, enforcer.enforce, ctx,
action, {}, is_registered_policy=True)
def _test_policy_allowed(self, scope, actions, personas):
enforcer = policy.Enforcer(scope=scope)
for persona in personas:
ctx = self._get_context(persona)
for action in actions:
# Everything should be allowed
enforcer.enforce(
ctx,
action,
target={"project_id": "test_tenant_id"},
is_registered_policy=True
)
def test_policy_cfn_allow_non_stack_user(self):
enforcer = policy.Enforcer(scope='cloudformation')
ctx = utils.dummy_context(roles=['not_a_stack_user'])
for action in self.cfn_actions:
# Everything should be allowed
enforcer.enforce(ctx, action, is_registered_policy=True)
def _test_policy_notallowed(self, scope, actions, personas):
enforcer = policy.Enforcer(scope=scope)
for persona in personas:
ctx = self._get_context(persona)
for action in actions:
# Everything should raise the default exception.Forbidden
self.assertRaises(
exception.Forbidden,
enforcer.enforce, ctx,
action,
target={"project_id": "test_tenant_id"},
is_registered_policy=True)
def test_set_rules_overwrite_true(self):
enforcer = policy.Enforcer()

View File

@ -90,6 +90,32 @@ def dummy_context(user='test_username', tenant_id='test_tenant_id',
})
def dummy_system_admin_context():
"""Return a heat.common.context.RequestContext for system-admin.
:returns: an instance of heat.common.context.RequestContext
"""
ctx = dummy_context(roles=['admin', 'member', 'reader'])
ctx.system_scope = 'all'
ctx.project_id = None
ctx.tenant_id = None
return ctx
def dummy_system_reader_context():
"""Return a heat.common.context.RequestContext for system-reader.
:returns: an instance of heat.common.context.RequestContext
"""
ctx = dummy_context(roles=['reader'])
ctx.system_scope = 'all'
ctx.project_id = None
ctx.tenant_id = None
return ctx
def parse_stack(t, params=None, files=None, stack_name=None,
stack_id=None, timeout_mins=None,
cache_data=None, tags=None):

View File

@ -16,6 +16,7 @@ contextlib2==0.5.5
coverage==4.0
croniter==0.3.4
cryptography==2.5
ddt==1.4.1
debtcollector==1.19.0
decorator==4.3.0
deprecation==2.0
@ -72,7 +73,7 @@ oslo.i18n==3.20.0
oslo.log==4.3.0
oslo.messaging==5.29.0
oslo.middleware==3.31.0
oslo.policy==3.6.0
oslo.policy==3.6.2
oslo.reports==1.18.0
oslo.serialization==2.25.0
oslo.service==1.24.0

View File

@ -0,0 +1,15 @@
---
features:
- |
The default policies provided by heat api have been updated to add support
for default roles and system scope. This is part of a broader community
effort to support read-only roles and implement secure, consistent default
policies.
Refer to `the Keystone documentation`__ for more information on the reason
for these changes.
__ https://docs.openstack.org/keystone/latest/admin/service-api-protection.html
deprecations:
- |
The old default policy rules have been deprecated for removal in Xena cycle.

View File

@ -4,6 +4,7 @@
pbr>=3.1.1 # Apache-2.0
Babel!=2.4.0,>=2.3.4 # BSD
ddt>=1.4.1 # MIT
croniter>=0.3.4 # MIT License
cryptography>=2.5 # BSD/Apache-2.0
debtcollector>=1.19.0 # Apache-2.0
@ -23,7 +24,7 @@ oslo.i18n>=3.20.0 # Apache-2.0
oslo.log>=4.3.0 # Apache-2.0
oslo.messaging>=5.29.0 # Apache-2.0
oslo.middleware>=3.31.0 # Apache-2.0
oslo.policy>=3.6.0 # Apache-2.0
oslo.policy>=3.6.2 # Apache-2.0
oslo.reports>=1.18.0 # Apache-2.0
oslo.serialization>=2.25.0 # Apache-2.0
oslo.service!=1.28.1,>=1.24.0 # Apache-2.0