summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLance Bragstad <lbragstad@gmail.com>2020-12-01 20:03:33 +0000
committerramishra <ramishra@redhat.com>2021-03-02 09:32:41 +0530
commit93594c30eca3a52366e8138a583a00dbe5927d7d (patch)
treedc156219e5b954329d64c5a156bd1e8abde9e5fd
parent8daa7e938985e0fc34f603debf3a8ba1413d8ff7 (diff)
downloadheat-93594c30eca3a52366e8138a583a00dbe5927d7d.tar.gz
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
-rw-r--r--heat/api/openstack/v1/util.py7
-rw-r--r--heat/policies/actions.py132
-rw-r--r--heat/policies/base.py36
-rw-r--r--heat/policies/build_info.py19
-rw-r--r--heat/policies/cloudformation.py149
-rw-r--r--heat/policies/events.py31
-rw-r--r--heat/policies/resource.py66
-rw-r--r--heat/policies/service.py16
-rw-r--r--heat/policies/software_configs.py66
-rw-r--r--heat/policies/software_deployments.py70
-rw-r--r--heat/policies/stacks.py367
-rw-r--r--heat/tests/api/openstack_v1/test_stacks.py8
-rw-r--r--heat/tests/api/openstack_v1/tools.py1
-rw-r--r--heat/tests/policy/check_admin.json3
-rw-r--r--heat/tests/policy/deny_stack_user.json15
-rw-r--r--heat/tests/policy/notallowed.json14
-rw-r--r--heat/tests/policy/resources.json4
-rw-r--r--heat/tests/policy/test_acl_personas.yaml241
-rw-r--r--heat/tests/policy/test_deprecated_access.yaml22
-rw-r--r--heat/tests/test_common_policy.py125
-rw-r--r--heat/tests/utils.py26
-rw-r--r--lower-constraints.txt3
-rw-r--r--releasenotes/notes/support-rbac-824a2d02c8746d3d.yaml15
-rw-r--r--requirements.txt3
24 files changed, 1220 insertions, 219 deletions
diff --git a/heat/api/openstack/v1/util.py b/heat/api/openstack/v1/util.py
index 86df81eb6..70a22d420 100644
--- a/heat/api/openstack/v1/util.py
+++ b/heat/api/openstack/v1/util.py
@@ -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()
diff --git a/heat/policies/actions.py b/heat/policies/actions.py
index 78865786e..ef40337f1 100644
--- a/heat/policies/actions.py
+++ b/heat/policies/actions.py
@@ -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
+ ),
+ 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
),
- _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 % '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
+ )
]
diff --git a/heat/policies/base.py b/heat/policies/base.py
index 7f4d8643d..cdc3b9f7d 100644
--- a/heat/policies/base.py
+++ b/heat/policies/base.py
@@ -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(
diff --git a/heat/policies/build_info.py b/heat/policies/build_info.py
index 066bf7bdb..ebcda36fc 100644
--- a/heat/policies/build_info.py
+++ b/heat/policies/build_info.py
@@ -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
)
]
diff --git a/heat/policies/cloudformation.py b/heat/policies/cloudformation.py
index aa61fa9a0..4983ee179 100644
--- a/heat/policies/cloudformation.py
+++ b/heat/policies/cloudformation.py
@@ -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
+ )
]
diff --git a/heat/policies/events.py b/heat/policies/events.py
index b6c1f21fa..886d22a58 100644
--- a/heat/policies/events.py
+++ b/heat/policies/events.py
@@ -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
)
]
diff --git a/heat/policies/resource.py b/heat/policies/resource.py
index 8be1c2a40..3d0fdcc7e 100644
--- a/heat/policies/resource.py
+++ b/heat/policies/resource.py
@@ -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
)
]
diff --git a/heat/policies/service.py b/heat/policies/service.py
index 9bf86a696..8e4e5d979 100644
--- a/heat/policies/service.py
+++ b/heat/policies/service.py
@@ -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
+ )
]
diff --git a/heat/policies/software_configs.py b/heat/policies/software_configs.py
index 72f6f2c99..5de6535fb 100644
--- a/heat/policies/software_configs.py
+++ b/heat/policies/software_configs.py
@@ -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
)
]
diff --git a/heat/policies/software_deployments.py b/heat/policies/software_deployments.py
index 05f73d586..a2dd0924a 100644
--- a/heat/policies/software_deployments.py
+++ b/heat/policies/software_deployments.py
@@ -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=[
{
diff --git a/heat/policies/stacks.py b/heat/policies/stacks.py
index 7332a69a3..04f6988c5 100644
--- a/heat/policies/stacks.py
+++ b/heat/policies/stacks.py
@@ -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
)
]
diff --git a/heat/tests/api/openstack_v1/test_stacks.py b/heat/tests/api/openstack_v1/test_stacks.py
index 67cd34a1b..48d1ebd61 100644
--- a/heat/tests/api/openstack_v1/test_stacks.py
+++ b/heat/tests/api/openstack_v1/test_stacks.py
@@ -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)
diff --git a/heat/tests/api/openstack_v1/tools.py b/heat/tests/api/openstack_v1/tools.py
index 63a8b0521..0f5247a58 100644
--- a/heat/tests/api/openstack_v1/tools.py
+++ b/heat/tests/api/openstack_v1/tools.py
@@ -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,
diff --git a/heat/tests/policy/check_admin.json b/heat/tests/policy/check_admin.json
deleted file mode 100644
index 96a15c83c..000000000
--- a/heat/tests/policy/check_admin.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "context_is_admin": "role:admin"
-}
diff --git a/heat/tests/policy/deny_stack_user.json b/heat/tests/policy/deny_stack_user.json
deleted file mode 100644
index c20d2673f..000000000
--- a/heat/tests/policy/deny_stack_user.json
+++ /dev/null
@@ -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",
-}
diff --git a/heat/tests/policy/notallowed.json b/heat/tests/policy/notallowed.json
deleted file mode 100644
index 5346307e3..000000000
--- a/heat/tests/policy/notallowed.json
+++ /dev/null
@@ -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": "!"
-}
diff --git a/heat/tests/policy/resources.json b/heat/tests/policy/resources.json
index 163fdb66e..dc56a4778 100644
--- a/heat/tests/policy/resources.json
+++ b/heat/tests/policy/resources.json
@@ -1,7 +1,3 @@
{
- "context_is_admin": "role:admin",
-
"resource_types:OS::Cinder::Quota": "!",
- "resource_types:OS::Keystone::*": "rule:context_is_admin"
-
}
diff --git a/heat/tests/policy/test_acl_personas.yaml b/heat/tests/policy/test_acl_personas.yaml
new file mode 100644
index 000000000..1fe5ce40a
--- /dev/null
+++ b/heat/tests/policy/test_acl_personas.yaml
@@ -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"
diff --git a/heat/tests/policy/test_deprecated_access.yaml b/heat/tests/policy/test_deprecated_access.yaml
new file mode 100644
index 000000000..26af91c8b
--- /dev/null
+++ b/heat/tests/policy/test_deprecated_access.yaml
@@ -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"
diff --git a/heat/tests/test_common_policy.py b/heat/tests/test_common_policy.py
index ee311a809..eb2753c4a 100644
--- a/heat/tests/test_common_policy.py
+++ b/heat/tests/test_common_policy.py
@@ -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')
-
- 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_policy_cfn_notallowed(self):
- enforcer = policy.Enforcer(
- scope='cloudformation',
- policy_file=self.get_policy_file('notallowed.json'))
-
- 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)
-
- def test_policy_cfn_deny_stack_user(self):
- enforcer = policy.Enforcer(scope='cloudformation')
-
- 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_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 _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
+
+ 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)
+
+ @ddt.file_data('policy/test_acl_personas.yaml')
+ @ddt.unpack
+ def test_legacy_rbac_policies(self, **kwargs):
+ self._test_legacy_rbac_policies(**kwargs)
+
+ @ddt.file_data('policy/test_deprecated_access.yaml')
+ @ddt.unpack
+ def test_deprecated_policies(self, **kwargs):
+ self._test_legacy_rbac_policies(**kwargs)
+
+ @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)
+
+ 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_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()
diff --git a/heat/tests/utils.py b/heat/tests/utils.py
index 854e7caf4..cf3e383f8 100644
--- a/heat/tests/utils.py
+++ b/heat/tests/utils.py
@@ -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):
diff --git a/lower-constraints.txt b/lower-constraints.txt
index 582eccf49..e3b2841bc 100644
--- a/lower-constraints.txt
+++ b/lower-constraints.txt
@@ -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
diff --git a/releasenotes/notes/support-rbac-824a2d02c8746d3d.yaml b/releasenotes/notes/support-rbac-824a2d02c8746d3d.yaml
new file mode 100644
index 000000000..faaa3283c
--- /dev/null
+++ b/releasenotes/notes/support-rbac-824a2d02c8746d3d.yaml
@@ -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.
diff --git a/requirements.txt b/requirements.txt
index e416eb3c4..cd7d4c06d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -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